Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3167760
chore: unify b2agg note storage layout with claim note
mmagician Feb 10, 2026
62d903b
chore: clarify destinationAddress in CLAIM note
mmagician Feb 10, 2026
ea5c09b
feat: mem_store_double_word_unaligned
mmagician Feb 10, 2026
2c7d070
feat: compute leaf value for bridging out
mmagician Feb 10, 2026
b82f071
chore: update comment about origin network ID
mmagician Feb 11, 2026
545ba44
fix: write_address_to_memory had incorrect address arithmetic
cursoragent Feb 11, 2026
5286915
fix: handling of dest address and ID in B2AGG
mmagician Feb 11, 2026
4f58246
feat: reverse_limbs_and_change_byte_endianness
mmagician Feb 11, 2026
78b8ba9
chore: integrate byte and limb swapping to bridging
mmagician Feb 11, 2026
5a91cac
fix: swap origin net ID endianness; rearrange mem writes
mmagician Feb 11, 2026
c011f8d
chore: pad mem with zeros after metadata
mmagician Feb 12, 2026
589c7a9
feat: store LET frontier in double-word array
mmagician Feb 11, 2026
4e96929
feat: frontier test generation from param"d leaves
mmagician Feb 11, 2026
e35c439
feat: verify computed LER against expected root
mmagician Feb 11, 2026
b9b0aed
write leaf"s amounts to JSON
mmagician Feb 11, 2026
fbc27c3
fix: compare LET by elements, rev elements per word
mmagician Feb 11, 2026
d94c035
chore: Replace `unwrap()` with `expect()` for StorageSlotName parsing…
Copilot Feb 16, 2026
a1c1499
Update crates/miden-testing/tests/agglayer/bridge_out.rs
mmagician Feb 16, 2026
140ca14
Merge branch 'agglayer-new' into mmagician-bridge-out-store-frontier
mmagician Feb 16, 2026
e37cb44
Merge branch 'mmagician-bridge-out-store-frontier' into mmagician-cur…
mmagician Feb 16, 2026
29776a7
chore: move (de)ser logic to test_utils
mmagician Feb 16, 2026
fc7d332
chore: organize test_utils better
mmagician Feb 16, 2026
c06b6d5
chore: serialize amounts as strings in mmr test vecs
mmagician Feb 16, 2026
4d71785
test bridge_out frontier persistence across two consumes
cursoragent Feb 17, 2026
857d718
fix bridge_out frontier reload num_leaves endianness
cursoragent Feb 17, 2026
ed8a052
test bridge_out with shared multi-note helper and 32-leaf case
cursoragent Feb 17, 2026
bf8991d
refactor bridge_out coverage to direct 32-leaf burn flow
cursoragent Feb 17, 2026
afc240c
refactor MMR vectors to seeded per-leaf destinations
cursoragent Feb 17, 2026
3bfb9d3
chore: cleanup tests
mmagician Feb 17, 2026
1845253
Merge branch 'agglayer-new' into mmagician-bridge-out-store-frontier
mmagician Feb 18, 2026
37ba1f1
Merge branch 'mmagician-bridge-out-store-frontier' into mmagician-cur…
mmagician Feb 18, 2026
4f9d96b
Merge branch 'agglayer-new' into mmagician-cursor-bridge-out-componen…
mmagician Feb 18, 2026
5a85998
Merge branch 'agglayer-new' into mmagician-cursor-bridge-out-componen…
mmagician Feb 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 148 additions & 3 deletions crates/miden-agglayer/asm/bridge/bridge_out.masm
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use miden::protocol::active_note
use miden::protocol::active_account
use miden::protocol::native_account
use miden::protocol::note
use miden::standards::note_tag
use miden::standards::data_structures::double_word_array
use miden::protocol::output_note
use miden::core::crypto::hashes::keccak256
use miden::core::crypto::hashes::rpo256
use miden::core::word
use miden::agglayer::utils
use miden::agglayer::asset_conversion
use miden::agglayer::crypto_utils
use miden::agglayer::mmr_frontier32_keccak
Comment on lines 1 to +14
Copy link
Contributor

