feat(agglayer): store and use metadata hash for bridge-out leaves#2583
Open
feat(agglayer): store and use metadata hash for bridge-out leaves#2583
Conversation
The metadata_hash field in bridge-out leaves was previously zeroed, which would cause EVM-side claim verification to fail (no preimage for bytes32(0) under keccak256). This stores a pre-computed keccak256(abi.encode(name, symbol, decimals)) in faucet storage and reads it via FPI during bridge-out leaf construction. Changes: - Add MetadataHash::from_token_info and encode_token_metadata helpers with Solidity ABI encoding compatibility (verified against test vectors) - Add metadata_hash_lo/hi storage slots to AggLayerFaucet - Add get_metadata_hash FPI-callable procedure to faucet MASM - Update bridge_out.masm to fetch metadata hash via FPI instead of pushing zeros - Export get_metadata_hash from faucet component - Regenerate Solidity MMR test vectors with real metadata hash - Add TODO in register_faucet for future on-chain verification Closes #2453 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add bounds assertion to encode_token_metadata for string lengths - Make encode_token_metadata pub(crate) since it's only used internally Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2affd1c to
d6d9127
Compare
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This was referenced Mar 11, 2026
mmagician
commented
Mar 12, 2026
crates/miden-agglayer/solidity-compat/test/MMRTestVectors.t.sol
Outdated
Show resolved
Hide resolved
…or ABI encoding Swap `tiny-keccak` for `miden_crypto::hash::keccak::Keccak256` to avoid an extra cargo dependency, and replace the hand-rolled ABI encoding with `alloy-sol-types` `sol!` macro for type-safe `abi.encode(string, string, uint8)`. Tests now read expected values from the test vector JSON instead of hardcoding them. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…hash Use `swapdw dropw dropw` instead of `exec.sys::truncate_stack` to explicitly drop the 8 excess padding elements in `get_metadata_hash`. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ity test Replace verbose TODO in bridge_config.masm with a concise version referencing issue #2586. In the Solidity test, compute METADATA_HASH via `keccak256(abi.encode(...))` instead of hardcoding the constant. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
d7e1b9c to
c57ca64
Compare
Use workspace dependency for serde in dev-dependencies and rename sol!-generated TokenMetadata to SolTokenMetadata to avoid ambiguity. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add padw padw padw padw before the get_metadata_hash FPI call, matching the pattern established in bridge_in.masm (cfb6211). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add padw padw padw padw before the get_metadata_hash FPI call, matching the pattern from bridge_in.masm (cfb6211). - Reorder: load PROC_MAST_ROOT first via procref, then faucet ID on top via mem_load, eliminating movup.5 movup.5. - Use temp global memory (not loc_loadw_be) to load faucet ID after procref, since loc_loadw_be after procref conflicts with FPI state. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Merge agglayer into metadata-hash branch, resolving conflict in lib.rs. The agglayer branch moved AggLayerBridge and AggLayerFaucet to separate modules (bridge.rs, faucet.rs). Added metadata hash support to the new faucet.rs module and updated the faucet_helpers test. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds end-to-end support for Solidity-compatible token metadata hashing in the AggLayer flow by storing a precomputed metadata hash on the faucet and retrieving it via FPI during bridge-out leaf construction, with corresponding updates to test vectors and dependencies.
Changes:
- Add
MetadataHash(keccak256 over Solidityabi.encode(name, symbol, decimals)) and store it in two faucet storage slots. - Update bridge-out MASM to fetch the faucet’s metadata hash via FPI and include it in leaf data / MMR computation.
- Refresh Solidity tests + JSON vectors and update Rust tests/call sites for the new faucet constructor parameter.
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| deny.toml | Allow CC0-1.0 license for newly introduced dependencies. |
| crates/miden-testing/tests/agglayer/faucet_helpers.rs | Update faucet creation in tests to provide MetadataHash. |
| crates/miden-testing/tests/agglayer/bridge_out.rs | Update bridge-out tests to pass MetadataHash into faucet creation. |
| crates/miden-testing/tests/agglayer/bridge_in.rs | Update faucet creation in tests to pass metadata hash from leaf data. |
| crates/miden-agglayer/src/lib.rs | Thread metadata_hash through faucet account creation helpers. |
| crates/miden-agglayer/src/faucet.rs | Add metadata-hash storage slots and persist hash into faucet component storage. |
| crates/miden-agglayer/src/eth_types/metadata_hash.rs | Implement Solidity ABI encoding + keccak hashing, plus compatibility tests. |
| crates/miden-agglayer/solidity-compat/test/MMRTestVectors.t.sol | Generate vectors using a real metadata hash instead of zero. |
| crates/miden-agglayer/solidity-compat/test-vectors/mmr_frontier_vectors.json | Update expected leaves/roots to match new metadata hash behavior. |
| crates/miden-agglayer/Cargo.toml | Add alloy-sol-types, miden-crypto, and dev deps for new tests. |
| crates/miden-agglayer/asm/components/faucet.masm | Re-export get_metadata_hash from the faucet component. |
| crates/miden-agglayer/asm/agglayer/faucet/mod.masm | Add storage constants and implement get_metadata_hash procedure. |
| crates/miden-agglayer/asm/agglayer/bridge/bridge_out.masm | Fetch metadata hash via FPI and write it into leaf data before hashing/MMR update. |
| crates/miden-agglayer/asm/agglayer/bridge/bridge_config.masm | Add TODO note about verification on faucet registration. |
| CHANGELOG.md | Document the new metadata-hash behavior in AggLayer faucet/bridge-out. |
| Cargo.toml | Add workspace dependency definition for alloy-sol-types. |
| Cargo.lock | Lock new transitive dependencies pulled in by alloy-sol-types and related crates. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
mmagician
commented
Mar 15, 2026
mmagician
commented
Mar 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
keccak256(abi.encode(name, symbol, decimals))metadata hash in faucet storage (2 value slots)MetadataHash::from_token_infoandencode_token_metadataRust helpers with Solidity ABI encoding compatibilityContext
When a user calls
claimAsset()onPolygonZkEVMBridgeV2, they pass the rawmetadatabytes as a parameter. The flow is:keccak256(metadata)as themetadataHashfield, and verifies the merkle proof against the exit root. If the hash doesn't match what's in the leaf, the proof fails.tokenInfoHash = keccak256(abi.encodePacked(originNetwork, originTokenAddress))and checkstokenInfoToWrappedToken[tokenInfoHash]to see if a wrapped token already exists._deployWrappedToken(tokenInfoHash, metadata)which:tokenInfoHashas the salt (making the address deterministic across chains)(string name, string symbol, uint8 decimals) = abi.decode(metadata, (string, string, uint8))initialize(name, symbol, decimals)on the proxy to set up the ERC20tokenInfoHash -> wrappedAddressandwrappedAddress -> {originNetwork, originTokenAddress}The key point: the
metadatabytes serve to initialize the wrapped token. The claimer/relayer must provide the correct raw metadata as part of the claim process (they can get the individual elements from the Miden faucet storage), and it its hash must match what is added to the leaf in LET upon bridging out Miden -> EVM.The metadata hash is computed off-chain at faucet creation time and stored in two storage slots. For future onchain verification during token registration see #2586.
Test plan
MetadataHash::from_token_info("Test Token", "TEST", 18)matches Solidity test vector hash0x4d0d9fb7...make lintpasses (clippy, format, typos, toml, machete)Closes #2453
🤖 Generated with Claude Code