feat: add lock / unlock functionality to agg_bridge for native miden assets#2771
feat: add lock / unlock functionality to agg_bridge for native miden assets#2771partylikeits1983 wants to merge 14 commits intoagglayerfrom
agg_bridge for native miden assets#2771Conversation
…and metadata hash
…h for native tokens
agg_bridge for native miden assets
Bumps rand 0.9.2 → 0.9.4 and rand 0.10.0 → 0.10.1 to resolve RUSTSEC-2026-0097 flagged by `cargo deny check` in CI.
650b79d to
d1d9938
Compare
Fumuran
left a comment
There was a problem hiding this comment.
Looks good, thank you!
It is a partial review, for now I only reviewed masm code. Mostly formatting suggestions and code optimizations
| #! 1. KEY [0, 0, fid_s, fid_p] -> [addr0, addr1, addr2, addr3] (origin address part 1) | ||
| #! 2. KEY [1, 0, fid_s, fid_p] -> [addr4, origin_network, scale, 0] (origin address part 2) |
There was a problem hiding this comment.
nit: I'm not sure about fid abbreviation, it could be not immediately clear. I would vote for faucet_id_suffux and faucet_id_prefix
| const REG_TOKEN_HASH_LOC = 0 | ||
| const REG_FID_S_LOC = 4 | ||
| const REG_FID_P_LOC = 5 | ||
| const REG_SCALE_LOC = 6 | ||
| const REG_ORIGIN_NETWORK_LOC = 7 | ||
| const REG_IS_NATIVE_LOC = 8 |
There was a problem hiding this comment.
optional nit: I would use more detailed names, though it is indeed not obvious how to express these pointers clearly but briefly
| # Drop the remaining pad to start fresh | ||
| dropw dropw dropw | ||
| # => [] |
There was a problem hiding this comment.
I'm not sure that this will work, since we are in the note script
There was a problem hiding this comment.
I tried removing them and the integration tests fail with when returning from a call
| # Drop all 16 pad elements and rebuild the stack | ||
| dropw dropw dropw dropw | ||
| # => [] |
| call.bridge_config::store_faucet_metadata_hash | ||
| # => [pad(16)] | ||
|
|
||
| dropw dropw dropw dropw |
There was a problem hiding this comment.
I suppose this works only because we were explicitly padding to the 16 elements before call, but once everything else is updated, we should be able to remove this line
Fumuran
left a comment
There was a problem hiding this comment.
Rust part looks great, thank you! I left just one question inline
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…masm Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@Fumuran I went with your suggestion, and packaged Separately, extracted |
The inter-call dropw sequences were removed, so the input pad(12) now persists across both call boundaries. Update every # => [...] comment to reflect the true sdepth (verified with sdepth debug.stack drop): pad(16) through the setup, pad(32) after call 1, pad(48) after call 2, pad(16) after the final repeat.8 cleanup.
- bridge_config.masm: reword the register_faucet local-offset comment and move an implementation detail out of get_faucet_metadata_hash's docstring into an inline comment. - bridge_in_output.masm: document that unlock_and_send's replay safety comes from the nullifier check in bridge_in::claim, not serial-number uniqueness. - bridge_in.rs: add bridge_in_unlock_native_duplicate_rejected. Seeds the bridge vault with 2x the claim amount so the nullifier is the only thing stopping a second unlock, then asserts the replay fails with ERR_CLAIM_ALREADY_SPENT.
Closes #2700. Adds a lock/unlock path for Miden-native tokens to the AggLayer bridge, mirroring
PolygonZkEVMBridgeV2.claimAsset()'s handling oforiginNetwork == networkID.The bridge no longer needs to be the faucet's owner to support it, so user-created faucets are now bridgeable once the bridge admin registers them via a
CONFIG_AGG_BRIDGEnote withis_native = true. Registration is still admin-gated (register_faucetis caller-restricted); what changed is the ownership requirement.Approach
Native faucet branch, end-to-end:
is_native, calllock_asset→native_account::add_assetto park the asset in the bridge's own vault. NoBURNnote is emitted.is_native, callunlock_and_send→native_account::remove_asset+p2id::newto emit aP2IDnote to the recipient. NoMINTnote, no faucet ntx.PROOF_DATA_KEYis used as the serial number so the note commitment is deterministic per claim.Metadata moved to the bridge. All three FPI calls from the bridge into the faucet (
asset_to_origin_asset,get_metadata_hash,get_scale) are replaced with bridge-local reads out of a newfaucet_metadata_map.A single map with four faucet-ID-keyed sub-keys holds everything:
[0, 0, fid_s, fid_p][addr0, addr1, addr2, addr3][1, 0, fid_s, fid_p][addr4, origin_network, scale, 0][2, 0, fid_s, fid_p][mh_lo0..3][3, 0, fid_s, fid_p][mh_hi0..3]faucet_registry_mapis extended from[1, 0, 0, 0]to[1, is_native, 0, 0], which is backward-compatible since existing entries haveis_native = 0implicitly.CONFIG_AGG_BRIDGEcarries the full metadata payload at registration (split across two calls to fit the 16-element stack).AggLayer faucet slimmed. With metadata on the bridge, the faucet's conversion-info / metadata-hash slots and its
asset_to_origin_asset/get_metadata_hash/get_scaleprocs are dead code. Removed: theAggLayerFaucetcomponent now only re-exportsmint_and_send+burnon top ofOwnable2Step+OwnerControlled. A Miden-native faucet which wants to integrate with Agglayer, now is just a plain network fungible faucet, no AggLayer-specific storage or FPI surface needed.Follow-ups
Not in this PR; filing separately per @bobbinth's comments in the original issue for this PR:
faucet_registry_mapintofaucet_metadata_mapby parkingis_nativein sub-key 1's 4th limb. Needs a new presence check (origin-address-word non-zero) before landing.nameon-chain (AggLayer: store token name in faucet storage #2585).