1#![no_std]
2
3extern crate alloc;
4
5use miden_assembly::Library;
6use miden_assembly::serde::Deserializable;
7use miden_core::{Felt, Word};
8use miden_protocol::account::{
9 Account,
10 AccountBuilder,
11 AccountComponent,
12 AccountId,
13 AccountStorageMode,
14 AccountType,
15};
16use miden_protocol::asset::TokenSymbol;
17use miden_protocol::note::NoteScript;
18use miden_protocol::vm::Program;
19use miden_standards::account::access::Ownable2Step;
20use miden_standards::account::auth::NoAuth;
21use miden_standards::account::mint_policies::OwnerControlled;
22use miden_utils_sync::LazyLock;
23
24pub mod b2agg_note;
25pub mod bridge;
26pub mod claim_note;
27pub mod config_note;
28pub mod errors;
29pub mod eth_types;
30pub mod faucet;
31pub mod update_ger_note;
32pub mod utils;
33
34pub use b2agg_note::B2AggNote;
35pub use bridge::{AggLayerBridge, AgglayerBridgeError};
36pub use claim_note::{
37 CgiChainHash,
38 ClaimNoteStorage,
39 ExitRoot,
40 LeafData,
41 LeafValue,
42 ProofData,
43 SmtNode,
44 create_claim_note,
45};
46pub use config_note::ConfigAggBridgeNote;
47#[cfg(any(test, feature = "testing"))]
48pub use eth_types::GlobalIndexExt;
49pub use eth_types::{
50 EthAddress,
51 EthAmount,
52 EthAmountError,
53 EthEmbeddedAccountId,
54 GlobalIndex,
55 GlobalIndexError,
56 MetadataHash,
57};
58pub use faucet::{AggLayerFaucet, AgglayerFaucetError};
59pub use update_ger_note::UpdateGerNote;
60pub use utils::Keccak256Output;
61
62static CLAIM_SCRIPT: LazyLock<NoteScript> = LazyLock::new(|| {
67 let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/CLAIM.masb"));
68 let program = Program::read_from_bytes(bytes).expect("shipped CLAIM script is well-formed");
69 NoteScript::new(program)
70});
71
72pub fn claim_script() -> NoteScript {
74 CLAIM_SCRIPT.clone()
75}
76
77static AGGLAYER_LIBRARY: LazyLock<Library> = LazyLock::new(|| {
81 let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/agglayer.masl"));
82 Library::read_from_bytes(bytes).expect("shipped AggLayer library is well-formed")
83});
84
85static BRIDGE_COMPONENT_LIBRARY: LazyLock<Library> = LazyLock::new(|| {
86 let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/components/bridge.masl"));
87 Library::read_from_bytes(bytes).expect("shipped bridge component library is well-formed")
88});
89
90static FAUCET_COMPONENT_LIBRARY: LazyLock<Library> = LazyLock::new(|| {
91 let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/components/faucet.masl"));
92 Library::read_from_bytes(bytes).expect("shipped faucet component library is well-formed")
93});
94
95pub fn agglayer_library() -> Library {
97 AGGLAYER_LIBRARY.clone()
98}
99
100fn agglayer_bridge_component_library() -> Library {
102 BRIDGE_COMPONENT_LIBRARY.clone()
103}
104
105fn agglayer_faucet_component_library() -> Library {
107 FAUCET_COMPONENT_LIBRARY.clone()
108}
109
110#[allow(clippy::too_many_arguments)]
137fn create_agglayer_faucet_component(
138 token_symbol: &str,
139 decimals: u8,
140 max_supply: Felt,
141 token_supply: Felt,
142 origin_token_address: &EthAddress,
143 origin_network: u32,
144 scale: u8,
145 metadata_hash: MetadataHash,
146) -> AccountComponent {
147 let symbol = TokenSymbol::new(token_symbol).expect("token symbol should be valid");
148 AggLayerFaucet::new(
149 symbol,
150 decimals,
151 max_supply,
152 token_supply,
153 *origin_token_address,
154 origin_network,
155 scale,
156 metadata_hash,
157 )
158 .expect("agglayer faucet metadata should be valid")
159 .into()
160}
161
162fn create_bridge_account_builder(
167 seed: Word,
168 bridge_admin_id: AccountId,
169 ger_manager_id: AccountId,
170) -> AccountBuilder {
171 Account::builder(seed.into())
172 .storage_mode(AccountStorageMode::Network)
173 .with_component(AggLayerBridge::new(bridge_admin_id, ger_manager_id))
174}
175
176pub fn create_bridge_account(
180 seed: Word,
181 bridge_admin_id: AccountId,
182 ger_manager_id: AccountId,
183) -> Account {
184 create_bridge_account_builder(seed, bridge_admin_id, ger_manager_id)
185 .with_auth_component(AccountComponent::from(NoAuth))
186 .build()
187 .expect("bridge account should be valid")
188}
189
190#[cfg(any(feature = "testing", test))]
194pub fn create_existing_bridge_account(
195 seed: Word,
196 bridge_admin_id: AccountId,
197 ger_manager_id: AccountId,
198) -> Account {
199 create_bridge_account_builder(seed, bridge_admin_id, ger_manager_id)
200 .with_auth_component(AccountComponent::from(NoAuth))
201 .build_existing()
202 .expect("bridge account should be valid")
203}
204
205#[allow(clippy::too_many_arguments)]
213fn create_agglayer_faucet_builder(
214 seed: Word,
215 token_symbol: &str,
216 decimals: u8,
217 max_supply: Felt,
218 token_supply: Felt,
219 bridge_account_id: AccountId,
220 origin_token_address: &EthAddress,
221 origin_network: u32,
222 scale: u8,
223 metadata_hash: MetadataHash,
224) -> AccountBuilder {
225 let agglayer_component = create_agglayer_faucet_component(
226 token_symbol,
227 decimals,
228 max_supply,
229 token_supply,
230 origin_token_address,
231 origin_network,
232 scale,
233 metadata_hash,
234 );
235
236 Account::builder(seed.into())
237 .account_type(AccountType::FungibleFaucet)
238 .storage_mode(AccountStorageMode::Network)
239 .with_component(agglayer_component)
240 .with_component(Ownable2Step::new(bridge_account_id))
241 .with_component(OwnerControlled::owner_only())
242}
243
244#[allow(clippy::too_many_arguments)]
248pub fn create_agglayer_faucet(
249 seed: Word,
250 token_symbol: &str,
251 decimals: u8,
252 max_supply: Felt,
253 bridge_account_id: AccountId,
254 origin_token_address: &EthAddress,
255 origin_network: u32,
256 scale: u8,
257 metadata_hash: MetadataHash,
258) -> Account {
259 create_agglayer_faucet_builder(
260 seed,
261 token_symbol,
262 decimals,
263 max_supply,
264 Felt::ZERO,
265 bridge_account_id,
266 origin_token_address,
267 origin_network,
268 scale,
269 metadata_hash,
270 )
271 .with_auth_component(AccountComponent::from(NoAuth))
272 .build()
273 .expect("agglayer faucet account should be valid")
274}
275
276#[cfg(any(feature = "testing", test))]
280#[allow(clippy::too_many_arguments)]
281pub fn create_existing_agglayer_faucet(
282 seed: Word,
283 token_symbol: &str,
284 decimals: u8,
285 max_supply: Felt,
286 token_supply: Felt,
287 bridge_account_id: AccountId,
288 origin_token_address: &EthAddress,
289 origin_network: u32,
290 scale: u8,
291 metadata_hash: MetadataHash,
292) -> Account {
293 create_agglayer_faucet_builder(
294 seed,
295 token_symbol,
296 decimals,
297 max_supply,
298 token_supply,
299 bridge_account_id,
300 origin_token_address,
301 origin_network,
302 scale,
303 metadata_hash,
304 )
305 .with_auth_component(AccountComponent::from(NoAuth))
306 .build_existing()
307 .expect("agglayer faucet account should be valid")
308}