@partylikeits1983 partylikeits1983 Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish these imports were autoformatted to be in alphabetical order since there are so many imports. My old masm formatter would do this, but its out of date with the latest masm syntax.



# TYPE ALIASES
Expand All @@ -21,6 +25,11 @@ type MemoryAddress = u32
const BURN_ASSET_MEM_PTR=24
const LEAF_DATA_START_PTR=44

# Memory pointer for loading the LET (Local Exit Tree) frontier into memory.
# The memory layout at this address matches what append_and_update_frontier expects:
# [num_leaves, 0, 0, 0, [[FRONTIER_NODE_LO, FRONTIER_NODE_HI]; 32]]
const LET_FRONTIER_MEM_PTR=100

const LEAF_TYPE_OFFSET=0
const ORIGIN_NETWORK_OFFSET=1
const ORIGIN_TOKEN_ADDRESS_OFFSET=2
Expand All @@ -33,7 +42,13 @@ const PADDING_OFFSET=29
const PUBLIC_NOTE=1
const BURN_NOTE_NUM_STORAGE_ITEMS=0

# Storage slot constants for the LET (Local Exit Tree).
# The frontier is stored as a double-word array in a map slot.
# The root and num_leaves are stored in separate value slots.
const LOCAL_EXIT_TREE_SLOT=word("miden::agglayer::let")
const LET_ROOT_LO_SLOT=word("miden::agglayer::let::root_lo")
const LET_ROOT_HI_SLOT=word("miden::agglayer::let::root_hi")
const LET_NUM_LEAVES_SLOT=word("miden::agglayer::let::num_leaves")

const LEAF_TYPE_ASSET=0
# TBD once we have an AggLayer-specific network ID
Expand Down Expand Up @@ -170,10 +185,140 @@ end
#! Invocation: exec
proc add_leaf_bridge(leaf_data_start_ptr: MemoryAddress)
exec.crypto_utils::compute_leaf_value
# => [LEAF_VALUE[8]]
# => [LEAF_VALUE_LO, LEAF_VALUE_HI]

# Load the LET frontier from storage into memory at LET_FRONTIER_MEM_PTR
exec.load_let_frontier_to_memory
# => [LEAF_VALUE_LO, LEAF_VALUE_HI]

# Push frontier pointer below the leaf value
push.LET_FRONTIER_MEM_PTR movdn.8
# => [LEAF_VALUE_LO, LEAF_VALUE_HI, let_frontier_ptr]

# Append the leaf to the frontier and compute the new root
exec.mmr_frontier32_keccak::append_and_update_frontier
# => [NEW_ROOT_LO, NEW_ROOT_HI, new_leaf_count]

# Save the root and num_leaves to their value slots
exec.save_let_root_and_num_leaves
# => []

# Write the updated frontier from memory back to the map
exec.save_let_frontier_to_storage
# => []
end

#! Loads the LET (Local Exit Tree) frontier from account storage into memory.
#!
#! The num_leaves is read from its dedicated value slot, and the 32 frontier entries are read
#! from the LET map slot (double-word array, indices 0..31). The data is placed into memory at
#! LET_FRONTIER_MEM_PTR, matching the layout expected by append_and_update_frontier:
#! [num_leaves, 0, 0, 0, [[FRONTIER_NODE_LO, FRONTIER_NODE_HI]; 32]]
#!
#! Empty (uninitialized) map entries return zeros, which is the correct initial state for the
#! frontier when there are no leaves.
#!
#! Inputs: []
#! Outputs: []
#!
#! Invocation: exec
proc load_let_frontier_to_memory
# 1. Load num_leaves from its value slot
push.LET_NUM_LEAVES_SLOT[0..2]
exec.active_account::get_item
# => [num_leaves_word]

