Skip to main content

miden_agglayer/
b2agg_note.rs

1//! Bridge Out note creation utilities.
2//!
3//! This module provides helpers for creating B2AGG (Bridge to AggLayer) notes,
4//! which are used to bridge assets out from Miden to the AggLayer network.
5
6use alloc::vec;
7use alloc::vec::Vec;
8
9use miden_core::Felt;
10use miden_protocol::account::AccountId;
11use miden_protocol::crypto::rand::FeltRng;
12use miden_protocol::errors::NoteError;
13use miden_protocol::note::{
14    Note,
15    NoteAssets,
16    NoteAttachment,
17    NoteAttachments,
18    NoteRecipient,
19    NoteScript,
20    NoteScriptRoot,
21    NoteStorage,
22    NoteType,
23    PartialNoteMetadata,
24};
25use miden_standards::interop::eth::EthAddress;
26use miden_standards::note::costs::NoteConsumptionCost;
27use miden_standards::note::{BurnNote, NetworkAccountTarget, NoteExecutionHint};
28use miden_utils_sync::LazyLock;
29
30use crate::costs::B2AGG_CONSUMPTION_CYCLES;
31use crate::note_script;
32
33// NOTE SCRIPT
34// ================================================================================================
35
36/// Path to the B2AGG note script procedure in the agglayer package.
37const B2AGG_SCRIPT_PATH: &str = "::agglayer::notes::b2agg::main";
38
39// Initialize the B2AGG note script only once
40static B2AGG_SCRIPT: LazyLock<NoteScript> = LazyLock::new(|| note_script(B2AGG_SCRIPT_PATH));
41
42// B2AGG NOTE
43// ================================================================================================
44
45/// B2AGG (Bridge to AggLayer) note.
46///
47/// This note is used to bridge assets from Miden to another network via the AggLayer.
48/// When consumed by a bridge account, the assets are burned and a corresponding
49/// claim can be made on the destination network. B2AGG notes are always public.
50pub struct B2AggNote;
51
52impl B2AggNote {
53    // CONSTANTS
54    // --------------------------------------------------------------------------------------------
55
56    /// Expected number of storage items for a B2AGG note.
57    pub const NUM_STORAGE_ITEMS: usize = 6;
58
59    // PUBLIC ACCESSORS
60    // --------------------------------------------------------------------------------------------
61
62    /// Returns the B2AGG (Bridge to AggLayer) note script.
63    pub fn script() -> NoteScript {
64        B2AGG_SCRIPT.clone()
65    }
66
67    /// Returns the B2AGG note script root.
68    pub fn script_root() -> NoteScriptRoot {
69        B2AGG_SCRIPT.root()
70    }
71
72    // BUILDERS
73    // --------------------------------------------------------------------------------------------
74
75    /// Creates a B2AGG (Bridge to AggLayer) note.
76    ///
77    /// This note is used to bridge assets from Miden to another network via the AggLayer.
78    /// When consumed by a bridge account, the assets are burned and a corresponding
79    /// claim can be made on the destination network. B2AGG notes are always public.
80    ///
81    /// # Parameters
82    /// - `destination_network`: The AggLayer-assigned network ID for the destination chain
83    /// - `destination_address`: The Ethereum address on the destination network
84    /// - `assets`: The assets to bridge (must be fungible assets from a network faucet)
85    /// - `target_account_id`: The account ID that will consume this note (bridge account)
86    /// - `sender_account_id`: The account ID of the note creator
87    /// - `rng`: Random number generator for creating the note serial number
88    ///
89    /// # Errors
90    /// Returns an error if note creation fails.
91    pub fn create<R: FeltRng>(
92        destination_network: u32,
93        destination_address: EthAddress,
94        assets: NoteAssets,
95        target_account_id: AccountId,
96        sender_account_id: AccountId,
97        rng: &mut R,
98    ) -> Result<Note, NoteError> {
99        let note_storage = build_note_storage(destination_network, destination_address)?;
100
101        let attachment = NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always)
102            .map_err(|error| {
103                NoteError::other_with_source("failed to create b2agg network account target", error)
104            })?;
105        let attachments = NoteAttachments::from(NoteAttachment::from(attachment));
106
107        let metadata = PartialNoteMetadata::new(sender_account_id, NoteType::Public);
108
109        let recipient = NoteRecipient::new(rng.draw_word(), Self::script(), note_storage);
110
111        Ok(Note::with_attachments(assets, metadata, recipient, attachments))
112    }
113}
114
115// HELPER FUNCTIONS
116// ================================================================================================
117
118/// Builds the note storage for a B2AGG note.
119///
120/// The storage layout is:
121/// - 1 felt: destination_network
122/// - 5 felts: destination_address (20 bytes as 5 u32 values)
123fn build_note_storage(
124    destination_network: u32,
125    destination_address: EthAddress,
126) -> Result<NoteStorage, NoteError> {
127    let mut elements = Vec::with_capacity(6);
128
129    let destination_network = u32::from_le_bytes(destination_network.to_be_bytes());
130    elements.push(Felt::from(destination_network));
131    elements.extend(destination_address.to_elements());
132
133    NoteStorage::new(elements)
134}
135
136// NOTE CONSUMPTION COST
137// ================================================================================================
138
139impl NoteConsumptionCost for B2AggNote {
140    fn consumption_cycles() -> u32 {
141        B2AGG_CONSUMPTION_CYCLES
142    }
143
144    /// Consuming a B2AGG note creates the BURN note routed to the agglayer faucet (a network
145    /// account).
146    fn created_notes() -> Vec<NoteScriptRoot> {
147        vec![BurnNote::script_root()]
148    }
149}