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::string::ToString;
7use alloc::vec::Vec;
8
9use miden_assembly::serde::Deserializable;
10use miden_core::program::Program;
11use miden_core::{Felt, Word};
12use miden_protocol::account::AccountId;
13use miden_protocol::crypto::rand::FeltRng;
14use miden_protocol::errors::NoteError;
15use miden_protocol::note::{
16    Note,
17    NoteAssets,
18    NoteAttachment,
19    NoteMetadata,
20    NoteRecipient,
21    NoteScript,
22    NoteStorage,
23    NoteType,
24};
25use miden_standards::note::{NetworkAccountTarget, NoteExecutionHint};
26use miden_utils_sync::LazyLock;
27
28use crate::EthAddress;
29
30// NOTE SCRIPT
31// ================================================================================================
32
33// Initialize the B2AGG note script only once
34static B2AGG_SCRIPT: LazyLock<NoteScript> = LazyLock::new(|| {
35    let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/B2AGG.masb"));
36    let program = Program::read_from_bytes(bytes).expect("shipped B2AGG script is well-formed");
37    NoteScript::new(program)
38});
39
40// B2AGG NOTE
41// ================================================================================================
42
43/// B2AGG (Bridge to AggLayer) note.
44///
45/// This note is used to bridge assets from Miden to another network via the AggLayer.
46/// When consumed by a bridge account, the assets are burned and a corresponding
47/// claim can be made on the destination network. B2AGG notes are always public.
48pub struct B2AggNote;
49
50impl B2AggNote {
51    // CONSTANTS
52    // --------------------------------------------------------------------------------------------
53
54    /// Expected number of storage items for a B2AGG note.
55    pub const NUM_STORAGE_ITEMS: usize = 6;
56
57    // PUBLIC ACCESSORS
58    // --------------------------------------------------------------------------------------------
59
60    /// Returns the B2AGG (Bridge to AggLayer) note script.
61    pub fn script() -> NoteScript {
62        B2AGG_SCRIPT.clone()
63    }
64
65    /// Returns the B2AGG note script root.
66    pub fn script_root() -> Word {
67        B2AGG_SCRIPT.root()
68    }
69
70    // BUILDERS
71    // --------------------------------------------------------------------------------------------
72
73    /// Creates a B2AGG (Bridge to AggLayer) note.
74    ///
75    /// This note is used to bridge assets from Miden to another network via the AggLayer.
76    /// When consumed by a bridge account, the assets are burned and a corresponding
77    /// claim can be made on the destination network. B2AGG notes are always public.
78    ///
79    /// # Parameters
80    /// - `destination_network`: The AggLayer-assigned network ID for the destination chain
81    /// - `destination_address`: The Ethereum address on the destination network
82    /// - `assets`: The assets to bridge (must be fungible assets from a network faucet)
83    /// - `target_account_id`: The account ID that will consume this note (bridge account)
84    /// - `sender_account_id`: The account ID of the note creator
85    /// - `rng`: Random number generator for creating the note serial number
86    ///
87    /// # Errors
88    /// Returns an error if note creation fails.
89    pub fn create<R: FeltRng>(
90        destination_network: u32,
91        destination_address: EthAddress,
92        assets: NoteAssets,
93        target_account_id: AccountId,
94        sender_account_id: AccountId,
95        rng: &mut R,
96    ) -> Result<Note, NoteError> {
97        let note_storage = build_note_storage(destination_network, destination_address)?;
98
99        let attachment = NoteAttachment::from(
100            NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always)
101                .map_err(|e| NoteError::other(e.to_string()))?,
102        );
103
104        let metadata =
105            NoteMetadata::new(sender_account_id, NoteType::Public).with_attachment(attachment);
106
107        let recipient = NoteRecipient::new(rng.draw_word(), Self::script(), note_storage);
108
109        Ok(Note::new(assets, metadata, recipient))
110    }
111}
112
113// HELPER FUNCTIONS
114// ================================================================================================
115
116/// Builds the note storage for a B2AGG note.
117///
118/// The storage layout is:
119/// - 1 felt: destination_network
120/// - 5 felts: destination_address (20 bytes as 5 u32 values)
121fn build_note_storage(
122    destination_network: u32,
123    destination_address: EthAddress,
124) -> Result<NoteStorage, NoteError> {
125    let mut elements = Vec::with_capacity(6);
126
127    let destination_network = u32::from_le_bytes(destination_network.to_be_bytes());
128    elements.push(Felt::from(destination_network));
129    elements.extend(destination_address.to_elements());
130
131    NoteStorage::new(elements)
132}