push.LET_FRONTIER_MEM_PTR mem_storew_be dropw
# => []

# 2. Load 32 frontier double-word entries from the map via double_word_array::get
push.0
# => [h=0]

repeat.32
# => [h]

# Read frontier[h] as a double word from the map
dup push.LOCAL_EXIT_TREE_SLOT[0..2]
exec.double_word_array::get
# => [VALUE_0, VALUE_1, h]

# Compute memory address and store the double word
dup.8 mul.8 add.LET_FRONTIER_MEM_PTR add.4 movdn.8
# => [VALUE_0, VALUE_1, mem_addr, h]
exec.utils::mem_store_double_word
dropw dropw drop
# => [h]

# TODO: Add LEAF_VALUE to MMR frontier
dropw dropw
add.1
# => [h+1]
end

drop
# => []
end

#! Saves the Local Exit Root and num_leaves to their dedicated value slots.
#!
#! Inputs: [NEW_ROOT_LO, NEW_ROOT_HI, new_leaf_count]
#! Outputs: []
#!
#! Invocation: exec
proc save_let_root_and_num_leaves
# 1. Save root lo word to its value slot
push.LET_ROOT_LO_SLOT[0..2]
exec.native_account::set_item
dropw
# => [NEW_ROOT_HI, new_leaf_count]

# 2. Save root hi word to its value slot
push.LET_ROOT_HI_SLOT[0..2]
exec.native_account::set_item
dropw
# => [new_leaf_count]

# 3. Save new_leaf_count to its value slot as [new_leaf_count, 0, 0, 0]
push.0.0.0
# => [0, 0, 0, new_leaf_count]
push.LET_NUM_LEAVES_SLOT[0..2]
exec.native_account::set_item
dropw
# => []
end

#! Writes the 32 frontier entries from memory back to the LET map slot.
#!
#! Each frontier entry is a double word (Keccak256 digest) stored at
#! LET_FRONTIER_MEM_PTR + 4 + h * 8, and is written to the map at double_word_array index h.
#!
#! Inputs: []
#! Outputs: []
#!
#! Invocation: exec
proc save_let_frontier_to_storage
push.0
# => [h=0]

repeat.32
# => [h]

# Load frontier[h] double word from memory
dup mul.8 add.LET_FRONTIER_MEM_PTR add.4
exec.utils::mem_load_double_word
# => [VALUE_0, VALUE_1, h]

# Write it back to the map at index h
dup.8 push.LOCAL_EXIT_TREE_SLOT[0..2]
exec.double_word_array::set
dropw dropw
# => [h]

add.1
# => [h+1]
end

drop
# => []
end

#! Writes the destination address to memory.
Expand Down
11 changes: 9 additions & 2 deletions crates/miden-agglayer/solidity-compat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,12 @@ The canonical zeros should match the constants in:

### MMR Frontier Vectors

The `test_generateVectors` adds leaves `0, 1, 2, ...` (as left-padded 32-byte values)
and outputs the root after each addition.
The `test_generateVectors` adds 32 leaves and outputs the root after each addition.
Each leaf uses:

- `amounts[i] = i + 1`
- `destination_networks[i]` and `destination_addresses[i]` generated deterministically from
a fixed seed in `MMRTestVectors.t.sol`

This gives reproducible "random-looking" destination parameters while keeping vector generation
stable across machines and reruns.
6 changes: 6 additions & 0 deletions crates/miden-agglayer/solidity-compat/foundry.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,11 @@
"name": "v1.14.0",
"rev": "1801b0541f4fda118a10798fd3486bb7051c5dd6"
}
},
"lib/openzeppelin-contracts-upgradeable": {
"branch": {
"name": "release-v4.9",
"rev": "2d081f24cac1a867f6f73d512f2022e1fa987854"
}
}
}
Loading