Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b8c256d
fix(AggLayer): use correct byte<>`Felt` conversion (#2387)
mmagician Feb 6, 2026
be44b8a
Merge branch 'next' into agglayer-new
mmagician Feb 10, 2026
0d9d083
feat(AggLayer): Move padding to the end of `NoteStorage` for `CLAIM` …
mmagician Feb 14, 2026
046b02b
feat(AggLayer): byte packing from felts to match Solidity `abi.encode…
mmagician Feb 14, 2026
8ad690b
feat(AggLayer): `GlobalIndex` wrapper (#2407)
mmagician Feb 14, 2026
c5cc3d2
feat(AggLayer): e2e bridge-in flow with real bridge data (#2413)
mmagician Feb 15, 2026
c3b4497
chore(Agglayer): refactors to make scaling down easier (#2446)
mmagician Feb 16, 2026
0ff8f8f
feat: u256 to felt scaling procedure (#2331)
partylikeits1983 Feb 18, 2026
3b4bd70
feat(AggLayer): process bridging-out data and load `LeafData` to memo…
mmagician Feb 18, 2026
245f7b0
feat(AggLayer): Store `hash(GER)` in the bridge storage and implement…
mmagician Feb 18, 2026
b1c483b
feat(AggLayer): store Local Exit Tree in `AggLayerBridge` contract an…
mmagician Feb 18, 2026
be765b0
feat(AggLayer): faucet registry (#2426)
mmagician Feb 18, 2026
86fcb9e
feat: add solidity-compat test for generating local claimAsset() para…
partylikeits1983 Feb 23, 2026
1531d50
refactor: address review nits from PR #2474 (#2489)
mmagician Feb 23, 2026
1c33faf
Merge branch 'next' into agglayer
mmagician Feb 23, 2026
9cfb4f2
feat: add native asset claim amount as element in `NoteStorage` of `C…
partylikeits1983 Feb 23, 2026
0137fce
feat(AggLayer): Sender (resp. consumer) validation on `CONFIG_AGG_BRI…
mmagician Feb 24, 2026
4ee2778
refactor(Agglayer): restructure `asm` directory and split out agglaye…
mmagician Feb 24, 2026
b8c3b82
refactor: wrap `verify_u128_*` in `verify_u256_*` procedure (#2504)
partylikeits1983 Feb 24, 2026
0e8f971
Merge branch 'next' into agglayer
mmagician Feb 24, 2026
6bc6903
refactor: enforce `CLAIM` note consumer via `NetworkAccountTarget` at…
mmagician Feb 25, 2026
893c7de
fix: Move sender validation from note script into bridge procedures (…
mmagician Feb 25, 2026
0394ef2
docs(AggLayer): fix doc comments and inline comments for bridge compo…
mmagician Feb 25, 2026
7fe02b6
refactor: remove `OutputNoteData` from `AdviceMap` in `CLAIM` note (#…
partylikeits1983 Feb 25, 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
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@
[submodule "crates/miden-agglayer/solidity-compat/lib/agglayer-contracts"]
path = crates/miden-agglayer/solidity-compat/lib/agglayer-contracts
url = https://github.com/agglayer/agglayer-contracts
[submodule "crates/miden-agglayer/solidity-compat/lib/openzeppelin-contracts-upgradeable"]
path = crates/miden-agglayer/solidity-compat/lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable.git
branch = release-v4.9
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Features

- Added AggLayer faucet registry to bridge account with conversion metadata, `CONFIG_AGG_BRIDGE` note for faucet registration, and FPI-based asset conversion in `bridge_out` ([#2426](https://github.com/0xMiden/miden-base/pull/2426)).
- Enable `CodeBuilder` to add advice map entries to compiled scripts ([#2275](https://github.com/0xMiden/miden-base/pull/2275)).
- Added `BlockNumber::MAX` constant to represent the maximum block number ([#2324](https://github.com/0xMiden/miden-base/pull/2324)).
- Added single-word `Array` standard ([#2203](https://github.com/0xMiden/miden-base/pull/2203)).
Expand All @@ -12,6 +13,8 @@
- Implemented verification of AggLayer deposits (claims) against GER ([#2295](https://github.com/0xMiden/miden-base/pull/2295), [#2288](https://github.com/0xMiden/miden-base/pull/2288)).
- Added `SignedBlock` struct ([#2355](https://github.com/0xMiden/miden-base/pull/2235)).
- Added `PackageKind` and `ProcedureExport` ([#2358](https://github.com/0xMiden/miden-base/pull/2358)).
- Changed GER storage to a map ([#2388](https://github.com/0xMiden/miden-base/pull/2388)).
- Implemented `assert_valid_ger` procedure for verifying GER against storage ([#2388](https://github.com/0xMiden/miden-base/pull/2388)).
- Added `P2idNoteStorage` and `P2ideNoteStorage` ([#2389](https://github.com/0xMiden/miden-base/pull/2389)).
- [BREAKING] Added `get_asset` and `get_initial_asset` kernel procedures and removed `get_balance`, `get_initial_balance` and `has_non_fungible_asset` kernel procedures ([#2369](https://github.com/0xMiden/miden-base/pull/2369)).
- Added `p2id::new` MASM constructor procedure for creating P2ID notes from MASM code ([#2381](https://github.com/0xMiden/miden-base/pull/2381)).
Expand All @@ -24,6 +27,7 @@

### Changes

- Restructured `miden-agglayer/asm` directory to separate bridge and faucet into per-component libraries, preventing cross-component procedure exposure ([#2294](https://github.com/0xMiden/miden-base/issues/2294)).
- Made kernel procedure offset constants public and replaced accessor procedures with direct constant usage ([#2375](https://github.com/0xMiden/miden-base/pull/2375)).
- [BREAKING] Made `AccountComponentMetadata` a required parameter of `AccountComponent::new()`; removed `with_supported_type`, `with_supports_all_types`, and `with_metadata` methods from `AccountComponent`; simplified `AccountComponentMetadata::new()` to take just `name`; renamed `AccountComponentTemplateError` to `ComponentMetadataError` ([#2373](https://github.com/0xMiden/miden-base/pull/2373), [#2395](https://github.com/0xMiden/miden-base/pull/2395)).
- Fixed MASM inline comment casing to adhere to commenting conventions ([#2398](https://github.com/0xMiden/miden-base/pull/2398)).
Expand All @@ -44,6 +48,8 @@
- [BREAKING] Updated note tag length to support up to 32 bits ([#2329](https://github.com/0xMiden/miden-base/pull/2329)).
- [BREAKING] Moved standard note code into individual note modules ([#2363](https://github.com/0xMiden/miden-base/pull/2363)).
- [BREAKING] Added `miden::standards::note_tag` module for account target note tags ([#2366](https://github.com/0xMiden/miden-base/pull/2366)).
- Unified the underlying representation of `ExitRoot` and `SmtNode` and use type aliases ([#2387](https://github.com/0xMiden/miden-base/pull/2387)).
- [BREAKING] Moved padding to the end of `CLAIM` `NoteStorage` layout ([#2405](https://github.com/0xMiden/miden-base/pull/2405)).
- [BREAKING] Consolidated authentication components ([#2390] (https://github.com/0xMiden/miden-base/pull/2390))
- [BREAKING] Refactored account ID and nonce memory and advice stack layout ([#2442](https://github.com/0xMiden/miden-base/pull/2442)).
- [BREAKING] Removed `hash_account` ([#2442](https://github.com/0xMiden/miden-base/pull/2442)).
Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ generate-solidity-test-vectors: ## Regenerate Solidity MMR test vectors using Fo
cd crates/miden-agglayer/solidity-compat && forge test -vv --match-test test_generateVectors
cd crates/miden-agglayer/solidity-compat && forge test -vv --match-test test_generateCanonicalZeros
cd crates/miden-agglayer/solidity-compat && forge test -vv --match-test test_generateVerificationProofData
cd crates/miden-agglayer/solidity-compat && forge test -vv --match-test test_generateLeafValueVectors
cd crates/miden-agglayer/solidity-compat && forge test -vv --match-test test_generateClaimAssetVectors

# --- benchmarking --------------------------------------------------------------------------------

Expand Down
5 changes: 5 additions & 0 deletions crates/miden-agglayer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,15 @@ testing = ["miden-protocol/testing"]
# Miden dependencies
miden-assembly = { workspace = true }
miden-core = { workspace = true }
miden-core-lib = { workspace = true }
miden-protocol = { workspace = true }
miden-standards = { workspace = true }
miden-utils-sync = { workspace = true }

# Third-party dependencies
primitive-types = { workspace = true }
thiserror = { workspace = true }

[dev-dependencies]
miden-agglayer = { features = ["testing"], path = "." }

Expand Down
221 changes: 221 additions & 0 deletions crates/miden-agglayer/asm/agglayer/bridge/bridge_config.masm
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
use miden::core::crypto::hashes::rpo256
use miden::protocol::account_id
use miden::protocol::active_account
use miden::protocol::active_note
use miden::protocol::native_account

# ERRORS
# =================================================================================================

const ERR_GER_NOT_FOUND = "GER not found in storage"
const ERR_FAUCET_NOT_REGISTERED="faucet is not registered in the bridge's faucet registry"
const ERR_SENDER_NOT_BRIDGE_ADMIN="note sender is not the bridge admin"
const ERR_SENDER_NOT_GER_MANAGER="note sender is not the global exit root manager"

# CONSTANTS
# =================================================================================================

# Storage slots
const BRIDGE_ADMIN_SLOT=word("miden::agglayer::bridge::admin")
const GER_MANAGER_SLOT=word("miden::agglayer::bridge::ger_manager")
const GER_STORAGE_SLOT=word("miden::agglayer::bridge::ger")
const FAUCET_REGISTRY_SLOT=word("miden::agglayer::bridge::faucet_registry")

# Flags
const GER_KNOWN_FLAG=1
const IS_FAUCET_REGISTERED_FLAG=1

# PUBLIC INTERFACE
# =================================================================================================

#! Updates the Global Exit Root (GER) in the bridge account storage.
#!
#! Computes hash(GER) = rpo256::merge(GER_UPPER, GER_LOWER) and stores it in a map
#! with value [GER_KNOWN_FLAG, 0, 0, 0] to indicate the GER is known.
#!
#! Panics if the note sender is not the global exit root manager.
#!
#! Inputs: [GER_LOWER[4], GER_UPPER[4], pad(8)]
#! Outputs: [pad(16)]
#!
#! Invocation: call
pub proc update_ger
# assert the note sender is the global exit root manager.
exec.assert_sender_is_ger_manager
# => [GER_LOWER[4], GER_UPPER[4], pad(8)]

# compute hash(GER) = rpo256::merge(GER_UPPER, GER_LOWER)
# inputs: [B, A] => output: hash(A || B)
exec.rpo256::merge
# => [GER_HASH, pad(12)]

# prepare VALUE = [0, 0, 0, GER_KNOWN_FLAG]
push.GER_KNOWN_FLAG.0.0.0
# => [0, 0, 0, GER_KNOWN_FLAG, GER_HASH, pad(12)]

swapw
# => [GER_HASH, VALUE, pad(12)]

push.GER_STORAGE_SLOT[0..2]
# => [slot_id_prefix, slot_id_suffix, GER_HASH, VALUE, pad(12)]

exec.native_account::set_map_item
# => [OLD_VALUE, pad(12)]
dropw
# => [pad(16)]
end

#! Asserts that the provided GER is valid (exists in storage).
#!
#! Computes hash(GER) = rpo256::merge(GER_UPPER, GER_LOWER) and looks up the hash in
#! the GER storage map. Panics if the GER has never been stored.
#!
#! Inputs: [GER_ROOT[8]]
#! Outputs: []
#!
#! Panics if:
#! - the GER is not found in storage.
#!
#! Invocation: exec
pub proc assert_valid_ger
# compute hash(GER)
exec.rpo256::merge
# => [GER_HASH]

push.GER_STORAGE_SLOT[0..2]
# => [slot_id_prefix, slot_id_suffix, GER_HASH]

exec.active_account::get_map_item
# => [VALUE]

# assert the GER is known in storage (VALUE = [0, 0, 0, GER_KNOWN_FLAG])
push.GER_KNOWN_FLAG.0.0.0
# => [0, 0, 0, GER_KNOWN_FLAG, VALUE]

assert_eqw.err=ERR_GER_NOT_FOUND
# => []
end

#! Registers a faucet in the bridge's faucet registry.
#!
#! Writes `KEY -> [1, 0, 0, 0]` into the `faucet_registry` map, where
#! `KEY = [faucet_id_prefix, faucet_id_suffix, 0, 0]`.
#!
#! The sentinel value `[1, 0, 0, 0]` distinguishes registered faucets from
#! non-existent entries (SMTs return EMPTY_WORD for missing keys).
#!
#! Panics if the note sender is not the bridge admin.
#!
#! Inputs: [faucet_id_prefix, faucet_id_suffix, pad(14)]
#! Outputs: [pad(16)]
#!
#! Invocation: call
pub proc register_faucet
# assert the note sender is the bridge admin.
exec.assert_sender_is_bridge_admin
# => [faucet_id_prefix, faucet_id_suffix, pad(14)]

# set_map_item expects [slot_id(2), KEY(4), VALUE(4)] and returns [OLD_VALUE(4)].
push.IS_FAUCET_REGISTERED_FLAG
# => [IS_FAUCET_REGISTERED_FLAG, faucet_id_prefix, faucet_id_suffix, pad(14)]

movdn.7
# => [[faucet_id_prefix, faucet_id_suffix, 0, 0], [0, 0, 0, IS_FAUCET_REGISTERED_FLAG], pad(9)]

# Place slot ID on top
push.FAUCET_REGISTRY_SLOT[0..2]
# Stack: [slot0, slot1, [prefix, suffix, 0, 0], [0, 0, 0, 1], pad(9)]

exec.native_account::set_map_item
# => [OLD_VALUE(4), pad(9)]

dropw
end

#! Asserts that a faucet is registered in the bridge's faucet registry.
#!
#! Looks up the faucet ID in the faucet registry map and asserts the registration
#! flag is set.
#!
#! Inputs: [faucet_id_prefix, faucet_id_suffix]
#! Outputs: []
#!
#! Panics if:
#! - the faucet is not registered in the faucet registry.
#!
#! Invocation: exec
pub proc assert_faucet_registered
# Build KEY = [faucet_id_prefix, faucet_id_suffix, 0, 0]
push.0.0
movup.3 movup.3
# => [faucet_id_prefix, faucet_id_suffix, 0, 0]

push.FAUCET_REGISTRY_SLOT[0..2]
exec.active_account::get_map_item
# => [VALUE(4)]

# the stored word must be [0, 0, 0, 1] for registered faucets
drop drop drop
assert.err=ERR_FAUCET_NOT_REGISTERED
# => []
end

#! Asserts that the note sender matches the bridge admin stored in account storage.
#!
#! Reads the bridge admin account ID from BRIDGE_ADMIN_SLOT and compares it against
#! the sender of the currently executing note. Panics if they do not match.
#!
#! Inputs: [pad(16)]
#! Outputs: [pad(16)]
#!
#! Panics if:
#! - the note sender does not match the bridge admin account ID.
#!
#! Invocation: exec
pub proc assert_sender_is_bridge_admin
# => [pad(16)]

push.BRIDGE_ADMIN_SLOT[0..2]
exec.active_account::get_item
# => [admin_prefix, admin_suffix, 0, 0, pad(16)]

exec.active_note::get_sender
# => [sender_prefix, sender_suffix, admin_prefix, admin_suffix, pad(18)]

exec.account_id::is_equal
assert.err=ERR_SENDER_NOT_BRIDGE_ADMIN
# => [pad(18)]

drop drop
# => [pad(16)]
end

#! Asserts that the note sender matches the global exit root manager stored in account storage.
#!
#! Reads the GER manager account ID from GER_MANAGER_SLOT and compares it against
#! the sender of the currently executing note. Panics if they do not match.
#!
#! Inputs: [pad(16)]
#! Outputs: [pad(16)]
#!
#! Panics if:
#! - the note sender does not match the GER manager account ID.
#!
#! Invocation: exec
pub proc assert_sender_is_ger_manager
# => [pad(16)]

push.GER_MANAGER_SLOT[0..2]
exec.active_account::get_item
# => [mgr_prefix, mgr_suffix, 0, 0, pad(16)]

exec.active_note::get_sender
# => [sender_prefix, sender_suffix, mgr_prefix, mgr_suffix, pad(18)]

exec.account_id::is_equal
assert.err=ERR_SENDER_NOT_GER_MANAGER
# => [pad(18)]

drop drop
# => [pad(16)]
end
Loading