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::Vec;
7
8use miden_assembly::Library;
9use miden_assembly::serde::Deserializable;
10use miden_core::Felt;
11use miden_protocol::account::AccountId;
12use miden_protocol::crypto::rand::FeltRng;
13use miden_protocol::errors::NoteError;
14use miden_protocol::note::{
15 Note,
16 NoteAssets,
17 NoteAttachment,
18 NoteAttachments,
19 NoteRecipient,
20 NoteScript,
21 NoteScriptRoot,
22 NoteStorage,
23 NoteType,
24 PartialNoteMetadata,
25};
26use miden_standards::note::{NetworkAccountTarget, NoteExecutionHint};
27use miden_utils_sync::LazyLock;
28
29use crate::EthAddress;
30
31// NOTE SCRIPT
32// ================================================================================================
33
34// Initialize the B2AGG note script only once
35static B2AGG_SCRIPT: LazyLock<NoteScript> = LazyLock::new(|| {
36 let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/b2agg.masl"));
37 let library =
38 Library::read_from_bytes(bytes).expect("shipped B2AGG script library is well-formed");
39 NoteScript::from_library(&library).expect("shipped B2AGG script is well-formed")
40});
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}