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}