-
Notifications
You must be signed in to change notification settings - Fork 115
feat: add solidity-compat test for generating local claimAsset() param data
#2474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
partylikeits1983
merged 5 commits into
agglayer
from
ajl-claim-asset-local-data-solidity
Feb 23, 2026
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
1f96b6b
feat: add solidity-compat test for generating local claimAsset() para…
partylikeits1983 07f74a0
refactor: rename solidity compat test files & claimAsset vector JSON …
partylikeits1983 cca8cdf
refactor: rename testing methods & update test comments
partylikeits1983 01266fa
Update crates/miden-testing/tests/agglayer/bridge_in.rs
partylikeits1983 489f10d
Update crates/miden-testing/tests/agglayer/bridge_in.rs
partylikeits1983 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
86 changes: 86 additions & 0 deletions
86
crates/miden-agglayer/solidity-compat/test-vectors/claim_asset_vectors_local_tx.json
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| { | ||
| "amount": 1000000000000000, | ||
| "deposit_count": 1, | ||
| "description": "L1 bridgeAsset transaction test vectors with valid Merkle proofs", | ||
| "destination_address": "0x00000000AA0000000000bb000000cc000000Dd00", | ||
| "destination_network": 20, | ||
| "global_exit_root": "0xbb7f9cbe48190e8859cbaecc54c8957863c786862bde7cff62df0a8b5adc19bb", | ||
| "global_index": "0x0000000000000000000000000000000000000000000000010000000000000000", | ||
| "leaf_type": 0, | ||
| "leaf_value": "0x8e5f0c4b8526561e30a89f900185ec681cc620fe3cadd8b281fb929063bd27ac", | ||
| "local_exit_root": "0x3e9a88b19d477b03175f9db12ba6b20eb33c0fe7a271667031685f034caf5af6", | ||
| "mainnet_exit_root": "0x3e9a88b19d477b03175f9db12ba6b20eb33c0fe7a271667031685f034caf5af6", | ||
| "metadata": "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a5465737420546f6b656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045445535400000000000000000000000000000000000000000000000000000000", | ||
| "metadata_hash": "0x4d0d9fb7f9ab2f012da088dc1c228173723db7e09147fe4fea2657849d580161", | ||
| "origin_network": 0, | ||
| "origin_token_address": "0x2DC70fb75b88d2eB4715bc06E1595E6D97c34DFF", | ||
| "rollup_exit_root": "0xd18cc25ae65a4e3d95587ffea9411747238567d6e5d3744240554713edefc197", | ||
| "smt_proof_local_exit_root": [ | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5", | ||
| "0xb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30", | ||
| "0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85", | ||
| "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", | ||
| "0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d", | ||
| "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", | ||
| "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", | ||
| "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", | ||
| "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", | ||
| "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", | ||
| "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", | ||
| "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", | ||
| "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", | ||
| "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", | ||
| "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", | ||
| "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", | ||
| "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", | ||
| "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", | ||
| "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", | ||
| "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", | ||
| "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", | ||
| "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", | ||
| "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", | ||
| "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", | ||
| "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", | ||
| "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", | ||
| "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", | ||
| "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", | ||
| "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", | ||
| "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", | ||
| "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" | ||
| ], | ||
| "smt_proof_rollup_exit_root": [ | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
| "0x0000000000000000000000000000000000000000000000000000000000000000" | ||
| ] | ||
| } |
File renamed without changes.
194 changes: 194 additions & 0 deletions
194
crates/miden-agglayer/solidity-compat/test/ClaimAssetTestVectorsLocalTx.t.sol
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,194 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.20; | ||
|
|
||
| import "forge-std/Test.sol"; | ||
| import "@agglayer/v2/lib/DepositContractV2.sol"; | ||
| import "@agglayer/lib/GlobalExitRootLib.sol"; | ||
|
|
||
| /** | ||
| * @title ClaimAssetTestVectorsLocalTx | ||
| * @notice Test contract that generates test vectors for an L1 bridgeAsset transaction. | ||
| * This simulates calling bridgeAsset() on the PolygonZkEVMBridgeV2 contract | ||
| * and captures all relevant data including VALID Merkle proofs. | ||
| * | ||
| * Run with: forge test -vv --match-contract ClaimAssetTestVectorsLocalTx | ||
| * | ||
| * The output can be used to verify Miden's ability to process L1 bridge transactions. | ||
| */ | ||
| contract ClaimAssetTestVectorsLocalTx is Test, DepositContractV2 { | ||
| /** | ||
| * @notice Generates bridge asset test vectors with VALID Merkle proofs. | ||
| * Simulates a user calling bridgeAsset() to bridge tokens from L1 to Miden. | ||
| * | ||
| * Output file: test-vectors/bridge_asset_vectors.json | ||
| */ | ||
| function test_generateClaimAssetVectorsLocalTx() public { | ||
| string memory obj = "root"; | ||
|
|
||
| // ====== BRIDGE TRANSACTION PARAMETERS ====== | ||
|
|
||
| uint8 leafType = 0; | ||
| uint32 originNetwork = 0; | ||
| address originTokenAddress = 0x2DC70fb75b88d2eB4715bc06E1595E6D97c34DFF; | ||
| uint32 destinationNetwork = 20; | ||
| address destinationAddress = 0x00000000AA0000000000bb000000cc000000Dd00; | ||
| uint256 amount = 1000000000000000; | ||
|
|
||
| bytes memory metadata = abi.encode("Test Token", "TEST", uint8(18)); | ||
| bytes32 metadataHash = keccak256(metadata); | ||
|
|
||
| // ====== COMPUTE LEAF VALUE AND ADD TO TREE ====== | ||
|
|
||
| bytes32 leafValue = getLeafValue( | ||
| leafType, originNetwork, originTokenAddress, destinationNetwork, destinationAddress, amount, metadataHash | ||
| ); | ||
|
|
||
| // Add the leaf to the deposit tree to generate valid Merkle proof | ||
| _addLeaf(leafValue); | ||
|
|
||
| // Get the deposit count (leaf index) - depositCount is uint256 in DepositContractBase | ||
| uint256 depositCountValue = uint256(depositCount); | ||
|
|
||
| // Get the local exit root (root of the deposit tree) | ||
| bytes32 localExitRoot = getRoot(); | ||
|
|
||
| // ====== GENERATE MERKLE PROOF ====== | ||
|
|
||
| // Generate canonical zeros for the Merkle proof | ||
| bytes32[32] memory canonicalZeros = _computeCanonicalZeros(); | ||
|
|
||
| // Build the Merkle proof from _branch array and canonical zeros | ||
| // The leaf index is depositCountValue - 1 (0-indexed) | ||
| uint256 leafIndex = depositCountValue - 1; | ||
| bytes32[32] memory smtProofLocal = _generateLocalProof(leafIndex, canonicalZeros); | ||
|
|
||
| // For mainnet deposits, the rollup proof is all zeros | ||
| bytes32[32] memory smtProofRollup; | ||
| for (uint256 i = 0; i < 32; i++) { | ||
| smtProofRollup[i] = bytes32(0); | ||
| } | ||
|
|
||
| // ====== COMPUTE EXIT ROOTS ====== | ||
|
|
||
| // For a simulated L1 bridge transaction: | ||
| // - mainnetExitRoot is the local exit root from the deposit tree | ||
| // - rollupExitRoot is simulated (deterministic for reproducibility) | ||
| bytes32 mainnetExitRoot = localExitRoot; | ||
| bytes32 rollupExitRoot = keccak256(abi.encodePacked("rollup_exit_root_simulated")); | ||
|
|
||
| // Compute global exit root | ||
| bytes32 globalExitRoot = GlobalExitRootLib.calculateGlobalExitRoot(mainnetExitRoot, rollupExitRoot); | ||
|
|
||
| // ====== VERIFY MERKLE PROOF ====== | ||
|
|
||
| // Verify that the generated proof is valid | ||
| require( | ||
| this.verifyMerkleProof(leafValue, smtProofLocal, uint32(leafIndex), mainnetExitRoot), | ||
| "Generated Merkle proof is invalid!" | ||
| ); | ||
|
|
||
| // ====== COMPUTE GLOBAL INDEX ====== | ||
|
|
||
| // Global index for mainnet deposits: (1 << 64) | leafIndex | ||
| // Note: leafIndex is 0-based (depositCount - 1), matching how the bridge contract | ||
| // extracts it via uint32(globalIndex) in _verifyLeaf() | ||
| uint256 globalIndex = (uint256(1) << 64) | uint256(leafIndex); | ||
partylikeits1983 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // ====== SERIALIZE SMT PROOFS ====== | ||
| _serializeProofs(obj, smtProofLocal, smtProofRollup); | ||
|
|
||
| // Scoped block 2: Serialize transaction parameters | ||
| { | ||
| vm.serializeUint(obj, "leaf_type", leafType); | ||
| vm.serializeUint(obj, "origin_network", originNetwork); | ||
| vm.serializeAddress(obj, "origin_token_address", originTokenAddress); | ||
| vm.serializeUint(obj, "destination_network", destinationNetwork); | ||
| vm.serializeAddress(obj, "destination_address", destinationAddress); | ||
| vm.serializeUint(obj, "amount", amount); | ||
| vm.serializeBytes(obj, "metadata", metadata); | ||
| vm.serializeBytes32(obj, "metadata_hash", metadataHash); | ||
| vm.serializeBytes32(obj, "leaf_value", leafValue); | ||
| } | ||
|
|
||
| // Scoped block 3: Serialize state, exit roots, and finalize | ||
| { | ||
| vm.serializeUint(obj, "deposit_count", depositCountValue); | ||
| vm.serializeBytes32(obj, "global_index", bytes32(globalIndex)); | ||
| vm.serializeBytes32(obj, "local_exit_root", localExitRoot); | ||
| vm.serializeBytes32(obj, "mainnet_exit_root", mainnetExitRoot); | ||
| vm.serializeBytes32(obj, "rollup_exit_root", rollupExitRoot); | ||
| vm.serializeBytes32(obj, "global_exit_root", globalExitRoot); | ||
|
|
||
| string memory json = vm.serializeString( | ||
| obj, "description", "L1 bridgeAsset transaction test vectors with valid Merkle proofs" | ||
| ); | ||
|
|
||
| string memory outputPath = "test-vectors/claim_asset_vectors_local_tx.json"; | ||
| vm.writeJson(json, outputPath); | ||
|
|
||
| console.log("Generated claim asset local tx test vectors with valid Merkle proofs"); | ||
| console.log("Output file:", outputPath); | ||
| console.log("Leaf index:", leafIndex); | ||
| console.log("Deposit count:", depositCountValue); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @notice Computes the canonical zero hashes for the Sparse Merkle Tree. | ||
| * @dev Each level i has zero hash: keccak256(zero[i-1], zero[i-1]) | ||
| * @return canonicalZeros Array of 32 zero hashes, one per tree level | ||
| */ | ||
| function _computeCanonicalZeros() internal pure returns (bytes32[32] memory canonicalZeros) { | ||
| bytes32 current = bytes32(0); | ||
| for (uint256 i = 0; i < 32; i++) { | ||
| canonicalZeros[i] = current; | ||
| current = keccak256(abi.encodePacked(current, current)); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @notice Generates the SMT proof for the local exit root. | ||
| * @dev For each level i: | ||
| * - If bit i of leafIndex is 1: use _branch[i] (sibling on left) | ||
| * - If bit i of leafIndex is 0: use canonicalZeros[i] (sibling on right) | ||
| * @param leafIndex The 0-indexed position of the leaf in the tree | ||
| * @param canonicalZeros The precomputed canonical zero hashes | ||
| * @return smtProofLocal The 32-element Merkle proof array | ||
| */ | ||
| function _generateLocalProof(uint256 leafIndex, bytes32[32] memory canonicalZeros) | ||
| internal | ||
| view | ||
| returns (bytes32[32] memory smtProofLocal) | ||
| { | ||
| for (uint256 i = 0; i < 32; i++) { | ||
| // Check if bit i of leafIndex is set | ||
| if ((leafIndex >> i) & 1 == 1) { | ||
| // Bit is 1: sibling is on the left, use _branch[i] | ||
| smtProofLocal[i] = _branch[i]; | ||
| } else { | ||
| // Bit is 0: sibling is on the right (or doesn't exist), use zero hash | ||
| smtProofLocal[i] = canonicalZeros[i]; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @notice Helper function to serialize SMT proofs (avoids stack too deep) | ||
| * @param obj The JSON object key | ||
| * @param smtProofLocal The local exit root proof | ||
| * @param smtProofRollup The rollup exit root proof | ||
| */ | ||
| function _serializeProofs(string memory obj, bytes32[32] memory smtProofLocal, bytes32[32] memory smtProofRollup) | ||
| internal | ||
| { | ||
| bytes32[] memory smtProofLocalDyn = new bytes32[](32); | ||
| bytes32[] memory smtProofRollupDyn = new bytes32[](32); | ||
| for (uint256 i = 0; i < 32; i++) { | ||
| smtProofLocalDyn[i] = smtProofLocal[i]; | ||
| smtProofRollupDyn[i] = smtProofRollup[i]; | ||
| } | ||
|
|
||
| vm.serializeBytes32(obj, "smt_proof_local_exit_root", smtProofLocalDyn); | ||
| vm.serializeBytes32(obj, "smt_proof_rollup_exit_root", smtProofRollupDyn); | ||
| } | ||
| } | ||
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
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.