use agglayer::bridge::bridge_in -> bridge
use miden::protocol::active_note
use miden::core::crypto::hashes::poseidon2
use miden::standards::attachments::network_account_target
# CONSTANTS
# =================================================================================================
const PROOF_DATA_SIZE = 536
const LEAF_DATA_SIZE = 32
const OUTPUT_NOTE_SIZE = 8
const CLAIM_NOTE_STORAGE_PTR = 0
const PROOF_DATA_START_PTR = CLAIM_NOTE_STORAGE_PTR
const LEAF_DATA_START_PTR = 536
const FAUCET_MINT_AMOUNT = 568
# ERRORS
# =================================================================================================
const ERR_CLAIM_TARGET_ACCT_MISMATCH = "CLAIM note attachment target account does not match consuming account"
# NOTE SCRIPT
# =================================================================================================
#! Agglayer Bridge CLAIM script: claims assets by calling the bridge's claim function.
#!
#! This note is consumed by the agglayer bridge account whose ID is provided
#! in the note attachment (NetworkAccountTarget). Upon consumption, the bridge validates
#! the Merkle proof, looks up the faucet from the token registry, and creates a MINT note
#! targeting the Agglayer Faucet.
#!
#! Requires that the account exposes:
#! - agglayer::bridge::bridge_in::claim procedure.
#!
#! Inputs: [ARGS, pad(12)]
#! Outputs: [pad(16)]
#!
#! NoteStorage layout (569 felts total):
#! - smtProofLocalExitRoot [0..255] : 256 felts
#! - smtProofRollupExitRoot [256..511] : 256 felts
#! - globalIndex [512..519] : 8 felts
#! - mainnetExitRoot [520..527] : 8 felts
#! - rollupExitRoot [528..535] : 8 felts
#! - leafType [536] : 1 felt
#! - originNetwork [537] : 1 felt
#! - originTokenAddress [538..542] : 5 felts
#! - destinationNetwork [543] : 1 felt
#! - destinationAddress [544..548] : 5 felts
#! - amount [549..556] : 8 felts
#! - metadata [557..564] : 8 felts
#! - padding [565..567] : 3 felts
#! - miden_claim_amount [568] : 1 felt
#!
#! Where:
#! - smtProofLocalExitRoot: SMT proof for local exit root (bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH])
#! - smtProofRollupExitRoot: SMT proof for rollup exit root (bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH])
#! - globalIndex: Global index (uint256 as 8 u32 felts). This is a packed "locator" for the leaf being claimed:
#! - mainnetFlag (1 bit): 1 = leaf came from L1 (Mainnet Exit Tree), 0 = leaf came from an L2 rollup
#! - rollupIndex (32 bits): which rollup (only used when mainnetFlag=0)
#! - localRootIndex (32 bits): leaf index / depositCount in the origin chain's Local Exit Tree
#! - Top 191 bits are ignored (not required to be zero), so indexers must decode it exactly like the contract does
#! - mainnetExitRoot: Mainnet exit root hash (bytes32 as 8 u32 felts)
#! - rollupExitRoot: Rollup exit root hash (bytes32 as 8 u32 felts)
#! - leafType: Leaf type (uint32): [0] transfer Ether / ERC20 tokens, [1] message
#! - originNetwork: Origin network identifier (uint32)
#! - originTokenAddress: Origin token address (address as 5 u32 felts)
#! - destinationNetwork: Destination network identifier (uint32)
#! - destinationAddress: 20-byte Ethereum address decodable into a Miden AccountId (5 u32 felts)
#! - amount: Amount of tokens (uint256 as 8 u32 felts)
#! - metadata: ABI encoded metadata (fixed size)
#! - miden_claim_amount: Scaled-down Miden token amount (Felt). This is the Y value computed from
#! scaling down the Ethereum amount (X) by the scale exponent: Y = floor(X / 10^scale_exp)
#!
#! Panics if:
#! - account does not expose claim procedure.
#! - note attachment target account does not match the consuming account.
begin
dropw
# => [pad(16)]
# Ensure note attachment targets the consuming bridge account.
exec.network_account_target::active_account_matches_target_account
assert.err=ERR_CLAIM_TARGET_ACCT_MISMATCH
# => [pad(16)]
# Load CLAIM note storage into memory, starting at address 0
push.CLAIM_NOTE_STORAGE_PTR exec.active_note::get_storage drop drop
# => [pad(16)]
exec.write_claim_data_into_advice_map_by_key
# => [PROOF_DATA_KEY, LEAF_DATA_KEY, pad(16)]
mem_load.FAUCET_MINT_AMOUNT
# => [faucet_mint_amount, PROOF_DATA_KEY, LEAF_DATA_KEY, pad(16)]
movdn.8
# => [PROOF_DATA_KEY, LEAF_DATA_KEY, faucet_mint_amount, pad(16)]
# call the Bridge Claim procedure
call.bridge::claim
# => [pad(16), pad(9)]
# a call invocation consumes and returns 16 elements, but we had trailing padding
dropw dropw drop
# => [pad(16)]
end
# HELPER PROCEDURES
# =================================================================================================
#! Reads claim data from memory and inserts it into the advice map under two separate keys.
#!
#! This procedure organizes the claim note data into two logical groups and inserts them
#! into the advice map under separate keys for easier access.
#!
#! Inputs: []
#! Outputs: [PROOF_DATA_KEY, LEAF_DATA_KEY]
#!
#! Advice map entries created:
#! PROOF_DATA_KEY => [
#! smtProofLocalExitRoot[256], // SMT proof for local exit root (256 felts, bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH])
#! smtProofRollupExitRoot[256], // SMT proof for rollup exit root (256 felts, bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH])
#! globalIndex[8], // Global index (8 felts, uint256 as 8 u32 felts)
#! mainnetExitRoot[8], // Mainnet exit root hash (8 felts, bytes32 as 8 u32 felts)
#! rollupExitRoot[8], // Rollup exit root hash (8 felts, bytes32 as 8 u32 felts)
#! ]
#!
#! LEAF_DATA_KEY => [
#! leafType[1], // Leaf type (1 felt, uint32)
#! originNetwork[1], // Origin network identifier (1 felt, uint32)
#! originTokenAddress[5], // Origin token address (5 felts, address as 5 u32 felts)
#! destinationNetwork[1], // Destination network identifier (1 felt, uint32)
#! destinationAddress[5], // Destination address (5 felts, address as 5 u32 felts)
#! amount[8], // Amount of tokens (8 felts, uint256 as 8 u32 felts)
#! metadata[8], // ABI encoded metadata (8 felts, fixed size)
#! padding[3], // padding (3 felts)
#! ]
#!
#! Invocation: exec
proc write_claim_data_into_advice_map_by_key
# 1) Get LEAF_DATA_KEY
push.LEAF_DATA_SIZE push.LEAF_DATA_START_PTR
exec.poseidon2::hash_elements
# => [LEAF_DATA_KEY]
push.LEAF_DATA_SIZE add.LEAF_DATA_START_PTR push.LEAF_DATA_START_PTR
movdn.5 movdn.5
# => [LEAF_DATA_KEY, start_ptr, end_ptr]
adv.insert_mem
# OS => [LEAF_DATA_KEY, start_ptr, end_ptr]
# AM => {LEAF_DATA_KEY: mem[start_ptr..end_ptr] }
movup.4 drop movup.4 drop
# => [LEAF_DATA_KEY]
# 2) Get PROOF_DATA_KEY
push.PROOF_DATA_SIZE push.PROOF_DATA_START_PTR
exec.poseidon2::hash_elements
# => [PROOF_DATA_KEY, LEAF_DATA_KEY]
push.PROOF_DATA_SIZE push.PROOF_DATA_START_PTR
movdn.5 movdn.5
# => [PROOF_DATA_KEY, start_ptr, end_ptr, LEAF_DATA_KEY]
adv.insert_mem
# OS => [PROOF_DATA_KEY, start_ptr, end_ptr, LEAF_DATA_KEY]
# AM => {PROOF_DATA_KEY: mem[start_ptr..end_ptr] }
movup.4 drop movup.4 drop
# => [PROOF_DATA_KEY, LEAF_DATA_KEY]
end