From d4ffea12b8e09c4e2eb2758fde25b4d98f23b2be Mon Sep 17 00:00:00 2001 From: Marti Date: Fri, 23 Jan 2026 13:52:43 +0000 Subject: [PATCH 01/35] feat: put target account in attachment --- .../asm/note_scripts/B2AGG.masm | 27 ++++++++++++++++- crates/miden-agglayer/src/errors/agglayer.rs | 2 ++ .../tests/agglayer/bridge_out.rs | 30 ++++++++++++++++--- 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm index a62e213daa..ffe30c399f 100644 --- a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm +++ b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm @@ -12,8 +12,9 @@ const B2AGG_NOTE_NUM_STORAGE_ITEMS=6 # ERRORS # ================================================================================================= const ERR_B2AGG_WRONG_NUMBER_OF_ASSETS="B2AGG script requires exactly 1 note asset" - const ERR_B2AGG_UNEXPECTED_NUMBER_OF_STORAGE_ITEMS="B2AGG script expects exactly 6 note storage items" +const ERR_B2AGG_TARGET_ACCOUNT_MISMATCH="B2AGG note attachment target account does not match consuming account" + #! Bridge-to-AggLayer (B2AGG) note script: bridges assets from Miden to an AggLayer-connected chain. #! @@ -34,15 +35,39 @@ const ERR_B2AGG_UNEXPECTED_NUMBER_OF_STORAGE_ITEMS="B2AGG script expects exactly #! - destination_address_2: bytes 8-11 #! - destination_address_3: bytes 12-15 #! - destination_address_4: bytes 16-19 +#! Note attachment is assumed to be a word layout: +#! - [target_id_prefix, target_id_suffix, 0, 0] #! #! Panics if: #! - The note does not contain exactly 6 storage items. #! - The note does not contain exactly 1 asset. +#! - The note attachment does not target the consuming account. #! begin dropw # => [pad(16)] + # Ensure note attachment targets the consuming account. + exec.active_note::get_metadata + # => [NOTE_ATTACHMENT, METADATA_HEADER, pad(8)] + + swapw dropw + # => [NOTE_ATTACHMENT, pad(12)] + + # Reorder attachment word to [target_id_prefix, target_id_suffix, 0, 0]. + movup.2 movup.3 + # => [target_id_prefix, target_id_suffix, 0, 0, pad(12)] + + exec.active_account::get_id + # => [account_id_prefix, account_id_suffix, target_id_prefix, target_id_suffix, 0, 0, pad(8)] + + exec.account_id::is_equal + assert.err=ERR_B2AGG_TARGET_ACCOUNT_MISMATCH + # => [0, 0, pad(14)] + + drop drop + # => [pad(16)] + # Check if reclaim exec.active_account::get_id # => [account_id_prefix, account_id_suffix, pad(16)] diff --git a/crates/miden-agglayer/src/errors/agglayer.rs b/crates/miden-agglayer/src/errors/agglayer.rs index 38c7f11b6f..516def2f72 100644 --- a/crates/miden-agglayer/src/errors/agglayer.rs +++ b/crates/miden-agglayer/src/errors/agglayer.rs @@ -16,6 +16,8 @@ pub const ERR_ADDR4_NONZERO: MasmError = MasmError::from_static_str("most-signif pub const ERR_B2AGG_UNEXPECTED_NUMBER_OF_STORAGE_ITEMS: MasmError = MasmError::from_static_str("B2AGG script expects exactly 6 note storage items"); /// Error Message: "B2AGG script requires exactly 1 note asset" pub const ERR_B2AGG_WRONG_NUMBER_OF_ASSETS: MasmError = MasmError::from_static_str("B2AGG script requires exactly 1 note asset"); +/// Error Message: "B2AGG note attachment target account does not match consuming account" +pub const ERR_B2AGG_TARGET_ACCOUNT_MISMATCH: MasmError = MasmError::from_static_str("B2AGG note attachment target account does not match consuming account"); /// Error Message: "CLAIM's target account address and transaction address do not match" pub const ERR_CLAIM_TARGET_ACCT_MISMATCH: MasmError = MasmError::from_static_str("CLAIM's target account address and transaction address do not match"); diff --git a/crates/miden-testing/tests/agglayer/bridge_out.rs b/crates/miden-testing/tests/agglayer/bridge_out.rs index ee22a0a502..d11ddc3056 100644 --- a/crates/miden-testing/tests/agglayer/bridge_out.rs +++ b/crates/miden-testing/tests/agglayer/bridge_out.rs @@ -13,6 +13,8 @@ use miden_protocol::account::{ use miden_protocol::asset::{Asset, FungibleAsset}; use miden_protocol::note::{ Note, + NoteAttachment, + NoteAttachmentScheme, NoteAssets, NoteMetadata, NoteRecipient, @@ -83,14 +85,24 @@ async fn test_bridge_out_consumes_b2agg_note() -> anyhow::Result<()> { EthAddressFormat::from_hex(destination_address).expect("Valid Ethereum address"); let address_felts = eth_address.to_elements().to_vec(); - // Combine network ID and address felts into note storage (6 felts total) + // Combine network ID and address felts into the note storage (6 felts total) let mut input_felts = vec![destination_network]; input_felts.extend(address_felts); let inputs = NoteStorage::new(input_felts.clone())?; + let target_account_id = bridge_account.id(); + // Store the target account ID in the attachment: [prefix, suffix, 0, 0]. + let attachment_word = Word::from([ + target_account_id.prefix().as_felt(), + target_account_id.suffix(), + Felt::new(0), + Felt::new(0), + ]); + let attachment = NoteAttachment::new_word(NoteAttachmentScheme::none(), attachment_word); // Create the B2AGG note with assets from the faucet - let b2agg_note_metadata = NoteMetadata::new(faucet.id(), note_type, tag); + let b2agg_note_metadata = + NoteMetadata::new(faucet.id(), note_type, tag).with_attachment(attachment); let b2agg_note_assets = NoteAssets::new(vec![bridge_asset])?; let serial_num = Word::from([1, 2, 3, 4u32]); let b2agg_note_script = NoteScript::new(b2agg_script); @@ -239,15 +251,25 @@ async fn test_b2agg_note_reclaim_scenario() -> anyhow::Result<()> { EthAddressFormat::from_hex(destination_address).expect("Valid Ethereum address"); let address_felts = eth_address.to_elements().to_vec(); - // Combine network ID and address felts into note storage (6 felts total) + // Combine network ID and address felts into the note storage (6 felts total) let mut input_felts = vec![destination_network]; input_felts.extend(address_felts); let inputs = NoteStorage::new(input_felts.clone())?; + let target_account_id = user_account.id(); + // Store the target account ID in the attachment: [prefix, suffix, 0, 0]. + let attachment_word = Word::from([ + target_account_id.prefix().as_felt(), + target_account_id.suffix(), + Felt::new(0), + Felt::new(0), + ]); + let attachment = NoteAttachment::new_word(NoteAttachmentScheme::none(), attachment_word); // Create the B2AGG note with the USER ACCOUNT as the sender // This is the key difference - the note sender will be the same as the consuming account - let b2agg_note_metadata = NoteMetadata::new(user_account.id(), note_type, tag); + let b2agg_note_metadata = + NoteMetadata::new(user_account.id(), note_type, tag).with_attachment(attachment); let b2agg_note_assets = NoteAssets::new(vec![bridge_asset])?; let serial_num = Word::from([1, 2, 3, 4u32]); let b2agg_note_script = NoteScript::new(b2agg_script); From 371efae0dd16d27bc6a7c1d1a90cb77a7d2cf1fc Mon Sep 17 00:00:00 2001 From: Marti Date: Fri, 23 Jan 2026 14:05:39 +0000 Subject: [PATCH 02/35] feat: extract b2agg creation to helper --- crates/miden-agglayer/src/bridge_out.rs | 123 ++++++++++++++++++ crates/miden-agglayer/src/lib.rs | 2 + .../tests/agglayer/bridge_out.rs | 105 +++++---------- 3 files changed, 154 insertions(+), 76 deletions(-) create mode 100644 crates/miden-agglayer/src/bridge_out.rs diff --git a/crates/miden-agglayer/src/bridge_out.rs b/crates/miden-agglayer/src/bridge_out.rs new file mode 100644 index 0000000000..6ae7d2c2b2 --- /dev/null +++ b/crates/miden-agglayer/src/bridge_out.rs @@ -0,0 +1,123 @@ +//! Bridge Out note creation utilities. +//! +//! This module provides helpers for creating B2AGG (Bridge to AggLayer) notes, +//! which are used to bridge assets out from Miden to the AggLayer network. + +use alloc::vec::Vec; + +use miden_core::{Felt, Word}; +use miden_protocol::account::AccountId; +use miden_protocol::crypto::rand::FeltRng; +use miden_protocol::errors::NoteError; +use miden_protocol::note::{ + Note, + NoteAssets, + NoteAttachment, + NoteAttachmentScheme, + NoteMetadata, + NoteRecipient, + NoteStorage, + NoteTag, + NoteType, +}; + +use crate::{EthAddressFormat, b2agg_script}; + +// B2AGG NOTE STRUCTURES +// ================================================================================================ + +/// Storage data for B2AGG note creation. +/// +/// Contains the destination network and address information required +/// for bridging assets to the AggLayer network. +#[derive(Debug, Clone)] +pub struct B2AggNoteStorage { + /// Destination network identifier (AggLayer-assigned network ID) + pub destination_network: u32, + /// Destination Ethereum address (20 bytes) + pub destination_address: EthAddressFormat, +} + +impl B2AggNoteStorage { + /// Creates a new B2AGG note storage with the specified destination. + pub fn new(destination_network: u32, destination_address: EthAddressFormat) -> Self { + Self { destination_network, destination_address } + } + + /// Converts the storage data to a vector of field elements for note storage. + /// + /// The layout is: + /// - 1 felt: destination_network + /// - 5 felts: destination_address (20 bytes as 5 u32 values) + pub fn to_elements(&self) -> Vec { + let mut elements = Vec::with_capacity(6); + + // Destination network + elements.push(Felt::new(self.destination_network as u64)); + + // Destination address (5 u32 felts) + elements.extend(self.destination_address.to_elements()); + + elements + } +} + +impl TryFrom for NoteStorage { + type Error = NoteError; + + fn try_from(storage: B2AggNoteStorage) -> Result { + NoteStorage::new(storage.to_elements()) + } +} + +// B2AGG NOTE CREATION +// ================================================================================================ + +/// Generates a B2AGG (Bridge to AggLayer) note. +/// +/// This note is used to bridge assets from Miden to another network via the AggLayer. +/// When consumed by a bridge account, the assets are burned and a corresponding +/// claim can be made on the destination network. +/// +/// # Parameters +/// - `storage`: The destination network and address information +/// - `assets`: The assets to bridge (must be fungible assets from a network faucet) +/// - `target_account_id`: The account ID that will consume this note (bridge account) +/// - `sender_account_id`: The account ID of the note creator +/// - `note_type`: The type of note (Public or Private) +/// - `rng`: Random number generator for creating the note serial number +/// +/// # Errors +/// Returns an error if note creation fails. +pub fn create_b2agg_note( + storage: B2AggNoteStorage, + assets: NoteAssets, + target_account_id: AccountId, + sender_account_id: AccountId, + note_type: NoteType, + rng: &mut R, +) -> Result { + let note_storage = NoteStorage::try_from(storage)?; + + let tag = NoteTag::new(0); + + // Store the target account ID in the attachment: [prefix, suffix, 0, 0] + let attachment_word = Word::from([ + target_account_id.prefix().as_felt(), + target_account_id.suffix(), + Felt::new(0), + Felt::new(0), + ]); + let attachment = NoteAttachment::new_word(NoteAttachmentScheme::none(), attachment_word); + + let metadata = NoteMetadata::new(sender_account_id, note_type, tag).with_attachment(attachment); + + let b2agg_script = b2agg_script(); + let recipient = NoteRecipient::new( + rng.draw_word(), + miden_protocol::note::NoteScript::new(b2agg_script), + note_storage, + ); + + Ok(Note::new(assets, metadata, recipient)) +} diff --git a/crates/miden-agglayer/src/lib.rs b/crates/miden-agglayer/src/lib.rs index 535c4f3cbf..c5073ef6d3 100644 --- a/crates/miden-agglayer/src/lib.rs +++ b/crates/miden-agglayer/src/lib.rs @@ -24,12 +24,14 @@ use miden_standards::account::auth::NoAuth; use miden_standards::account::faucets::NetworkFungibleFaucet; use miden_utils_sync::LazyLock; +pub mod bridge_out; pub mod claim_note; pub mod errors; pub mod eth_types; pub mod update_ger_note; pub mod utils; +pub use bridge_out::{B2AggNoteStorage, create_b2agg_note}; pub use claim_note::{ ClaimNoteStorage, ExitRoot, diff --git a/crates/miden-testing/tests/agglayer/bridge_out.rs b/crates/miden-testing/tests/agglayer/bridge_out.rs index d11ddc3056..bc1e2bc3e8 100644 --- a/crates/miden-testing/tests/agglayer/bridge_out.rs +++ b/crates/miden-testing/tests/agglayer/bridge_out.rs @@ -1,6 +1,7 @@ extern crate alloc; -use miden_agglayer::{EthAddressFormat, b2agg_script, bridge_out_component}; +use miden_agglayer::{B2AggNoteStorage, EthAddressFormat, bridge_out_component, create_b2agg_note}; +use miden_protocol::Felt; use miden_protocol::account::{ Account, AccountId, @@ -11,20 +12,8 @@ use miden_protocol::account::{ StorageSlotName, }; use miden_protocol::asset::{Asset, FungibleAsset}; -use miden_protocol::note::{ - Note, - NoteAttachment, - NoteAttachmentScheme, - NoteAssets, - NoteMetadata, - NoteRecipient, - NoteScript, - NoteStorage, - NoteTag, - NoteType, -}; +use miden_protocol::note::{NoteAssets, NoteScript, NoteTag, NoteType}; use miden_protocol::transaction::OutputNote; -use miden_protocol::{Felt, Word}; use miden_standards::account::faucets::FungibleFaucetExt; use miden_standards::note::StandardNote; use miden_testing::{AccountState, Auth, MockChain}; @@ -70,44 +59,25 @@ async fn test_bridge_out_consumes_b2agg_note() -> anyhow::Result<()> { let amount = Felt::new(100); let bridge_asset: Asset = FungibleAsset::new(faucet.id(), amount.into()).unwrap().into(); - let tag = NoteTag::new(0); - let note_type = NoteType::Public; // Use Public note type for network transaction - - // Get the B2AGG note script - let b2agg_script = b2agg_script(); // Create note storage with destination network and address - // destination_network: u32 (AggLayer-assigned network ID) - // destination_address: 20 bytes (Ethereum address) split into 5 u32 values - let destination_network = Felt::new(1); // Example network ID + let destination_network = 1u32; // Example network ID let destination_address = "0x1234567890abcdef1122334455667788990011aa"; let eth_address = EthAddressFormat::from_hex(destination_address).expect("Valid Ethereum address"); - let address_felts = eth_address.to_elements().to_vec(); - - // Combine network ID and address felts into the note storage (6 felts total) - let mut input_felts = vec![destination_network]; - input_felts.extend(address_felts); - - let inputs = NoteStorage::new(input_felts.clone())?; - let target_account_id = bridge_account.id(); - // Store the target account ID in the attachment: [prefix, suffix, 0, 0]. - let attachment_word = Word::from([ - target_account_id.prefix().as_felt(), - target_account_id.suffix(), - Felt::new(0), - Felt::new(0), - ]); - let attachment = NoteAttachment::new_word(NoteAttachmentScheme::none(), attachment_word); - - // Create the B2AGG note with assets from the faucet - let b2agg_note_metadata = - NoteMetadata::new(faucet.id(), note_type, tag).with_attachment(attachment); - let b2agg_note_assets = NoteAssets::new(vec![bridge_asset])?; - let serial_num = Word::from([1, 2, 3, 4u32]); - let b2agg_note_script = NoteScript::new(b2agg_script); - let b2agg_note_recipient = NoteRecipient::new(serial_num, b2agg_note_script, inputs); - let b2agg_note = Note::new(b2agg_note_assets, b2agg_note_metadata, b2agg_note_recipient); + + let storage = B2AggNoteStorage::new(destination_network, eth_address); + let assets = NoteAssets::new(vec![bridge_asset])?; + + // Create the B2AGG note using the helper + let b2agg_note = create_b2agg_note( + storage, + assets, + bridge_account.id(), + faucet.id(), + NoteType::Public, + builder.rng_mut(), + )?; // Add the B2AGG note to the mock chain builder.add_output_note(OutputNote::Full(b2agg_note.clone())); @@ -238,43 +208,26 @@ async fn test_b2agg_note_reclaim_scenario() -> anyhow::Result<()> { let amount = Felt::new(50); let bridge_asset: Asset = FungibleAsset::new(faucet.id(), amount.into()).unwrap().into(); - let tag = NoteTag::new(0); - let note_type = NoteType::Public; - - // Get the B2AGG note script - let b2agg_script = b2agg_script(); // Create note storage with destination network and address - let destination_network = Felt::new(1); + let destination_network = 1u32; let destination_address = "0x1234567890abcdef1122334455667788990011aa"; let eth_address = EthAddressFormat::from_hex(destination_address).expect("Valid Ethereum address"); - let address_felts = eth_address.to_elements().to_vec(); - - // Combine network ID and address felts into the note storage (6 felts total) - let mut input_felts = vec![destination_network]; - input_felts.extend(address_felts); - - let inputs = NoteStorage::new(input_felts.clone())?; - let target_account_id = user_account.id(); - // Store the target account ID in the attachment: [prefix, suffix, 0, 0]. - let attachment_word = Word::from([ - target_account_id.prefix().as_felt(), - target_account_id.suffix(), - Felt::new(0), - Felt::new(0), - ]); - let attachment = NoteAttachment::new_word(NoteAttachmentScheme::none(), attachment_word); + + let storage = B2AggNoteStorage::new(destination_network, eth_address); + let assets = NoteAssets::new(vec![bridge_asset])?; // Create the B2AGG note with the USER ACCOUNT as the sender // This is the key difference - the note sender will be the same as the consuming account - let b2agg_note_metadata = - NoteMetadata::new(user_account.id(), note_type, tag).with_attachment(attachment); - let b2agg_note_assets = NoteAssets::new(vec![bridge_asset])?; - let serial_num = Word::from([1, 2, 3, 4u32]); - let b2agg_note_script = NoteScript::new(b2agg_script); - let b2agg_note_recipient = NoteRecipient::new(serial_num, b2agg_note_script, inputs); - let b2agg_note = Note::new(b2agg_note_assets, b2agg_note_metadata, b2agg_note_recipient); + let b2agg_note = create_b2agg_note( + storage, + assets, + user_account.id(), + user_account.id(), + NoteType::Public, + builder.rng_mut(), + )?; // Add the B2AGG note to the mock chain builder.add_output_note(OutputNote::Full(b2agg_note.clone())); From 1b044d3760b9a1ea27cef571e0e4ad7b83dabb04 Mon Sep 17 00:00:00 2001 From: Marti Date: Fri, 23 Jan 2026 14:18:30 +0000 Subject: [PATCH 03/35] lint: regen error file --- crates/miden-agglayer/src/errors/agglayer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/miden-agglayer/src/errors/agglayer.rs b/crates/miden-agglayer/src/errors/agglayer.rs index 516def2f72..95d62c618d 100644 --- a/crates/miden-agglayer/src/errors/agglayer.rs +++ b/crates/miden-agglayer/src/errors/agglayer.rs @@ -12,12 +12,12 @@ use miden_protocol::errors::MasmError; /// Error Message: "most-significant 4 bytes (addr4) must be zero" pub const ERR_ADDR4_NONZERO: MasmError = MasmError::from_static_str("most-significant 4 bytes (addr4) must be zero"); +/// Error Message: "B2AGG note attachment target account does not match consuming account" +pub const ERR_B2AGG_TARGET_ACCOUNT_MISMATCH: MasmError = MasmError::from_static_str("B2AGG note attachment target account does not match consuming account"); /// Error Message: "B2AGG script expects exactly 6 note storage items" pub const ERR_B2AGG_UNEXPECTED_NUMBER_OF_STORAGE_ITEMS: MasmError = MasmError::from_static_str("B2AGG script expects exactly 6 note storage items"); /// Error Message: "B2AGG script requires exactly 1 note asset" pub const ERR_B2AGG_WRONG_NUMBER_OF_ASSETS: MasmError = MasmError::from_static_str("B2AGG script requires exactly 1 note asset"); -/// Error Message: "B2AGG note attachment target account does not match consuming account" -pub const ERR_B2AGG_TARGET_ACCOUNT_MISMATCH: MasmError = MasmError::from_static_str("B2AGG note attachment target account does not match consuming account"); /// Error Message: "CLAIM's target account address and transaction address do not match" pub const ERR_CLAIM_TARGET_ACCT_MISMATCH: MasmError = MasmError::from_static_str("CLAIM's target account address and transaction address do not match"); From bfe80556765012a0617b3bc755a0b47d7da9c47b Mon Sep 17 00:00:00 2001 From: Marti Date: Sat, 24 Jan 2026 10:47:49 +0000 Subject: [PATCH 04/35] feat: use NetworkAccountTarget for attachments - make bridge a network account - move the ID check to non-reclaim branch --- .../asm/note_scripts/B2AGG.masm | 41 +++++++++---------- crates/miden-agglayer/src/bridge_out.rs | 19 ++++----- crates/miden-agglayer/src/lib.rs | 2 +- .../tests/agglayer/bridge_out.rs | 24 ++++++----- 4 files changed, 42 insertions(+), 44 deletions(-) diff --git a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm index ffe30c399f..21773cd3d7 100644 --- a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm +++ b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm @@ -36,7 +36,7 @@ const ERR_B2AGG_TARGET_ACCOUNT_MISMATCH="B2AGG note attachment target account do #! - destination_address_3: bytes 12-15 #! - destination_address_4: bytes 16-19 #! Note attachment is assumed to be a word layout: -#! - [target_id_prefix, target_id_suffix, 0, 0] +#! - [target_id_suffix, target_id_prefix, 0, 0] #! #! Panics if: #! - The note does not contain exactly 6 storage items. @@ -47,27 +47,6 @@ begin dropw # => [pad(16)] - # Ensure note attachment targets the consuming account. - exec.active_note::get_metadata - # => [NOTE_ATTACHMENT, METADATA_HEADER, pad(8)] - - swapw dropw - # => [NOTE_ATTACHMENT, pad(12)] - - # Reorder attachment word to [target_id_prefix, target_id_suffix, 0, 0]. - movup.2 movup.3 - # => [target_id_prefix, target_id_suffix, 0, 0, pad(12)] - - exec.active_account::get_id - # => [account_id_prefix, account_id_suffix, target_id_prefix, target_id_suffix, 0, 0, pad(8)] - - exec.account_id::is_equal - assert.err=ERR_B2AGG_TARGET_ACCOUNT_MISMATCH - # => [0, 0, pad(14)] - - drop drop - # => [pad(16)] - # Check if reclaim exec.active_account::get_id # => [account_id_prefix, account_id_suffix, pad(16)] @@ -83,6 +62,24 @@ begin exec.basic_wallet::add_assets_to_account # => [pad(16)] else + # Ensure note attachment targets the consuming bridge account. + exec.active_note::get_metadata + # => [NOTE_ATTACHMENT, METADATA_HEADER, pad(8)] + + swapw dropw + # => [NOTE_ATTACHMENT, pad(12)] + + # Reorder attachment word to [target_id_prefix, target_id_suffix]. + drop drop + # => [target_id_prefix, target_id_suffix, pad(14)] (auto-padding) + + exec.active_account::get_id + # => [account_id_prefix, account_id_suffix, target_id_prefix, target_id_suffix, pad(14)] + + exec.account_id::is_equal + assert.err=ERR_B2AGG_TARGET_ACCOUNT_MISMATCH + # => [pad(16)] + # Store note storage -> mem[8..14] push.8 exec.active_note::get_storage # => [num_storage_items, dest_ptr, pad(16)] diff --git a/crates/miden-agglayer/src/bridge_out.rs b/crates/miden-agglayer/src/bridge_out.rs index 6ae7d2c2b2..59ebc9c589 100644 --- a/crates/miden-agglayer/src/bridge_out.rs +++ b/crates/miden-agglayer/src/bridge_out.rs @@ -3,9 +3,10 @@ //! This module provides helpers for creating B2AGG (Bridge to AggLayer) notes, //! which are used to bridge assets out from Miden to the AggLayer network. +use alloc::string::ToString; use alloc::vec::Vec; -use miden_core::{Felt, Word}; +use miden_core::Felt; use miden_protocol::account::AccountId; use miden_protocol::crypto::rand::FeltRng; use miden_protocol::errors::NoteError; @@ -13,13 +14,14 @@ use miden_protocol::note::{ Note, NoteAssets, NoteAttachment, - NoteAttachmentScheme, + NoteExecutionHint, NoteMetadata, NoteRecipient, NoteStorage, NoteTag, NoteType, }; +use miden_standards::note::NetworkAccountTarget; use crate::{EthAddressFormat, b2agg_script}; @@ -101,14 +103,11 @@ pub fn create_b2agg_note( let tag = NoteTag::new(0); - // Store the target account ID in the attachment: [prefix, suffix, 0, 0] - let attachment_word = Word::from([ - target_account_id.prefix().as_felt(), - target_account_id.suffix(), - Felt::new(0), - Felt::new(0), - ]); - let attachment = NoteAttachment::new_word(NoteAttachmentScheme::none(), attachment_word); + // map error into other error + let attachment = NoteAttachment::from( + NetworkAccountTarget::new(target_account_id, NoteExecutionHint::None) + .map_err(|e| NoteError::other(e.to_string()))?, + ); let metadata = NoteMetadata::new(sender_account_id, note_type, tag).with_attachment(attachment); diff --git a/crates/miden-agglayer/src/lib.rs b/crates/miden-agglayer/src/lib.rs index c5073ef6d3..0221063585 100644 --- a/crates/miden-agglayer/src/lib.rs +++ b/crates/miden-agglayer/src/lib.rs @@ -270,7 +270,7 @@ pub fn create_bridge_account_builder(seed: Word) -> AccountBuilder { let bridge_out_component = bridge_out_component(vec![]); Account::builder(seed.into()) - .storage_mode(AccountStorageMode::Public) + .storage_mode(AccountStorageMode::Network) .with_component(bridge_out_component) .with_component(bridge_in_component) } diff --git a/crates/miden-testing/tests/agglayer/bridge_out.rs b/crates/miden-testing/tests/agglayer/bridge_out.rs index bc1e2bc3e8..2ee1124a4f 100644 --- a/crates/miden-testing/tests/agglayer/bridge_out.rs +++ b/crates/miden-testing/tests/agglayer/bridge_out.rs @@ -1,16 +1,14 @@ extern crate alloc; -use miden_agglayer::{B2AggNoteStorage, EthAddressFormat, bridge_out_component, create_b2agg_note}; -use miden_protocol::Felt; -use miden_protocol::account::{ - Account, - AccountId, - AccountIdVersion, - AccountStorageMode, - AccountType, - StorageSlot, - StorageSlotName, +use miden_agglayer::{ + B2AggNoteStorage, + EthAddressFormat, + create_b2agg_note, + create_existing_bridge_account, }; +use miden_crypto::rand::FeltRng; +use miden_protocol::Felt; +use miden_protocol::account::{AccountId, AccountIdVersion, AccountStorageMode, AccountType}; use miden_protocol::asset::{Asset, FungibleAsset}; use miden_protocol::note::{NoteAssets, NoteScript, NoteTag, NoteType}; use miden_protocol::transaction::OutputNote; @@ -200,6 +198,10 @@ async fn test_b2agg_note_reclaim_scenario() -> anyhow::Result<()> { let faucet = builder.add_existing_network_faucet("AGG", 1000, faucet_owner_account_id, Some(100))?; + // Create a bridge account (includes a `bridge_out` component tested here) + let bridge_account = create_existing_bridge_account(builder.rng_mut().draw_word()); + builder.add_account(bridge_account.clone())?; + // Create a user account that will create and consume the B2AGG note let mut user_account = builder.add_existing_wallet(Auth::BasicAuth)?; @@ -223,7 +225,7 @@ async fn test_b2agg_note_reclaim_scenario() -> anyhow::Result<()> { let b2agg_note = create_b2agg_note( storage, assets, - user_account.id(), + bridge_account.id(), user_account.id(), NoteType::Public, builder.rng_mut(), From b61a1f582ac4c8bbb3ae1bc81fb789e7c0aa311d Mon Sep 17 00:00:00 2001 From: Marti Date: Sat, 24 Jan 2026 10:49:32 +0000 Subject: [PATCH 05/35] fix: still need LET slot --- crates/miden-agglayer/src/lib.rs | 11 ++++++++--- crates/miden-testing/tests/agglayer/bridge_out.rs | 13 +++---------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/crates/miden-agglayer/src/lib.rs b/crates/miden-agglayer/src/lib.rs index 0221063585..9ef02c26ee 100644 --- a/crates/miden-agglayer/src/lib.rs +++ b/crates/miden-agglayer/src/lib.rs @@ -256,19 +256,24 @@ pub fn create_agglayer_faucet_component( /// Creates a complete bridge account builder with the standard configuration. pub fn create_bridge_account_builder(seed: Word) -> AccountBuilder { + // Create the "bridge_in" component let ger_upper_storage_slot_name = StorageSlotName::new("miden::agglayer::bridge::ger_upper") .expect("Bridge storage slot name should be valid"); let ger_lower_storage_slot_name = StorageSlotName::new("miden::agglayer::bridge::ger_lower") .expect("Bridge storage slot name should be valid"); - let bridge_storage_slots = vec![ + let bridge_in_storage_slots = vec![ StorageSlot::with_value(ger_upper_storage_slot_name, Word::empty()), StorageSlot::with_value(ger_lower_storage_slot_name, Word::empty()), ]; - let bridge_in_component = bridge_in_component(bridge_storage_slots); + let bridge_in_component = bridge_in_component(bridge_in_storage_slots); - let bridge_out_component = bridge_out_component(vec![]); + // Create the "bridge_out" component + let let_storage_slot_name = StorageSlotName::new("miden::agglayer::let").unwrap(); + let bridge_out_storage_slots = vec![StorageSlot::with_empty_map(let_storage_slot_name)]; + let bridge_out_component = bridge_out_component(bridge_out_storage_slots); + // Combine the components into a single account(builder) Account::builder(seed.into()) .storage_mode(AccountStorageMode::Network) .with_component(bridge_out_component) diff --git a/crates/miden-testing/tests/agglayer/bridge_out.rs b/crates/miden-testing/tests/agglayer/bridge_out.rs index 2ee1124a4f..cc3c67d6a3 100644 --- a/crates/miden-testing/tests/agglayer/bridge_out.rs +++ b/crates/miden-testing/tests/agglayer/bridge_out.rs @@ -41,16 +41,9 @@ async fn test_bridge_out_consumes_b2agg_note() -> anyhow::Result<()> { let faucet = builder.add_existing_network_faucet("AGG", 1000, faucet_owner_account_id, Some(100))?; - // Create a bridge account with the bridge_out component using network (public) storage - // Add a storage map for the bridge component to store MMR frontier data - let storage_slot_name = StorageSlotName::new("miden::agglayer::let").unwrap(); - let storage_slots = vec![StorageSlot::with_empty_map(storage_slot_name)]; - let bridge_component = bridge_out_component(storage_slots); - let account_builder = Account::builder(builder.rng_mut().random()) - .storage_mode(AccountStorageMode::Public) - .with_component(bridge_component); - let mut bridge_account = - builder.add_account_from_builder(Auth::IncrNonce, account_builder, AccountState::Exists)?; + // Create a bridge account (includes a `bridge_out` component tested here) + let mut bridge_account = create_existing_bridge_account(builder.rng_mut().draw_word()); + builder.add_account(bridge_account.clone())?; // CREATE B2AGG NOTE WITH ASSETS // -------------------------------------------------------------------------------------------- From 38132c8dfeb94274e9b0df62f6dccf592e0b091f Mon Sep 17 00:00:00 2001 From: Marti Date: Sat, 24 Jan 2026 11:14:13 +0000 Subject: [PATCH 06/35] chore: test the target mismatch logic --- .../tests/agglayer/bridge_out.rs | 86 ++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/crates/miden-testing/tests/agglayer/bridge_out.rs b/crates/miden-testing/tests/agglayer/bridge_out.rs index cc3c67d6a3..74374e982a 100644 --- a/crates/miden-testing/tests/agglayer/bridge_out.rs +++ b/crates/miden-testing/tests/agglayer/bridge_out.rs @@ -1,5 +1,6 @@ extern crate alloc; +use miden_agglayer::errors::ERR_B2AGG_TARGET_ACCOUNT_MISMATCH; use miden_agglayer::{ B2AggNoteStorage, EthAddressFormat, @@ -14,8 +15,7 @@ use miden_protocol::note::{NoteAssets, NoteScript, NoteTag, NoteType}; use miden_protocol::transaction::OutputNote; use miden_standards::account::faucets::FungibleFaucetExt; use miden_standards::note::StandardNote; -use miden_testing::{AccountState, Auth, MockChain}; -use rand::Rng; +use miden_testing::{Auth, MockChain, assert_transaction_executor_error}; /// Tests the B2AGG (Bridge to AggLayer) note script with bridge_out account component. /// @@ -266,3 +266,85 @@ async fn test_b2agg_note_reclaim_scenario() -> anyhow::Result<()> { Ok(()) } + +/// Tests that a non-target account cannot consume a B2AGG note (non-reclaim branch). +/// +/// This test covers the security check in the B2AGG note script that ensures only the +/// designated target account (specified in the note attachment) can consume the note +/// when not in reclaim mode. +/// +/// Test flow: +/// 1. Creates a network faucet to provide assets +/// 2. Creates a bridge account as the designated target for the B2AGG note +/// 3. Creates a user account as the sender (creator) of the B2AGG note +/// 4. Creates a "malicious" account with a bridge interface +/// 5. Attempts to consume the B2AGG note with the malicious account +/// 6. Verifies that the transaction fails with ERR_B2AGG_TARGET_ACCOUNT_MISMATCH +#[tokio::test] +async fn test_b2agg_note_non_target_account_cannot_consume() -> anyhow::Result<()> { + let mut builder = MockChain::builder(); + + // Create a network faucet owner account + let faucet_owner_account_id = AccountId::dummy( + [1; 15], + AccountIdVersion::Version0, + AccountType::RegularAccountImmutableCode, + AccountStorageMode::Private, + ); + + // Create a network faucet to provide assets for the B2AGG note + let faucet = + builder.add_existing_network_faucet("AGG", 1000, faucet_owner_account_id, Some(100))?; + + // Create a bridge account as the designated TARGET for the B2AGG note + let bridge_account = create_existing_bridge_account(builder.rng_mut().draw_word()); + builder.add_account(bridge_account.clone())?; + + // Create a user account as the SENDER of the B2AGG note + let sender_account = builder.add_existing_wallet(Auth::BasicAuth)?; + + // Create a "malicious" account with a bridge interface + let malicious_account = create_existing_bridge_account(builder.rng_mut().draw_word()); + builder.add_account(malicious_account.clone())?; + + // CREATE B2AGG NOTE + // -------------------------------------------------------------------------------------------- + + let amount = Felt::new(50); + let bridge_asset: Asset = FungibleAsset::new(faucet.id(), amount.into()).unwrap().into(); + + // Create note storage with destination network and address + let destination_network = 1u32; + let destination_address = "0x1234567890abcdef1122334455667788990011aa"; + let eth_address = + EthAddressFormat::from_hex(destination_address).expect("Valid Ethereum address"); + + let storage = B2AggNoteStorage::new(destination_network, eth_address); + let assets = NoteAssets::new(vec![bridge_asset])?; + + // Create the B2AGG note + let b2agg_note = create_b2agg_note( + storage, + assets, + bridge_account.id(), // target + sender_account.id(), // sender + NoteType::Public, + builder.rng_mut(), + )?; + + // Add the B2AGG note to the mock chain + builder.add_output_note(OutputNote::Full(b2agg_note.clone())); + let mock_chain = builder.build()?; + + // ATTEMPT TO CONSUME B2AGG NOTE WITH MALICIOUS ACCOUNT (SHOULD FAIL) + // -------------------------------------------------------------------------------------------- + let result = mock_chain + .build_tx_context(malicious_account.id(), &[], &[b2agg_note])? + .build()? + .execute() + .await; + + assert_transaction_executor_error!(result, ERR_B2AGG_TARGET_ACCOUNT_MISMATCH); + + Ok(()) +} From 0d83087a2631c236f5076a986f5061d432f0f338 Mon Sep 17 00:00:00 2001 From: Marti Date: Sat, 24 Jan 2026 11:28:08 +0000 Subject: [PATCH 07/35] chore: apply target checks to UPDATE_GER --- .../asm/note_scripts/UPDATE_GER.masm | 23 +++++++++++++++++++ crates/miden-agglayer/src/bridge_out.rs | 1 - crates/miden-agglayer/src/update_ger_note.rs | 16 ++++++++++--- .../tests/agglayer/update_ger.rs | 12 +++++++--- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm b/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm index baa8ebae66..a4c3380c2e 100644 --- a/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm +++ b/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm @@ -1,5 +1,7 @@ use miden::agglayer::bridge_in use miden::protocol::active_note +use miden::protocol::active_account +use miden::protocol::account_id # CONSTANTS # ================================================================================================= @@ -10,6 +12,7 @@ const STORAGE_PTR_GER_UPPER = 4 # ERRORS # ================================================================================================= const ERR_UPDATE_GER_UNEXPECTED_NUMBER_OF_STORAGE_ITEMS = "UPDATE_GER script expects exactly 8 note storage items" +const ERR_UPDATE_GER_TARGET_ACCOUNT_MISMATCH = "UPDATE_GER note attachment target account does not match consuming account" #! Agglayer Bridge UPDATE_GER script: updates the GER by calling the bridge_in::update_ger function. #! @@ -33,6 +36,26 @@ begin dropw # => [pad(16)] + # Ensure note attachment targets the consuming bridge account. + exec.active_note::get_metadata + # => [NOTE_ATTACHMENT, METADATA_HEADER, pad(8)] + + swapw dropw + # => [NOTE_ATTACHMENT, pad(12)] + + # Reorder attachment word to [target_id_prefix, target_id_suffix]. + drop drop + # => [target_id_prefix, target_id_suffix, pad(14)] (auto-padding) + + exec.active_account::get_id + # => [account_id_prefix, account_id_suffix, target_id_prefix, target_id_suffix, pad(14)] + + exec.account_id::is_equal + assert.err=ERR_UPDATE_GER_TARGET_ACCOUNT_MISMATCH + # => [pad(16)] + + # proceed with the GER update logic + push.STORAGE_PTR_GER_LOWER exec.active_note::get_storage # => [num_storage_items, dest_ptr, pad(16)] diff --git a/crates/miden-agglayer/src/bridge_out.rs b/crates/miden-agglayer/src/bridge_out.rs index 59ebc9c589..783038feb7 100644 --- a/crates/miden-agglayer/src/bridge_out.rs +++ b/crates/miden-agglayer/src/bridge_out.rs @@ -103,7 +103,6 @@ pub fn create_b2agg_note( let tag = NoteTag::new(0); - // map error into other error let attachment = NoteAttachment::from( NetworkAccountTarget::new(target_account_id, NoteExecutionHint::None) .map_err(|e| NoteError::other(e.to_string()))?, diff --git a/crates/miden-agglayer/src/update_ger_note.rs b/crates/miden-agglayer/src/update_ger_note.rs index 86dd464501..00761f8756 100644 --- a/crates/miden-agglayer/src/update_ger_note.rs +++ b/crates/miden-agglayer/src/update_ger_note.rs @@ -1,18 +1,23 @@ extern crate alloc; +use alloc::string::ToString; use alloc::vec; +use miden_protocol::account::AccountId; use miden_protocol::crypto::rand::FeltRng; use miden_protocol::errors::NoteError; use miden_protocol::note::{ Note, NoteAssets, + NoteAttachment, + NoteExecutionHint, NoteMetadata, NoteRecipient, NoteStorage, NoteTag, NoteType, }; +use miden_standards::note::NetworkAccountTarget; use crate::{ExitRoot, update_ger_script}; @@ -21,7 +26,8 @@ use crate::{ExitRoot, update_ger_script}; /// The note storage contains 8 felts: GER[0..7] pub fn create_update_ger_note( ger: ExitRoot, - sender_account_id: miden_protocol::account::AccountId, + sender_account_id: AccountId, + target_account_id: AccountId, rng: &mut R, ) -> Result { let update_ger_script = update_ger_script(); @@ -36,9 +42,13 @@ pub fn create_update_ger_note( let recipient = NoteRecipient::new(serial_num, update_ger_script, note_storage); - // Create note metadata - use a simple public tag + let attachment = NoteAttachment::from( + NetworkAccountTarget::new(target_account_id, NoteExecutionHint::None) + .map_err(|e| NoteError::other(e.to_string()))?, + ); let note_tag = NoteTag::new(0); - let metadata = NoteMetadata::new(sender_account_id, NoteType::Public, note_tag); + let metadata = NoteMetadata::new(sender_account_id, NoteType::Public, note_tag) + .with_attachment(attachment); // UPDATE_GER notes don't carry assets let assets = NoteAssets::new(vec![])?; diff --git a/crates/miden-testing/tests/agglayer/update_ger.rs b/crates/miden-testing/tests/agglayer/update_ger.rs index 06c35ad6ee..aa5ac4f0f5 100644 --- a/crates/miden-testing/tests/agglayer/update_ger.rs +++ b/crates/miden-testing/tests/agglayer/update_ger.rs @@ -3,7 +3,7 @@ use miden_protocol::Word; use miden_protocol::account::StorageSlotName; use miden_protocol::crypto::rand::FeltRng; use miden_protocol::transaction::OutputNote; -use miden_testing::MockChain; +use miden_testing::{Auth, MockChain}; #[tokio::test] async fn test_update_ger_note_updates_storage() -> anyhow::Result<()> { @@ -15,7 +15,12 @@ async fn test_update_ger_note_updates_storage() -> anyhow::Result<()> { let bridge_account = create_existing_bridge_account(bridge_seed); builder.add_account(bridge_account.clone())?; - // CREATE UPDATE_GER NOTE WITH 8 STORAGE ITEMS + // CREATE USER ACCOUNT (NOTE SENDER) + // -------------------------------------------------------------------------------------------- + let user_account = builder.add_existing_wallet(Auth::BasicAuth)?; + builder.add_account(user_account.clone())?; + + // CREATE UPDATE_GER NOTE WITH 8 STORAGE ITEMS (NEW GER AS TWO WORDS) // -------------------------------------------------------------------------------------------- let ger_bytes: [u8; 32] = [ @@ -24,7 +29,8 @@ async fn test_update_ger_note_updates_storage() -> anyhow::Result<()> { 0x77, 0x88, ]; let ger = ExitRoot::from(ger_bytes); - let update_ger_note = create_update_ger_note(ger, bridge_account.id(), builder.rng_mut())?; + let update_ger_note = + create_update_ger_note(ger, user_account.id(), bridge_account.id(), builder.rng_mut())?; builder.add_output_note(OutputNote::Full(update_ger_note.clone())); let mock_chain = builder.build()?; From d59c8a3a8eff22531e94f3ec7a238a76bd15a6ac Mon Sep 17 00:00:00 2001 From: Marti Date: Sat, 24 Jan 2026 12:42:30 +0100 Subject: [PATCH 08/35] Apply suggestion from @mmagician --- crates/miden-agglayer/asm/note_scripts/B2AGG.masm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm index 21773cd3d7..34d90fbdbb 100644 --- a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm +++ b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm @@ -35,8 +35,8 @@ const ERR_B2AGG_TARGET_ACCOUNT_MISMATCH="B2AGG note attachment target account do #! - destination_address_2: bytes 8-11 #! - destination_address_3: bytes 12-15 #! - destination_address_4: bytes 16-19 -#! Note attachment is assumed to be a word layout: -#! - [target_id_suffix, target_id_prefix, 0, 0] +#! Note attachment is constructed from a NetworkAccountTarget standard: +#! - [0, 0, target_id_prefix, target_id_suffix] #! #! Panics if: #! - The note does not contain exactly 6 storage items. From 55a87927397a54b840aae72412f5b43a8b2eecb1 Mon Sep 17 00:00:00 2001 From: Marti Date: Sat, 24 Jan 2026 15:00:04 +0000 Subject: [PATCH 09/35] chore: add TODOs --- crates/miden-agglayer/asm/note_scripts/B2AGG.masm | 2 ++ crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm | 2 ++ 2 files changed, 4 insertions(+) diff --git a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm index 34d90fbdbb..06eb9e9c8c 100644 --- a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm +++ b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm @@ -66,6 +66,8 @@ begin exec.active_note::get_metadata # => [NOTE_ATTACHMENT, METADATA_HEADER, pad(8)] + # TODO simplify once https://github.com/0xMiden/miden-base/pull/2338 lands + swapw dropw # => [NOTE_ATTACHMENT, pad(12)] diff --git a/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm b/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm index a4c3380c2e..22a5b276b2 100644 --- a/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm +++ b/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm @@ -40,6 +40,8 @@ begin exec.active_note::get_metadata # => [NOTE_ATTACHMENT, METADATA_HEADER, pad(8)] + # TODO simplify once https://github.com/0xMiden/miden-base/pull/2338 lands + swapw dropw # => [NOTE_ATTACHMENT, pad(12)] From ed6c582fb95f5efbd43806a3ac7e6f67e1eaa9d8 Mon Sep 17 00:00:00 2001 From: Marti Date: Sat, 24 Jan 2026 15:03:04 +0000 Subject: [PATCH 10/35] chore: lint --- crates/miden-agglayer/src/errors/agglayer.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/miden-agglayer/src/errors/agglayer.rs b/crates/miden-agglayer/src/errors/agglayer.rs index 95d62c618d..d087bd79e8 100644 --- a/crates/miden-agglayer/src/errors/agglayer.rs +++ b/crates/miden-agglayer/src/errors/agglayer.rs @@ -37,5 +37,7 @@ pub const ERR_NOT_U32: MasmError = MasmError::from_static_str("address limb is n /// Error Message: "maximum scaling factor is 18" pub const ERR_SCALE_AMOUNT_EXCEEDED_LIMIT: MasmError = MasmError::from_static_str("maximum scaling factor is 18"); +/// Error Message: "UPDATE_GER note attachment target account does not match consuming account" +pub const ERR_UPDATE_GER_TARGET_ACCOUNT_MISMATCH: MasmError = MasmError::from_static_str("UPDATE_GER note attachment target account does not match consuming account"); /// Error Message: "UPDATE_GER script expects exactly 8 note storage items" pub const ERR_UPDATE_GER_UNEXPECTED_NUMBER_OF_STORAGE_ITEMS: MasmError = MasmError::from_static_str("UPDATE_GER script expects exactly 8 note storage items"); From 26476ac5978de30420ffea6af0557cdf83675d6c Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 28 Jan 2026 10:36:11 +0000 Subject: [PATCH 11/35] docs(masm): trim dangling B2AGG note description Co-authored-by: marti --- crates/miden-agglayer/asm/note_scripts/B2AGG.masm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm index 06eb9e9c8c..1d982928f6 100644 --- a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm +++ b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm @@ -20,9 +20,8 @@ const ERR_B2AGG_TARGET_ACCOUNT_MISMATCH="B2AGG note attachment target account do #! #! This note can be consumed in two ways: #! - If the consuming account is the sender (reclaim): the note's assets are added back to the consuming account. -#! - If the consuming account is the Agglayer Bridge: the note's assets are moved to a BURN note, +#! - If the consuming account is the Agglayer Bridge: the note's assets are moved to a BURN note, #! and the note details are hashed into a leaf and appended to the Local Exit Tree. -#! global exit root (GER) merkle tree structure. #! #! Inputs: [] #! Outputs: [] From 2217b38bd42c8fb94c0239caa81e451c386a7f0b Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 28 Jan 2026 10:36:54 +0000 Subject: [PATCH 12/35] docs(masm): clarify B2AGG attachment layout Co-authored-by: marti --- crates/miden-agglayer/asm/note_scripts/B2AGG.masm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm index 1d982928f6..bb9e4a254c 100644 --- a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm +++ b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm @@ -35,7 +35,7 @@ const ERR_B2AGG_TARGET_ACCOUNT_MISMATCH="B2AGG note attachment target account do #! - destination_address_3: bytes 12-15 #! - destination_address_4: bytes 16-19 #! Note attachment is constructed from a NetworkAccountTarget standard: -#! - [0, 0, target_id_prefix, target_id_suffix] +#! - [0, exec_hint_tag, target_id_prefix, target_id_suffix] #! #! Panics if: #! - The note does not contain exactly 6 storage items. From 4c742ec7877facd0f3d6543932e4cfa905ccdfec Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 28 Jan 2026 10:38:45 +0000 Subject: [PATCH 13/35] feat: use network account target helper Co-authored-by: marti --- crates/miden-agglayer/asm/note_scripts/B2AGG.masm | 14 ++++++++------ .../asm/note_scripts/UPDATE_GER.masm | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm index bb9e4a254c..91938f7e12 100644 --- a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm +++ b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm @@ -2,6 +2,8 @@ use miden::agglayer::bridge_out use miden::protocol::account_id use miden::protocol::active_account use miden::protocol::active_note +use miden::protocol::note +use miden::standards::attachments::network_account_target use miden::standards::wallets::basic->basic_wallet # CONSTANTS @@ -65,14 +67,14 @@ begin exec.active_note::get_metadata # => [NOTE_ATTACHMENT, METADATA_HEADER, pad(8)] - # TODO simplify once https://github.com/0xMiden/miden-base/pull/2338 lands + exec.note::extract_attachment_info_from_metadata + # => [attachment_kind, attachment_scheme, NOTE_ATTACHMENT, pad(8)] - swapw dropw - # => [NOTE_ATTACHMENT, pad(12)] + swap + # => [attachment_scheme, attachment_kind, NOTE_ATTACHMENT, pad(8)] - # Reorder attachment word to [target_id_prefix, target_id_suffix]. - drop drop - # => [target_id_prefix, target_id_suffix, pad(14)] (auto-padding) + exec.network_account_target::get_id + # => [target_id_prefix, target_id_suffix, pad(14)] exec.active_account::get_id # => [account_id_prefix, account_id_suffix, target_id_prefix, target_id_suffix, pad(14)] diff --git a/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm b/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm index 22a5b276b2..98f9bc75be 100644 --- a/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm +++ b/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm @@ -2,6 +2,8 @@ use miden::agglayer::bridge_in use miden::protocol::active_note use miden::protocol::active_account use miden::protocol::account_id +use miden::protocol::note +use miden::standards::attachments::network_account_target # CONSTANTS # ================================================================================================= @@ -40,14 +42,14 @@ begin exec.active_note::get_metadata # => [NOTE_ATTACHMENT, METADATA_HEADER, pad(8)] - # TODO simplify once https://github.com/0xMiden/miden-base/pull/2338 lands + exec.note::extract_attachment_info_from_metadata + # => [attachment_kind, attachment_scheme, NOTE_ATTACHMENT, pad(8)] - swapw dropw - # => [NOTE_ATTACHMENT, pad(12)] + swap + # => [attachment_scheme, attachment_kind, NOTE_ATTACHMENT, pad(8)] - # Reorder attachment word to [target_id_prefix, target_id_suffix]. - drop drop - # => [target_id_prefix, target_id_suffix, pad(14)] (auto-padding) + exec.network_account_target::get_id + # => [target_id_prefix, target_id_suffix, pad(14)] exec.active_account::get_id # => [account_id_prefix, account_id_suffix, target_id_prefix, target_id_suffix, pad(14)] From bbecf8cb0937bec3ef73827f11ef575cb8d57481 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 28 Jan 2026 10:49:04 +0000 Subject: [PATCH 14/35] feat: make B2AGG notes always public Co-authored-by: marti --- crates/miden-agglayer/src/bridge_out.rs | 7 +++---- crates/miden-testing/tests/agglayer/bridge_out.rs | 3 --- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/crates/miden-agglayer/src/bridge_out.rs b/crates/miden-agglayer/src/bridge_out.rs index 783038feb7..7b01645b79 100644 --- a/crates/miden-agglayer/src/bridge_out.rs +++ b/crates/miden-agglayer/src/bridge_out.rs @@ -79,14 +79,13 @@ impl TryFrom for NoteStorage { /// /// This note is used to bridge assets from Miden to another network via the AggLayer. /// When consumed by a bridge account, the assets are burned and a corresponding -/// claim can be made on the destination network. +/// claim can be made on the destination network. B2AGG notes are always public. /// /// # Parameters /// - `storage`: The destination network and address information /// - `assets`: The assets to bridge (must be fungible assets from a network faucet) /// - `target_account_id`: The account ID that will consume this note (bridge account) /// - `sender_account_id`: The account ID of the note creator -/// - `note_type`: The type of note (Public or Private) /// - `rng`: Random number generator for creating the note serial number /// /// # Errors @@ -96,7 +95,6 @@ pub fn create_b2agg_note( assets: NoteAssets, target_account_id: AccountId, sender_account_id: AccountId, - note_type: NoteType, rng: &mut R, ) -> Result { let note_storage = NoteStorage::try_from(storage)?; @@ -108,7 +106,8 @@ pub fn create_b2agg_note( .map_err(|e| NoteError::other(e.to_string()))?, ); - let metadata = NoteMetadata::new(sender_account_id, note_type, tag).with_attachment(attachment); + let metadata = + NoteMetadata::new(sender_account_id, NoteType::Public, tag).with_attachment(attachment); let b2agg_script = b2agg_script(); let recipient = NoteRecipient::new( diff --git a/crates/miden-testing/tests/agglayer/bridge_out.rs b/crates/miden-testing/tests/agglayer/bridge_out.rs index 74374e982a..bf8ecf5624 100644 --- a/crates/miden-testing/tests/agglayer/bridge_out.rs +++ b/crates/miden-testing/tests/agglayer/bridge_out.rs @@ -66,7 +66,6 @@ async fn test_bridge_out_consumes_b2agg_note() -> anyhow::Result<()> { assets, bridge_account.id(), faucet.id(), - NoteType::Public, builder.rng_mut(), )?; @@ -220,7 +219,6 @@ async fn test_b2agg_note_reclaim_scenario() -> anyhow::Result<()> { assets, bridge_account.id(), user_account.id(), - NoteType::Public, builder.rng_mut(), )?; @@ -328,7 +326,6 @@ async fn test_b2agg_note_non_target_account_cannot_consume() -> anyhow::Result<( assets, bridge_account.id(), // target sender_account.id(), // sender - NoteType::Public, builder.rng_mut(), )?; From 0e20ba8624930a335c8a0ccb03443987e9312dce Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 28 Jan 2026 10:49:52 +0000 Subject: [PATCH 15/35] feat: mark B2AGG notes always consumable Co-authored-by: marti --- crates/miden-agglayer/src/bridge_out.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/miden-agglayer/src/bridge_out.rs b/crates/miden-agglayer/src/bridge_out.rs index 7b01645b79..62899a158c 100644 --- a/crates/miden-agglayer/src/bridge_out.rs +++ b/crates/miden-agglayer/src/bridge_out.rs @@ -102,7 +102,7 @@ pub fn create_b2agg_note( let tag = NoteTag::new(0); let attachment = NoteAttachment::from( - NetworkAccountTarget::new(target_account_id, NoteExecutionHint::None) + NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always) .map_err(|e| NoteError::other(e.to_string()))?, ); From b2628618493486e4bfc93e856ff59e4451bd6446 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 28 Jan 2026 10:50:43 +0000 Subject: [PATCH 16/35] style: use NoteScript import for B2AGG Co-authored-by: marti --- crates/miden-agglayer/src/bridge_out.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/miden-agglayer/src/bridge_out.rs b/crates/miden-agglayer/src/bridge_out.rs index 62899a158c..a1194b2f6d 100644 --- a/crates/miden-agglayer/src/bridge_out.rs +++ b/crates/miden-agglayer/src/bridge_out.rs @@ -17,6 +17,7 @@ use miden_protocol::note::{ NoteExecutionHint, NoteMetadata, NoteRecipient, + NoteScript, NoteStorage, NoteTag, NoteType, @@ -112,7 +113,7 @@ pub fn create_b2agg_note( let b2agg_script = b2agg_script(); let recipient = NoteRecipient::new( rng.draw_word(), - miden_protocol::note::NoteScript::new(b2agg_script), + NoteScript::new(b2agg_script), note_storage, ); From 851eceaa14d0c2ab33c1d23469c5b7653fdfa5cc Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 28 Jan 2026 10:52:15 +0000 Subject: [PATCH 17/35] docs: add changelog entry for PR 2334 Co-authored-by: marti --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97fe2dd6cc..0ba41b5c7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - 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)). +- Added B2AGG and UPDATE_GER note attachment target checks ([#2334](https://github.com/0xMiden/miden-base/pull/2334)). ### Changes From 3750112d2b6eba34c3a143315623914ed9dfa3db Mon Sep 17 00:00:00 2001 From: Marti Date: Wed, 28 Jan 2026 14:33:19 +0100 Subject: [PATCH 18/35] Apply suggestions from code review --- crates/miden-agglayer/src/update_ger_note.rs | 2 +- crates/miden-testing/tests/agglayer/bridge_out.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/miden-agglayer/src/update_ger_note.rs b/crates/miden-agglayer/src/update_ger_note.rs index 00761f8756..d6c780750d 100644 --- a/crates/miden-agglayer/src/update_ger_note.rs +++ b/crates/miden-agglayer/src/update_ger_note.rs @@ -43,7 +43,7 @@ pub fn create_update_ger_note( let recipient = NoteRecipient::new(serial_num, update_ger_script, note_storage); let attachment = NoteAttachment::from( - NetworkAccountTarget::new(target_account_id, NoteExecutionHint::None) + NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always) .map_err(|e| NoteError::other(e.to_string()))?, ); let note_tag = NoteTag::new(0); diff --git a/crates/miden-testing/tests/agglayer/bridge_out.rs b/crates/miden-testing/tests/agglayer/bridge_out.rs index bf8ecf5624..1b3d8b388f 100644 --- a/crates/miden-testing/tests/agglayer/bridge_out.rs +++ b/crates/miden-testing/tests/agglayer/bridge_out.rs @@ -324,8 +324,8 @@ async fn test_b2agg_note_non_target_account_cannot_consume() -> anyhow::Result<( let b2agg_note = create_b2agg_note( storage, assets, - bridge_account.id(), // target - sender_account.id(), // sender + bridge_account.id(), + sender_account.id(), builder.rng_mut(), )?; From 8857e672db244b4dae27d2e7492e0c12c9f95498 Mon Sep 17 00:00:00 2001 From: Marti Date: Wed, 28 Jan 2026 13:39:53 +0000 Subject: [PATCH 19/35] chore: move helper to network_account_target --- .../asm/note_scripts/B2AGG.masm | 17 +-------- .../asm/note_scripts/UPDATE_GER.masm | 19 ++-------- .../attachments/network_account_target.masm | 36 +++++++++++++++++++ 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm index 91938f7e12..f5d3432462 100644 --- a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm +++ b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm @@ -64,22 +64,7 @@ begin # => [pad(16)] else # Ensure note attachment targets the consuming bridge account. - exec.active_note::get_metadata - # => [NOTE_ATTACHMENT, METADATA_HEADER, pad(8)] - - exec.note::extract_attachment_info_from_metadata - # => [attachment_kind, attachment_scheme, NOTE_ATTACHMENT, pad(8)] - - swap - # => [attachment_scheme, attachment_kind, NOTE_ATTACHMENT, pad(8)] - - exec.network_account_target::get_id - # => [target_id_prefix, target_id_suffix, pad(14)] - - exec.active_account::get_id - # => [account_id_prefix, account_id_suffix, target_id_prefix, target_id_suffix, pad(14)] - - exec.account_id::is_equal + exec.network_account_target::active_account_matches_target_account assert.err=ERR_B2AGG_TARGET_ACCOUNT_MISMATCH # => [pad(16)] diff --git a/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm b/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm index 98f9bc75be..da8cece032 100644 --- a/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm +++ b/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm @@ -39,22 +39,7 @@ begin # => [pad(16)] # Ensure note attachment targets the consuming bridge account. - exec.active_note::get_metadata - # => [NOTE_ATTACHMENT, METADATA_HEADER, pad(8)] - - exec.note::extract_attachment_info_from_metadata - # => [attachment_kind, attachment_scheme, NOTE_ATTACHMENT, pad(8)] - - swap - # => [attachment_scheme, attachment_kind, NOTE_ATTACHMENT, pad(8)] - - exec.network_account_target::get_id - # => [target_id_prefix, target_id_suffix, pad(14)] - - exec.active_account::get_id - # => [account_id_prefix, account_id_suffix, target_id_prefix, target_id_suffix, pad(14)] - - exec.account_id::is_equal + exec.network_account_target::active_account_matches_target_account assert.err=ERR_UPDATE_GER_TARGET_ACCOUNT_MISMATCH # => [pad(16)] @@ -74,4 +59,4 @@ begin call.bridge_in::update_ger # => [] -end \ No newline at end of file +end diff --git a/crates/miden-standards/asm/standards/attachments/network_account_target.masm b/crates/miden-standards/asm/standards/attachments/network_account_target.masm index 9c097162bc..8497363867 100644 --- a/crates/miden-standards/asm/standards/attachments/network_account_target.masm +++ b/crates/miden-standards/asm/standards/attachments/network_account_target.masm @@ -2,6 +2,8 @@ #! #! Provides a standardized way to work with network account targets. +use miden::protocol::account_id +use miden::protocol::active_account use miden::protocol::active_note use miden::protocol::note @@ -70,3 +72,37 @@ pub proc new push.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME # => [attachment_scheme, attachment_kind, ATTACHMENT] end + +#! Returns a boolean indicating whether the active account matches the target account +#! encoded in the note attachment. +#! +#! Inputs: [] +#! Outputs: [is_equal] +#! +#! Where: +#! - is_equal is a boolean indicating whether the active account matches the target account. +#! +#! Invocation: exec +pub proc active_account_matches_target_account + # Ensure note attachment targets the consuming bridge account. + exec.active_note::get_metadata + # => [NOTE_ATTACHMENT, METADATA_HEADER] + + swapw + # => [METADATA_HEADER, NOTE_ATTACHMENT] + + exec.note::extract_attachment_info_from_metadata + # => [attachment_kind, attachment_scheme, NOTE_ATTACHMENT] + + swap + # => [attachment_scheme, attachment_kind, NOTE_ATTACHMENT] + + exec.get_id + # => [target_id_prefix, target_id_suffix] + + exec.active_account::get_id + # => [account_id_prefix, account_id_suffix, target_id_prefix, target_id_suffix] + + exec.account_id::is_equal + # => [is_equal] +end From 3b2a537133f6075ce5e38738eb13a3bed83154a2 Mon Sep 17 00:00:00 2001 From: Marti Date: Wed, 28 Jan 2026 13:43:34 +0000 Subject: [PATCH 20/35] chore: note script section headers --- crates/miden-agglayer/asm/note_scripts/B2AGG.masm | 2 ++ crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm | 3 +++ 2 files changed, 5 insertions(+) diff --git a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm index f5d3432462..9523160e9c 100644 --- a/crates/miden-agglayer/asm/note_scripts/B2AGG.masm +++ b/crates/miden-agglayer/asm/note_scripts/B2AGG.masm @@ -17,6 +17,8 @@ const ERR_B2AGG_WRONG_NUMBER_OF_ASSETS="B2AGG script requires exactly 1 note ass const ERR_B2AGG_UNEXPECTED_NUMBER_OF_STORAGE_ITEMS="B2AGG script expects exactly 6 note storage items" const ERR_B2AGG_TARGET_ACCOUNT_MISMATCH="B2AGG note attachment target account does not match consuming account" +# NOTE SCRIPT +# ================================================================================================= #! Bridge-to-AggLayer (B2AGG) note script: bridges assets from Miden to an AggLayer-connected chain. #! diff --git a/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm b/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm index da8cece032..e8699d821e 100644 --- a/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm +++ b/crates/miden-agglayer/asm/note_scripts/UPDATE_GER.masm @@ -16,6 +16,9 @@ const STORAGE_PTR_GER_UPPER = 4 const ERR_UPDATE_GER_UNEXPECTED_NUMBER_OF_STORAGE_ITEMS = "UPDATE_GER script expects exactly 8 note storage items" const ERR_UPDATE_GER_TARGET_ACCOUNT_MISMATCH = "UPDATE_GER note attachment target account does not match consuming account" +# NOTE SCRIPT +# ================================================================================================= + #! Agglayer Bridge UPDATE_GER script: updates the GER by calling the bridge_in::update_ger function. #! #! This note can only be consumed by the specific agglayer bridge account whose ID is provided From 6f90bd9de145af2bc3239ffbd685037bbde48169 Mon Sep 17 00:00:00 2001 From: Marti Date: Wed, 28 Jan 2026 13:43:46 +0000 Subject: [PATCH 21/35] chore: comment simplify and wrap --- crates/miden-agglayer/src/bridge_out.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/miden-agglayer/src/bridge_out.rs b/crates/miden-agglayer/src/bridge_out.rs index a1194b2f6d..c63ee06ee0 100644 --- a/crates/miden-agglayer/src/bridge_out.rs +++ b/crates/miden-agglayer/src/bridge_out.rs @@ -31,8 +31,7 @@ use crate::{EthAddressFormat, b2agg_script}; /// Storage data for B2AGG note creation. /// -/// Contains the destination network and address information required -/// for bridging assets to the AggLayer network. +/// Contains the destination network and address, required for bridging assets to AggLayer. #[derive(Debug, Clone)] pub struct B2AggNoteStorage { /// Destination network identifier (AggLayer-assigned network ID) From 9ece869ffcfb7944e070ba4016fe208a1ee702b1 Mon Sep 17 00:00:00 2001 From: Marti Date: Wed, 28 Jan 2026 14:39:44 +0000 Subject: [PATCH 22/35] lint --- crates/miden-agglayer/src/bridge_out.rs | 7 ++----- crates/miden-testing/tests/agglayer/bridge_out.rs | 9 ++------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/crates/miden-agglayer/src/bridge_out.rs b/crates/miden-agglayer/src/bridge_out.rs index c63ee06ee0..ed3da5171c 100644 --- a/crates/miden-agglayer/src/bridge_out.rs +++ b/crates/miden-agglayer/src/bridge_out.rs @@ -110,11 +110,8 @@ pub fn create_b2agg_note( NoteMetadata::new(sender_account_id, NoteType::Public, tag).with_attachment(attachment); let b2agg_script = b2agg_script(); - let recipient = NoteRecipient::new( - rng.draw_word(), - NoteScript::new(b2agg_script), - note_storage, - ); + let recipient = + NoteRecipient::new(rng.draw_word(), NoteScript::new(b2agg_script), note_storage); Ok(Note::new(assets, metadata, recipient)) } diff --git a/crates/miden-testing/tests/agglayer/bridge_out.rs b/crates/miden-testing/tests/agglayer/bridge_out.rs index 1b3d8b388f..655ab588f1 100644 --- a/crates/miden-testing/tests/agglayer/bridge_out.rs +++ b/crates/miden-testing/tests/agglayer/bridge_out.rs @@ -61,13 +61,8 @@ async fn test_bridge_out_consumes_b2agg_note() -> anyhow::Result<()> { let assets = NoteAssets::new(vec![bridge_asset])?; // Create the B2AGG note using the helper - let b2agg_note = create_b2agg_note( - storage, - assets, - bridge_account.id(), - faucet.id(), - builder.rng_mut(), - )?; + let b2agg_note = + create_b2agg_note(storage, assets, bridge_account.id(), faucet.id(), builder.rng_mut())?; // Add the B2AGG note to the mock chain builder.add_output_note(OutputNote::Full(b2agg_note.clone())); From 02826728fc826092672b673c264161d8fc031ff0 Mon Sep 17 00:00:00 2001 From: Marti Date: Wed, 28 Jan 2026 17:15:00 +0100 Subject: [PATCH 23/35] fix: use `with_account_target` instead of `0` for `NoteTag` Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- crates/miden-agglayer/src/bridge_out.rs | 2 +- crates/miden-agglayer/src/update_ger_note.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/miden-agglayer/src/bridge_out.rs b/crates/miden-agglayer/src/bridge_out.rs index ed3da5171c..0844b9fb32 100644 --- a/crates/miden-agglayer/src/bridge_out.rs +++ b/crates/miden-agglayer/src/bridge_out.rs @@ -99,7 +99,7 @@ pub fn create_b2agg_note( ) -> Result { let note_storage = NoteStorage::try_from(storage)?; - let tag = NoteTag::new(0); + let tag = NoteTag::with_account_target(target_account_id); let attachment = NoteAttachment::from( NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always) diff --git a/crates/miden-agglayer/src/update_ger_note.rs b/crates/miden-agglayer/src/update_ger_note.rs index d6c780750d..2129486cd2 100644 --- a/crates/miden-agglayer/src/update_ger_note.rs +++ b/crates/miden-agglayer/src/update_ger_note.rs @@ -46,7 +46,7 @@ pub fn create_update_ger_note( NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always) .map_err(|e| NoteError::other(e.to_string()))?, ); - let note_tag = NoteTag::new(0); + let note_tag = NoteTag::with_account_target(target_account_id); let metadata = NoteMetadata::new(sender_account_id, NoteType::Public, note_tag) .with_attachment(attachment); From ec8f116ab7aaae1d9134968410c440623b50944b Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 21:20:27 +0000 Subject: [PATCH 24/35] chore: add missing panic to get_id --- .../asm/standards/attachments/network_account_target.masm | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/miden-standards/asm/standards/attachments/network_account_target.masm b/crates/miden-standards/asm/standards/attachments/network_account_target.masm index 8497363867..d41c08d3b7 100644 --- a/crates/miden-standards/asm/standards/attachments/network_account_target.masm +++ b/crates/miden-standards/asm/standards/attachments/network_account_target.masm @@ -39,6 +39,7 @@ const ERR_ATTACHMENT_KIND_MISMATCH = "expected attachment kind to be Word for ne #! #! Panics if: #! - the attachment scheme does not match NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME. +#! - the attachment kind does not match NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND. #! #! Invocation: exec pub proc get_id From 3c6e32feef93a874e8bece403d3cf572be19310d Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 21:20:52 +0000 Subject: [PATCH 25/35] chore: mention active note --- .../asm/standards/attachments/network_account_target.masm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/miden-standards/asm/standards/attachments/network_account_target.masm b/crates/miden-standards/asm/standards/attachments/network_account_target.masm index d41c08d3b7..90dc4c0ebe 100644 --- a/crates/miden-standards/asm/standards/attachments/network_account_target.masm +++ b/crates/miden-standards/asm/standards/attachments/network_account_target.masm @@ -75,7 +75,7 @@ pub proc new end #! Returns a boolean indicating whether the active account matches the target account -#! encoded in the note attachment. +#! encoded in the active note's attachment. #! #! Inputs: [] #! Outputs: [is_equal] From 185cb510a18c5ee5f645b26540f576b4fa9a0cfe Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 21:21:17 +0000 Subject: [PATCH 26/35] docs: how active_account_matches_target_account panics --- .../asm/standards/attachments/network_account_target.masm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/miden-standards/asm/standards/attachments/network_account_target.masm b/crates/miden-standards/asm/standards/attachments/network_account_target.masm index 90dc4c0ebe..9a7df22bc7 100644 --- a/crates/miden-standards/asm/standards/attachments/network_account_target.masm +++ b/crates/miden-standards/asm/standards/attachments/network_account_target.masm @@ -83,6 +83,10 @@ end #! Where: #! - is_equal is a boolean indicating whether the active account matches the target account. #! +#! Panics if: +#! - the attachment scheme does not match NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME. +#! - the attachment kind does not match NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND. +#! #! Invocation: exec pub proc active_account_matches_target_account # Ensure note attachment targets the consuming bridge account. From a7a38098a8a169f6f39ce4e8da1ae0350cf792aa Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 21:21:33 +0000 Subject: [PATCH 27/35] Revert "fix: use `with_account_target` instead of `0` for `NoteTag`" This reverts commit 02826728fc826092672b673c264161d8fc031ff0. --- crates/miden-agglayer/src/bridge_out.rs | 2 +- crates/miden-agglayer/src/update_ger_note.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/miden-agglayer/src/bridge_out.rs b/crates/miden-agglayer/src/bridge_out.rs index 0844b9fb32..ed3da5171c 100644 --- a/crates/miden-agglayer/src/bridge_out.rs +++ b/crates/miden-agglayer/src/bridge_out.rs @@ -99,7 +99,7 @@ pub fn create_b2agg_note( ) -> Result { let note_storage = NoteStorage::try_from(storage)?; - let tag = NoteTag::with_account_target(target_account_id); + let tag = NoteTag::new(0); let attachment = NoteAttachment::from( NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always) diff --git a/crates/miden-agglayer/src/update_ger_note.rs b/crates/miden-agglayer/src/update_ger_note.rs index 2129486cd2..d6c780750d 100644 --- a/crates/miden-agglayer/src/update_ger_note.rs +++ b/crates/miden-agglayer/src/update_ger_note.rs @@ -46,7 +46,7 @@ pub fn create_update_ger_note( NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always) .map_err(|e| NoteError::other(e.to_string()))?, ); - let note_tag = NoteTag::with_account_target(target_account_id); + let note_tag = NoteTag::new(0); let metadata = NoteMetadata::new(sender_account_id, NoteType::Public, note_tag) .with_attachment(attachment); From 495dc2b968bbebada1b16490a2484886ffc4e239 Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 22:02:49 +0000 Subject: [PATCH 28/35] feat: extract assert_is_network_account_target helper --- .../attachments/network_account_target.masm | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/crates/miden-standards/asm/standards/attachments/network_account_target.masm b/crates/miden-standards/asm/standards/attachments/network_account_target.masm index 9a7df22bc7..aeebb13d5b 100644 --- a/crates/miden-standards/asm/standards/attachments/network_account_target.masm +++ b/crates/miden-standards/asm/standards/attachments/network_account_target.masm @@ -23,6 +23,25 @@ pub const NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND = 1 const ERR_ATTACHMENT_SCHEME_MISMATCH = "expected network account target attachment scheme" const ERR_ATTACHMENT_KIND_MISMATCH = "expected attachment kind to be Word for network account target" +#! Asserts that the attachment scheme and kind match the expected values for a +#! NetworkAccountTarget attachment. +#! +#! Inputs: [attachment_scheme, attachment_kind] +#! Outputs: [] +#! +#! Panics if: +#! - the attachment scheme does not match NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME. +#! - the attachment kind does not match NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND. +#! +#! Invocation: exec +pub proc assert_is_network_account_target + eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME assert.err=ERR_ATTACHMENT_SCHEME_MISMATCH + # => [attachment_kind] + + eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND assert.err=ERR_ATTACHMENT_KIND_MISMATCH + # => [] +end + #! Returns the account ID encoded in the attachment. #! #! The attachment is expected to have the following layout: @@ -38,15 +57,13 @@ const ERR_ATTACHMENT_KIND_MISMATCH = "expected attachment kind to be Word for ne #! - account_id_{prefix,suffix} are the prefix and suffix felts of an account ID. #! #! Panics if: -#! - the attachment scheme does not match NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME. -#! - the attachment kind does not match NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND. +#! - the attachment scheme or kind are not compatible with a network account target. #! #! Invocation: exec pub proc get_id # verify that the attachment scheme and kind are correct - # => [attachment_scheme, attachment_kind, NOTE_ATTACHMENT] - eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME assert.err=ERR_ATTACHMENT_SCHEME_MISMATCH - eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND assert.err=ERR_ATTACHMENT_KIND_MISMATCH + exec.assert_is_network_account_target + # => [NOTE_ATTACHMENT] = [0, exec_hint_tag, account_id_prefix, account_id_suffix] drop drop @@ -84,12 +101,11 @@ end #! - is_equal is a boolean indicating whether the active account matches the target account. #! #! Panics if: -#! - the attachment scheme does not match NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME. -#! - the attachment kind does not match NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND. +#! - the attachment scheme or kind are not compatible with a network account target. #! #! Invocation: exec pub proc active_account_matches_target_account - # Ensure note attachment targets the consuming bridge account. + # ensure note attachment targets the consuming bridge account exec.active_note::get_metadata # => [NOTE_ATTACHMENT, METADATA_HEADER] @@ -102,6 +118,9 @@ pub proc active_account_matches_target_account swap # => [attachment_scheme, attachment_kind, NOTE_ATTACHMENT] + # ensure the attachment is a network account target + exec.assert_is_network_account_target + exec.get_id # => [target_id_prefix, target_id_suffix] From f8e4fd23a6bd788b307b9202150c79a768d8cac0 Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 22:12:02 +0000 Subject: [PATCH 29/35] feat: change is_network_account_target to return bool, not panic --- .../attachments/network_account_target.masm | 45 +++++++++---------- .../src/standards/network_account_target.rs | 16 +++++++ 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/crates/miden-standards/asm/standards/attachments/network_account_target.masm b/crates/miden-standards/asm/standards/attachments/network_account_target.masm index aeebb13d5b..46133f4136 100644 --- a/crates/miden-standards/asm/standards/attachments/network_account_target.masm +++ b/crates/miden-standards/asm/standards/attachments/network_account_target.masm @@ -20,26 +20,24 @@ pub const NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND = 1 # ERRORS # ================================================================================================ -const ERR_ATTACHMENT_SCHEME_MISMATCH = "expected network account target attachment scheme" -const ERR_ATTACHMENT_KIND_MISMATCH = "expected attachment kind to be Word for network account target" +const ERR_NOT_NETWORK_ACCOUNT_TARGET = "attachment is not a valid network account target" -#! Asserts that the attachment scheme and kind match the expected values for a -#! NetworkAccountTarget attachment. +#! Returns a boolean indicating whether the attachment scheme and kind match the expected +#! values for a NetworkAccountTarget attachment. #! #! Inputs: [attachment_scheme, attachment_kind] -#! Outputs: [] -#! -#! Panics if: -#! - the attachment scheme does not match NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME. -#! - the attachment kind does not match NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND. +#! Outputs: [is_network_account_target] #! #! Invocation: exec -pub proc assert_is_network_account_target - eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME assert.err=ERR_ATTACHMENT_SCHEME_MISMATCH - # => [attachment_kind] +pub proc is_network_account_target + eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME + # => [is_scheme_valid, attachment_kind] + + swap eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND + # => [is_kind_valid, is_scheme_valid] - eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND assert.err=ERR_ATTACHMENT_KIND_MISMATCH - # => [] + and + # => [is_network_account_target] end #! Returns the account ID encoded in the attachment. @@ -47,23 +45,20 @@ end #! The attachment is expected to have the following layout: #! [0, exec_hint_tag, account_id_prefix, account_id_suffix] #! +#! WARNING: This procedure does not validate the attachment scheme or kind. The caller +#! should validate these using `is_network_account_target` before calling this procedure. +#! #! WARNING: This procedure does not validate that the returned account ID is well-formed. #! The caller should validate the account ID if needed using `account_id::validate`. #! -#! Inputs: [attachment_scheme, attachment_kind, NOTE_ATTACHMENT] +#! Inputs: [NOTE_ATTACHMENT] #! Outputs: [account_id_prefix, account_id_suffix] #! #! Where: #! - account_id_{prefix,suffix} are the prefix and suffix felts of an account ID. #! -#! Panics if: -#! - the attachment scheme or kind are not compatible with a network account target. -#! #! Invocation: exec pub proc get_id - # verify that the attachment scheme and kind are correct - exec.assert_is_network_account_target - # => [NOTE_ATTACHMENT] = [0, exec_hint_tag, account_id_prefix, account_id_suffix] drop drop @@ -101,7 +96,7 @@ end #! - is_equal is a boolean indicating whether the active account matches the target account. #! #! Panics if: -#! - the attachment scheme or kind are not compatible with a network account target. +#! - the attachment is not a valid network account target. #! #! Invocation: exec pub proc active_account_matches_target_account @@ -119,10 +114,12 @@ pub proc active_account_matches_target_account # => [attachment_scheme, attachment_kind, NOTE_ATTACHMENT] # ensure the attachment is a network account target - exec.assert_is_network_account_target + exec.is_network_account_target assert.err=ERR_NOT_NETWORK_ACCOUNT_TARGET + + # => [NOTE_ATTACHMENT] = [0, exec_hint_tag, account_id_prefix, account_id_suffix] exec.get_id - # => [target_id_prefix, target_id_suffix] + # => [account_id_prefix, account_id_suffix] exec.active_account::get_id # => [account_id_prefix, account_id_suffix, target_id_prefix, target_id_suffix] diff --git a/crates/miden-testing/src/standards/network_account_target.rs b/crates/miden-testing/src/standards/network_account_target.rs index 9908377592..40b65b6f0f 100644 --- a/crates/miden-testing/src/standards/network_account_target.rs +++ b/crates/miden-testing/src/standards/network_account_target.rs @@ -26,12 +26,21 @@ async fn network_account_target_get_id() -> anyhow::Result<()> { use miden::standards::attachments::network_account_target use miden::protocol::note + const ERR_NOT_NETWORK_ACCOUNT_TARGET = "attachment is not a valid network account target" + begin push.{attachment_word} push.{metadata_header} exec.note::extract_attachment_info_from_metadata # => [attachment_kind, attachment_scheme, NOTE_ATTACHMENT] + swap + # => [attachment_scheme, attachment_kind, NOTE_ATTACHMENT] + exec.network_account_target::is_network_account_target + # => [is_valid, NOTE_ATTACHMENT] + assert.err=ERR_NOT_NETWORK_ACCOUNT_TARGET + # => [NOTE_ATTACHMENT] exec.network_account_target::get_id + # => [account_id_prefix, account_id_suffix] # cleanup stack movup.2 drop movup.2 drop end @@ -104,6 +113,8 @@ async fn network_account_target_attachment_round_trip() -> anyhow::Result<()> { r#" use miden::standards::attachments::network_account_target + const ERR_NOT_NETWORK_ACCOUNT_TARGET = "attachment is not a valid network account target" + begin push.{exec_hint} push.{target_id_suffix} @@ -111,8 +122,13 @@ async fn network_account_target_attachment_round_trip() -> anyhow::Result<()> { # => [target_id_prefix, target_id_suffix, exec_hint] exec.network_account_target::new # => [attachment_scheme, attachment_kind, ATTACHMENT] + exec.network_account_target::is_network_account_target + # => [is_valid, ATTACHMENT] + assert.err=ERR_NOT_NETWORK_ACCOUNT_TARGET + # => [ATTACHMENT] exec.network_account_target::get_id # => [target_id_prefix, target_id_suffix] + # cleanup stack movup.2 drop movup.2 drop end "#, From aad47e5d6b5d5f32c0e9da451a667aec57912e61 Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 22:35:39 +0000 Subject: [PATCH 30/35] feat: swap kind/scheme in signatures --- .../attachments/network_account_target.masm | 19 ++++++++----------- .../src/standards/network_account_target.rs | 4 +--- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/crates/miden-standards/asm/standards/attachments/network_account_target.masm b/crates/miden-standards/asm/standards/attachments/network_account_target.masm index 46133f4136..08cc380d74 100644 --- a/crates/miden-standards/asm/standards/attachments/network_account_target.masm +++ b/crates/miden-standards/asm/standards/attachments/network_account_target.masm @@ -25,16 +25,16 @@ const ERR_NOT_NETWORK_ACCOUNT_TARGET = "attachment is not a valid network accoun #! Returns a boolean indicating whether the attachment scheme and kind match the expected #! values for a NetworkAccountTarget attachment. #! -#! Inputs: [attachment_scheme, attachment_kind] +#! Inputs: [attachment_kind, attachment_scheme] #! Outputs: [is_network_account_target] #! #! Invocation: exec pub proc is_network_account_target - eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME - # => [is_scheme_valid, attachment_kind] + eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND + # => [is_kind_valid, attachment_scheme] - swap eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND - # => [is_kind_valid, is_scheme_valid] + swap eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME + # => [is_scheme_valid, is_kind_valid] and # => [is_network_account_target] @@ -69,7 +69,7 @@ end #! [0, exec_hint_tag, account_id_prefix, account_id_suffix] #! #! Inputs: [account_id_prefix, account_id_suffix, exec_hint] -#! Outputs: [attachment_scheme, attachment_kind, NOTE_ATTACHMENT] +#! Outputs: [attachment_kind, attachment_scheme, NOTE_ATTACHMENT] #! #! Where: #! - account_id_{prefix,suffix} are the prefix and suffix felts of an account ID. @@ -81,9 +81,9 @@ end pub proc new movup.2 push.0 - push.NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND push.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME - # => [attachment_scheme, attachment_kind, ATTACHMENT] + push.NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND + # => [attachment_kind, attachment_scheme, ATTACHMENT] end #! Returns a boolean indicating whether the active account matches the target account @@ -110,9 +110,6 @@ pub proc active_account_matches_target_account exec.note::extract_attachment_info_from_metadata # => [attachment_kind, attachment_scheme, NOTE_ATTACHMENT] - swap - # => [attachment_scheme, attachment_kind, NOTE_ATTACHMENT] - # ensure the attachment is a network account target exec.is_network_account_target assert.err=ERR_NOT_NETWORK_ACCOUNT_TARGET diff --git a/crates/miden-testing/src/standards/network_account_target.rs b/crates/miden-testing/src/standards/network_account_target.rs index 40b65b6f0f..7ff5d8293a 100644 --- a/crates/miden-testing/src/standards/network_account_target.rs +++ b/crates/miden-testing/src/standards/network_account_target.rs @@ -33,8 +33,6 @@ async fn network_account_target_get_id() -> anyhow::Result<()> { push.{metadata_header} exec.note::extract_attachment_info_from_metadata # => [attachment_kind, attachment_scheme, NOTE_ATTACHMENT] - swap - # => [attachment_scheme, attachment_kind, NOTE_ATTACHMENT] exec.network_account_target::is_network_account_target # => [is_valid, NOTE_ATTACHMENT] assert.err=ERR_NOT_NETWORK_ACCOUNT_TARGET @@ -78,7 +76,7 @@ async fn network_account_target_new_attachment() -> anyhow::Result<()> { push.{target_id_prefix} # => [target_id_prefix, target_id_suffix, exec_hint] exec.network_account_target::new - # => [attachment_scheme, attachment_kind, ATTACHMENT, pad(16)] + # => [attachment_kind, attachment_scheme, ATTACHMENT, pad(16)] # cleanup stack swapdw dropw dropw From 30d1fd05e44977fdb0aeaf712bd7885d2a4ed5a4 Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 22:43:00 +0000 Subject: [PATCH 31/35] lint: regen errors --- crates/miden-standards/src/errors/standards.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/miden-standards/src/errors/standards.rs b/crates/miden-standards/src/errors/standards.rs index 410f0358a5..5ed671079a 100644 --- a/crates/miden-standards/src/errors/standards.rs +++ b/crates/miden-standards/src/errors/standards.rs @@ -9,11 +9,6 @@ use miden_protocol::errors::MasmError; // STANDARDS ERRORS // ================================================================================================ -/// Error Message: "expected attachment kind to be Word for network account target" -pub const ERR_ATTACHMENT_KIND_MISMATCH: MasmError = MasmError::from_static_str("expected attachment kind to be Word for network account target"); -/// Error Message: "expected network account target attachment scheme" -pub const ERR_ATTACHMENT_SCHEME_MISMATCH: MasmError = MasmError::from_static_str("expected network account target attachment scheme"); - /// Error Message: "burn requires exactly 1 note asset" pub const ERR_BASIC_FUNGIBLE_BURN_WRONG_NUMBER_OF_ASSETS: MasmError = MasmError::from_static_str("burn requires exactly 1 note asset"); @@ -26,6 +21,9 @@ pub const ERR_MALFORMED_MULTISIG_CONFIG: MasmError = MasmError::from_static_str( /// Error Message: "MINT script expects exactly 12 storage items for private or 16+ storage items for public output notes" pub const ERR_MINT_UNEXPECTED_NUMBER_OF_STORAGE_ITEMS: MasmError = MasmError::from_static_str("MINT script expects exactly 12 storage items for private or 16+ storage items for public output notes"); +/// Error Message: "attachment is not a valid network account target" +pub const ERR_NOT_NETWORK_ACCOUNT_TARGET: MasmError = MasmError::from_static_str("attachment is not a valid network account target"); + /// Error Message: "failed to reclaim P2IDE note because the reclaiming account is not the sender" pub const ERR_P2IDE_RECLAIM_ACCT_IS_NOT_SENDER: MasmError = MasmError::from_static_str("failed to reclaim P2IDE note because the reclaiming account is not the sender"); /// Error Message: "P2IDE reclaim is disabled" From 1b9c98bda9d22c4e3bff3a09ce51c3865978d31b Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 23:02:26 +0000 Subject: [PATCH 32/35] feat: encapsulate note logic in structs --- crates/miden-agglayer/src/bridge_out.rs | 166 ++++++++++-------- crates/miden-agglayer/src/lib.rs | 28 +-- crates/miden-agglayer/src/update_ger_note.rs | 112 +++++++++--- .../tests/agglayer/bridge_out.rs | 30 ++-- .../tests/agglayer/update_ger.rs | 4 +- 5 files changed, 198 insertions(+), 142 deletions(-) diff --git a/crates/miden-agglayer/src/bridge_out.rs b/crates/miden-agglayer/src/bridge_out.rs index ed3da5171c..f942b6d0ce 100644 --- a/crates/miden-agglayer/src/bridge_out.rs +++ b/crates/miden-agglayer/src/bridge_out.rs @@ -6,7 +6,8 @@ use alloc::string::ToString; use alloc::vec::Vec; -use miden_core::Felt; +use miden_assembly::utils::Deserializable; +use miden_core::{Felt, Program, Word}; use miden_protocol::account::AccountId; use miden_protocol::crypto::rand::FeltRng; use miden_protocol::errors::NoteError; @@ -23,95 +24,114 @@ use miden_protocol::note::{ NoteType, }; use miden_standards::note::NetworkAccountTarget; +use miden_utils_sync::LazyLock; -use crate::{EthAddressFormat, b2agg_script}; +use crate::EthAddressFormat; -// B2AGG NOTE STRUCTURES +// NOTE SCRIPT // ================================================================================================ -/// Storage data for B2AGG note creation. +// Initialize the B2AGG note script only once +static B2AGG_SCRIPT: LazyLock = LazyLock::new(|| { + let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/B2AGG.masb")); + let program = Program::read_from_bytes(bytes).expect("Shipped B2AGG script is well-formed"); + NoteScript::new(program) +}); + +// B2AGG NOTE +// ================================================================================================ + +/// B2AGG (Bridge to AggLayer) note. /// -/// Contains the destination network and address, required for bridging assets to AggLayer. -#[derive(Debug, Clone)] -pub struct B2AggNoteStorage { - /// Destination network identifier (AggLayer-assigned network ID) - pub destination_network: u32, - /// Destination Ethereum address (20 bytes) - pub destination_address: EthAddressFormat, -} +/// This note is used to bridge assets from Miden to another network via the AggLayer. +/// When consumed by a bridge account, the assets are burned and a corresponding +/// claim can be made on the destination network. B2AGG notes are always public. +pub struct B2AggNote; -impl B2AggNoteStorage { - /// Creates a new B2AGG note storage with the specified destination. - pub fn new(destination_network: u32, destination_address: EthAddressFormat) -> Self { - Self { destination_network, destination_address } - } +impl B2AggNote { + // CONSTANTS + // -------------------------------------------------------------------------------------------- - /// Converts the storage data to a vector of field elements for note storage. - /// - /// The layout is: - /// - 1 felt: destination_network - /// - 5 felts: destination_address (20 bytes as 5 u32 values) - pub fn to_elements(&self) -> Vec { - let mut elements = Vec::with_capacity(6); + /// Expected number of storage items for a B2AGG note. + pub const NUM_STORAGE_ITEMS: usize = 6; - // Destination network - elements.push(Felt::new(self.destination_network as u64)); + // PUBLIC ACCESSORS + // -------------------------------------------------------------------------------------------- - // Destination address (5 u32 felts) - elements.extend(self.destination_address.to_elements()); + /// Returns the B2AGG (Bridge to AggLayer) note script. + pub fn script() -> NoteScript { + B2AGG_SCRIPT.clone() + } - elements + /// Returns the B2AGG note script root. + pub fn script_root() -> Word { + B2AGG_SCRIPT.root() } -} -impl TryFrom for NoteStorage { - type Error = NoteError; + // BUILDERS + // -------------------------------------------------------------------------------------------- - fn try_from(storage: B2AggNoteStorage) -> Result { - NoteStorage::new(storage.to_elements()) + /// Creates a B2AGG (Bridge to AggLayer) note. + /// + /// This note is used to bridge assets from Miden to another network via the AggLayer. + /// When consumed by a bridge account, the assets are burned and a corresponding + /// claim can be made on the destination network. B2AGG notes are always public. + /// + /// # Parameters + /// - `destination_network`: The AggLayer-assigned network ID for the destination chain + /// - `destination_address`: The Ethereum address on the destination network + /// - `assets`: The assets to bridge (must be fungible assets from a network faucet) + /// - `target_account_id`: The account ID that will consume this note (bridge account) + /// - `sender_account_id`: The account ID of the note creator + /// - `rng`: Random number generator for creating the note serial number + /// + /// # Errors + /// Returns an error if note creation fails. + pub fn create( + destination_network: u32, + destination_address: EthAddressFormat, + assets: NoteAssets, + target_account_id: AccountId, + sender_account_id: AccountId, + rng: &mut R, + ) -> Result { + let note_storage = build_note_storage(destination_network, destination_address)?; + + let tag = NoteTag::new(0); + + let attachment = NoteAttachment::from( + NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always) + .map_err(|e| NoteError::other(e.to_string()))?, + ); + + let metadata = + NoteMetadata::new(sender_account_id, NoteType::Public, tag).with_attachment(attachment); + + let recipient = NoteRecipient::new(rng.draw_word(), Self::script(), note_storage); + + Ok(Note::new(assets, metadata, recipient)) } } -// B2AGG NOTE CREATION +// HELPER FUNCTIONS // ================================================================================================ -/// Generates a B2AGG (Bridge to AggLayer) note. -/// -/// This note is used to bridge assets from Miden to another network via the AggLayer. -/// When consumed by a bridge account, the assets are burned and a corresponding -/// claim can be made on the destination network. B2AGG notes are always public. -/// -/// # Parameters -/// - `storage`: The destination network and address information -/// - `assets`: The assets to bridge (must be fungible assets from a network faucet) -/// - `target_account_id`: The account ID that will consume this note (bridge account) -/// - `sender_account_id`: The account ID of the note creator -/// - `rng`: Random number generator for creating the note serial number +/// Builds the note storage for a B2AGG note. /// -/// # Errors -/// Returns an error if note creation fails. -pub fn create_b2agg_note( - storage: B2AggNoteStorage, - assets: NoteAssets, - target_account_id: AccountId, - sender_account_id: AccountId, - rng: &mut R, -) -> Result { - let note_storage = NoteStorage::try_from(storage)?; - - let tag = NoteTag::new(0); - - let attachment = NoteAttachment::from( - NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always) - .map_err(|e| NoteError::other(e.to_string()))?, - ); - - let metadata = - NoteMetadata::new(sender_account_id, NoteType::Public, tag).with_attachment(attachment); - - let b2agg_script = b2agg_script(); - let recipient = - NoteRecipient::new(rng.draw_word(), NoteScript::new(b2agg_script), note_storage); - - Ok(Note::new(assets, metadata, recipient)) +/// The storage layout is: +/// - 1 felt: destination_network +/// - 5 felts: destination_address (20 bytes as 5 u32 values) +fn build_note_storage( + destination_network: u32, + destination_address: EthAddressFormat, +) -> Result { + let mut elements = Vec::with_capacity(6); + + // Destination network + elements.push(Felt::new(destination_network as u64)); + + // Destination address (5 u32 felts) + elements.extend(destination_address.to_elements()); + + NoteStorage::new(elements) } diff --git a/crates/miden-agglayer/src/lib.rs b/crates/miden-agglayer/src/lib.rs index 9ced1675c6..8681db5251 100644 --- a/crates/miden-agglayer/src/lib.rs +++ b/crates/miden-agglayer/src/lib.rs @@ -31,7 +31,7 @@ pub mod eth_types; pub mod update_ger_note; pub mod utils; -pub use bridge_out::{B2AggNoteStorage, create_b2agg_note}; +pub use bridge_out::B2AggNote; pub use claim_note::{ ClaimNoteStorage, ExitRoot, @@ -42,22 +42,11 @@ pub use claim_note::{ create_claim_note, }; pub use eth_types::{EthAddressFormat, EthAmount, EthAmountError}; -pub use update_ger_note::create_update_ger_note; +pub use update_ger_note::UpdateGerNote; // AGGLAYER NOTE SCRIPTS // ================================================================================================ -// Initialize the B2AGG note script only once -static B2AGG_SCRIPT: LazyLock = LazyLock::new(|| { - let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/B2AGG.masb")); - Program::read_from_bytes(bytes).expect("Shipped B2AGG script is well-formed") -}); - -/// Returns the B2AGG (Bridge to AggLayer) note script. -pub fn b2agg_script() -> Program { - B2AGG_SCRIPT.clone() -} - // Initialize the CLAIM note script only once static CLAIM_SCRIPT: LazyLock = LazyLock::new(|| { let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/CLAIM.masb")); @@ -70,19 +59,6 @@ pub fn claim_script() -> NoteScript { CLAIM_SCRIPT.clone() } -// Initialize the UPDATE_GER note script only once -static UPDATE_GER_SCRIPT: LazyLock = LazyLock::new(|| { - let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/UPDATE_GER.masb")); - let program = - Program::read_from_bytes(bytes).expect("Shipped UPDATE_GER script is well-formed"); - NoteScript::new(program) -}); - -/// Returns the UPDATE_GER note script. -pub fn update_ger_script() -> NoteScript { - UPDATE_GER_SCRIPT.clone() -} - // AGGLAYER ACCOUNT COMPONENTS // ================================================================================================ diff --git a/crates/miden-agglayer/src/update_ger_note.rs b/crates/miden-agglayer/src/update_ger_note.rs index d6c780750d..9e4e1cb36e 100644 --- a/crates/miden-agglayer/src/update_ger_note.rs +++ b/crates/miden-agglayer/src/update_ger_note.rs @@ -1,8 +1,15 @@ +//! UPDATE_GER note creation utilities. +//! +//! This module provides helpers for creating UPDATE_GER notes, +//! which are used to update the Global Exit Root in the bridge account. + extern crate alloc; use alloc::string::ToString; use alloc::vec; +use miden_assembly::utils::Deserializable; +use miden_core::{Program, Word}; use miden_protocol::account::AccountId; use miden_protocol::crypto::rand::FeltRng; use miden_protocol::errors::NoteError; @@ -13,45 +20,98 @@ use miden_protocol::note::{ NoteExecutionHint, NoteMetadata, NoteRecipient, + NoteScript, NoteStorage, NoteTag, NoteType, }; use miden_standards::note::NetworkAccountTarget; +use miden_utils_sync::LazyLock; + +use crate::ExitRoot; + +// NOTE SCRIPT +// ================================================================================================ -use crate::{ExitRoot, update_ger_script}; +// Initialize the UPDATE_GER note script only once +static UPDATE_GER_SCRIPT: LazyLock = LazyLock::new(|| { + let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/UPDATE_GER.masb")); + let program = + Program::read_from_bytes(bytes).expect("Shipped UPDATE_GER script is well-formed"); + NoteScript::new(program) +}); -/// Creates an UPDATE_GER note with the given GER (Global Exit Root) data. +// UPDATE_GER NOTE +// ================================================================================================ + +/// UPDATE_GER note. /// -/// The note storage contains 8 felts: GER[0..7] -pub fn create_update_ger_note( - ger: ExitRoot, - sender_account_id: AccountId, - target_account_id: AccountId, - rng: &mut R, -) -> Result { - let update_ger_script = update_ger_script(); +/// This note is used to update the Global Exit Root (GER) in the bridge account. +/// It carries the new GER data and is always public. +pub struct UpdateGerNote; + +impl UpdateGerNote { + // CONSTANTS + // -------------------------------------------------------------------------------------------- + + /// Expected number of storage items for an UPDATE_GER note. + pub const NUM_STORAGE_ITEMS: usize = 8; + + // PUBLIC ACCESSORS + // -------------------------------------------------------------------------------------------- + + /// Returns the UPDATE_GER note script. + pub fn script() -> NoteScript { + UPDATE_GER_SCRIPT.clone() + } + + /// Returns the UPDATE_GER note script root. + pub fn script_root() -> Word { + UPDATE_GER_SCRIPT.root() + } + + // BUILDERS + // -------------------------------------------------------------------------------------------- - // Create note storage with 8 felts: GER[0..7] - let storage_values = ger.to_elements().to_vec(); + /// Creates an UPDATE_GER note with the given GER (Global Exit Root) data. + /// + /// The note storage contains 8 felts: GER[0..7] + /// + /// # Parameters + /// - `ger`: The Global Exit Root data + /// - `sender_account_id`: The account ID of the note creator + /// - `target_account_id`: The account ID that will consume this note (bridge account) + /// - `rng`: Random number generator for creating the note serial number + /// + /// # Errors + /// Returns an error if note creation fails. + pub fn create( + ger: ExitRoot, + sender_account_id: AccountId, + target_account_id: AccountId, + rng: &mut R, + ) -> Result { + // Create note storage with 8 felts: GER[0..7] + let storage_values = ger.to_elements().to_vec(); - let note_storage = NoteStorage::new(storage_values)?; + let note_storage = NoteStorage::new(storage_values)?; - // Generate a serial number for the note - let serial_num = rng.draw_word(); + // Generate a serial number for the note + let serial_num = rng.draw_word(); - let recipient = NoteRecipient::new(serial_num, update_ger_script, note_storage); + let recipient = NoteRecipient::new(serial_num, Self::script(), note_storage); - let attachment = NoteAttachment::from( - NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always) - .map_err(|e| NoteError::other(e.to_string()))?, - ); - let note_tag = NoteTag::new(0); - let metadata = NoteMetadata::new(sender_account_id, NoteType::Public, note_tag) - .with_attachment(attachment); + let attachment = NoteAttachment::from( + NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always) + .map_err(|e| NoteError::other(e.to_string()))?, + ); + let note_tag = NoteTag::new(0); + let metadata = NoteMetadata::new(sender_account_id, NoteType::Public, note_tag) + .with_attachment(attachment); - // UPDATE_GER notes don't carry assets - let assets = NoteAssets::new(vec![])?; + // UPDATE_GER notes don't carry assets + let assets = NoteAssets::new(vec![])?; - Ok(Note::new(assets, metadata, recipient)) + Ok(Note::new(assets, metadata, recipient)) + } } diff --git a/crates/miden-testing/tests/agglayer/bridge_out.rs b/crates/miden-testing/tests/agglayer/bridge_out.rs index 655ab588f1..bca7648091 100644 --- a/crates/miden-testing/tests/agglayer/bridge_out.rs +++ b/crates/miden-testing/tests/agglayer/bridge_out.rs @@ -1,12 +1,7 @@ extern crate alloc; use miden_agglayer::errors::ERR_B2AGG_TARGET_ACCOUNT_MISMATCH; -use miden_agglayer::{ - B2AggNoteStorage, - EthAddressFormat, - create_b2agg_note, - create_existing_bridge_account, -}; +use miden_agglayer::{B2AggNote, EthAddressFormat, create_existing_bridge_account}; use miden_crypto::rand::FeltRng; use miden_protocol::Felt; use miden_protocol::account::{AccountId, AccountIdVersion, AccountStorageMode, AccountType}; @@ -57,12 +52,17 @@ async fn test_bridge_out_consumes_b2agg_note() -> anyhow::Result<()> { let eth_address = EthAddressFormat::from_hex(destination_address).expect("Valid Ethereum address"); - let storage = B2AggNoteStorage::new(destination_network, eth_address); let assets = NoteAssets::new(vec![bridge_asset])?; // Create the B2AGG note using the helper - let b2agg_note = - create_b2agg_note(storage, assets, bridge_account.id(), faucet.id(), builder.rng_mut())?; + let b2agg_note = B2AggNote::create( + destination_network, + eth_address, + assets, + bridge_account.id(), + faucet.id(), + builder.rng_mut(), + )?; // Add the B2AGG note to the mock chain builder.add_output_note(OutputNote::Full(b2agg_note.clone())); @@ -204,13 +204,13 @@ async fn test_b2agg_note_reclaim_scenario() -> anyhow::Result<()> { let eth_address = EthAddressFormat::from_hex(destination_address).expect("Valid Ethereum address"); - let storage = B2AggNoteStorage::new(destination_network, eth_address); let assets = NoteAssets::new(vec![bridge_asset])?; // Create the B2AGG note with the USER ACCOUNT as the sender // This is the key difference - the note sender will be the same as the consuming account - let b2agg_note = create_b2agg_note( - storage, + let b2agg_note = B2AggNote::create( + destination_network, + eth_address, assets, bridge_account.id(), user_account.id(), @@ -312,12 +312,12 @@ async fn test_b2agg_note_non_target_account_cannot_consume() -> anyhow::Result<( let eth_address = EthAddressFormat::from_hex(destination_address).expect("Valid Ethereum address"); - let storage = B2AggNoteStorage::new(destination_network, eth_address); let assets = NoteAssets::new(vec![bridge_asset])?; // Create the B2AGG note - let b2agg_note = create_b2agg_note( - storage, + let b2agg_note = B2AggNote::create( + destination_network, + eth_address, assets, bridge_account.id(), sender_account.id(), diff --git a/crates/miden-testing/tests/agglayer/update_ger.rs b/crates/miden-testing/tests/agglayer/update_ger.rs index aa5ac4f0f5..6b2f973ae9 100644 --- a/crates/miden-testing/tests/agglayer/update_ger.rs +++ b/crates/miden-testing/tests/agglayer/update_ger.rs @@ -1,4 +1,4 @@ -use miden_agglayer::{ExitRoot, create_existing_bridge_account, create_update_ger_note}; +use miden_agglayer::{ExitRoot, UpdateGerNote, create_existing_bridge_account}; use miden_protocol::Word; use miden_protocol::account::StorageSlotName; use miden_protocol::crypto::rand::FeltRng; @@ -30,7 +30,7 @@ async fn test_update_ger_note_updates_storage() -> anyhow::Result<()> { ]; let ger = ExitRoot::from(ger_bytes); let update_ger_note = - create_update_ger_note(ger, user_account.id(), bridge_account.id(), builder.rng_mut())?; + UpdateGerNote::create(ger, user_account.id(), bridge_account.id(), builder.rng_mut())?; builder.add_output_note(OutputNote::Full(update_ger_note.clone())); let mock_chain = builder.build()?; From 5a09fda15d11ed073218145cd97bd2e02ee43a90 Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 23:08:40 +0000 Subject: [PATCH 33/35] chore: rename file to bagg_note --- crates/miden-agglayer/src/{bridge_out.rs => b2agg_note.rs} | 0 crates/miden-agglayer/src/lib.rs | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename crates/miden-agglayer/src/{bridge_out.rs => b2agg_note.rs} (100%) diff --git a/crates/miden-agglayer/src/bridge_out.rs b/crates/miden-agglayer/src/b2agg_note.rs similarity index 100% rename from crates/miden-agglayer/src/bridge_out.rs rename to crates/miden-agglayer/src/b2agg_note.rs diff --git a/crates/miden-agglayer/src/lib.rs b/crates/miden-agglayer/src/lib.rs index 8681db5251..2e28c1a6bc 100644 --- a/crates/miden-agglayer/src/lib.rs +++ b/crates/miden-agglayer/src/lib.rs @@ -24,14 +24,14 @@ use miden_standards::account::auth::NoAuth; use miden_standards::account::faucets::NetworkFungibleFaucet; use miden_utils_sync::LazyLock; -pub mod bridge_out; +pub mod b2agg_note; pub mod claim_note; pub mod errors; pub mod eth_types; pub mod update_ger_note; pub mod utils; -pub use bridge_out::B2AggNote; +pub use b2agg_note::B2AggNote; pub use claim_note::{ ClaimNoteStorage, ExitRoot, From 457bcd9eb7394d0867f90500ed5eb1a76c23bddc Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 23:11:46 +0000 Subject: [PATCH 34/35] chore: remove redundant comments --- crates/miden-agglayer/src/b2agg_note.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/miden-agglayer/src/b2agg_note.rs b/crates/miden-agglayer/src/b2agg_note.rs index f942b6d0ce..637d2598a6 100644 --- a/crates/miden-agglayer/src/b2agg_note.rs +++ b/crates/miden-agglayer/src/b2agg_note.rs @@ -127,10 +127,7 @@ fn build_note_storage( ) -> Result { let mut elements = Vec::with_capacity(6); - // Destination network elements.push(Felt::new(destination_network as u64)); - - // Destination address (5 u32 felts) elements.extend(destination_address.to_elements()); NoteStorage::new(elements) From 779a1bf0e446b17ceefcc09690b02f58aef2eb22 Mon Sep 17 00:00:00 2001 From: Marti Date: Wed, 4 Feb 2026 11:53:40 +0000 Subject: [PATCH 35/35] Revert "feat: swap kind/scheme in signatures" This reverts commit aad47e5d6b5d5f32c0e9da451a667aec57912e61. --- .../attachments/network_account_target.masm | 19 +++++++++++-------- .../src/standards/network_account_target.rs | 4 +++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/crates/miden-standards/asm/standards/attachments/network_account_target.masm b/crates/miden-standards/asm/standards/attachments/network_account_target.masm index 08cc380d74..46133f4136 100644 --- a/crates/miden-standards/asm/standards/attachments/network_account_target.masm +++ b/crates/miden-standards/asm/standards/attachments/network_account_target.masm @@ -25,16 +25,16 @@ const ERR_NOT_NETWORK_ACCOUNT_TARGET = "attachment is not a valid network accoun #! Returns a boolean indicating whether the attachment scheme and kind match the expected #! values for a NetworkAccountTarget attachment. #! -#! Inputs: [attachment_kind, attachment_scheme] +#! Inputs: [attachment_scheme, attachment_kind] #! Outputs: [is_network_account_target] #! #! Invocation: exec pub proc is_network_account_target - eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND - # => [is_kind_valid, attachment_scheme] + eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME + # => [is_scheme_valid, attachment_kind] - swap eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME - # => [is_scheme_valid, is_kind_valid] + swap eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND + # => [is_kind_valid, is_scheme_valid] and # => [is_network_account_target] @@ -69,7 +69,7 @@ end #! [0, exec_hint_tag, account_id_prefix, account_id_suffix] #! #! Inputs: [account_id_prefix, account_id_suffix, exec_hint] -#! Outputs: [attachment_kind, attachment_scheme, NOTE_ATTACHMENT] +#! Outputs: [attachment_scheme, attachment_kind, NOTE_ATTACHMENT] #! #! Where: #! - account_id_{prefix,suffix} are the prefix and suffix felts of an account ID. @@ -81,9 +81,9 @@ end pub proc new movup.2 push.0 - push.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME push.NETWORK_ACCOUNT_TARGET_ATTACHMENT_KIND - # => [attachment_kind, attachment_scheme, ATTACHMENT] + push.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME + # => [attachment_scheme, attachment_kind, ATTACHMENT] end #! Returns a boolean indicating whether the active account matches the target account @@ -110,6 +110,9 @@ pub proc active_account_matches_target_account exec.note::extract_attachment_info_from_metadata # => [attachment_kind, attachment_scheme, NOTE_ATTACHMENT] + swap + # => [attachment_scheme, attachment_kind, NOTE_ATTACHMENT] + # ensure the attachment is a network account target exec.is_network_account_target assert.err=ERR_NOT_NETWORK_ACCOUNT_TARGET diff --git a/crates/miden-testing/src/standards/network_account_target.rs b/crates/miden-testing/src/standards/network_account_target.rs index ae6c2a1cfc..bd07dfe44a 100644 --- a/crates/miden-testing/src/standards/network_account_target.rs +++ b/crates/miden-testing/src/standards/network_account_target.rs @@ -33,6 +33,8 @@ async fn network_account_target_get_id() -> anyhow::Result<()> { push.{metadata_header} exec.note::extract_attachment_info_from_metadata # => [attachment_kind, attachment_scheme, NOTE_ATTACHMENT] + swap + # => [attachment_scheme, attachment_kind, NOTE_ATTACHMENT] exec.network_account_target::is_network_account_target # => [is_valid, NOTE_ATTACHMENT] assert.err=ERR_NOT_NETWORK_ACCOUNT_TARGET @@ -76,7 +78,7 @@ async fn network_account_target_new_attachment() -> anyhow::Result<()> { push.{target_id_prefix} # => [target_id_prefix, target_id_suffix, exec_hint] exec.network_account_target::new - # => [attachment_kind, attachment_scheme, ATTACHMENT, pad(16)] + # => [attachment_scheme, attachment_kind, ATTACHMENT, pad(16)] # cleanup stack swapdw dropw dropw