#![no_std]
extern crate alloc;
use miden_assembly::Library;
use miden_assembly::serde::Deserializable;
use miden_core::{Felt, Word};
use miden_protocol::account::{
Account,
AccountBuilder,
AccountComponent,
AccountId,
AccountStorageMode,
AccountType,
};
use miden_protocol::asset::TokenSymbol;
use miden_protocol::note::NoteScript;
use miden_protocol::vm::Program;
use miden_standards::account::access::Ownable2Step;
use miden_standards::account::auth::NoAuth;
use miden_standards::account::mint_policies::OwnerControlled;
use miden_utils_sync::LazyLock;
pub mod b2agg_note;
pub mod bridge;
pub mod claim_note;
pub mod config_note;
pub mod errors;
pub mod eth_types;
pub mod faucet;
pub mod update_ger_note;
pub mod utils;
pub use b2agg_note::B2AggNote;
pub use bridge::{AggLayerBridge, AgglayerBridgeError};
pub use claim_note::{
CgiChainHash,
ClaimNoteStorage,
ExitRoot,
LeafData,
LeafValue,
ProofData,
SmtNode,
create_claim_note,
};
pub use config_note::ConfigAggBridgeNote;
#[cfg(any(test, feature = "testing"))]
pub use eth_types::GlobalIndexExt;
pub use eth_types::{
EthAddress,
EthAmount,
EthAmountError,
EthEmbeddedAccountId,
GlobalIndex,
GlobalIndexError,
MetadataHash,
};
pub use faucet::{AggLayerFaucet, AgglayerFaucetError};
pub use update_ger_note::UpdateGerNote;
pub use utils::Keccak256Output;
static CLAIM_SCRIPT: LazyLock<NoteScript> = LazyLock::new(|| {
let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/CLAIM.masb"));
let program = Program::read_from_bytes(bytes).expect("shipped CLAIM script is well-formed");
NoteScript::new(program)
});
pub fn claim_script() -> NoteScript {
CLAIM_SCRIPT.clone()
}
static AGGLAYER_LIBRARY: LazyLock<Library> = LazyLock::new(|| {
let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/agglayer.masl"));
Library::read_from_bytes(bytes).expect("shipped AggLayer library is well-formed")
});
static BRIDGE_COMPONENT_LIBRARY: LazyLock<Library> = LazyLock::new(|| {
let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/components/bridge.masl"));
Library::read_from_bytes(bytes).expect("shipped bridge component library is well-formed")
});
static FAUCET_COMPONENT_LIBRARY: LazyLock<Library> = LazyLock::new(|| {
let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/components/faucet.masl"));
Library::read_from_bytes(bytes).expect("shipped faucet component library is well-formed")
});
pub fn agglayer_library() -> Library {
AGGLAYER_LIBRARY.clone()
}
fn agglayer_bridge_component_library() -> Library {
BRIDGE_COMPONENT_LIBRARY.clone()
}
fn agglayer_faucet_component_library() -> Library {
FAUCET_COMPONENT_LIBRARY.clone()
}
#[allow(clippy::too_many_arguments)]
fn create_agglayer_faucet_component(
token_symbol: &str,
decimals: u8,
max_supply: Felt,
token_supply: Felt,
origin_token_address: &EthAddress,
origin_network: u32,
scale: u8,
metadata_hash: MetadataHash,
) -> AccountComponent {
let symbol = TokenSymbol::new(token_symbol).expect("token symbol should be valid");
AggLayerFaucet::new(
symbol,
decimals,
max_supply,
token_supply,
*origin_token_address,
origin_network,
scale,
metadata_hash,
)
.expect("agglayer faucet metadata should be valid")
.into()
}
fn create_bridge_account_builder(
seed: Word,
bridge_admin_id: AccountId,
ger_manager_id: AccountId,
) -> AccountBuilder {
Account::builder(seed.into())
.storage_mode(AccountStorageMode::Network)
.with_component(AggLayerBridge::new(bridge_admin_id, ger_manager_id))
}
pub fn create_bridge_account(
seed: Word,
bridge_admin_id: AccountId,
ger_manager_id: AccountId,
) -> Account {
create_bridge_account_builder(seed, bridge_admin_id, ger_manager_id)
.with_auth_component(AccountComponent::from(NoAuth))
.build()
.expect("bridge account should be valid")
}
#[cfg(any(feature = "testing", test))]
pub fn create_existing_bridge_account(
seed: Word,
bridge_admin_id: AccountId,
ger_manager_id: AccountId,
) -> Account {
create_bridge_account_builder(seed, bridge_admin_id, ger_manager_id)
.with_auth_component(AccountComponent::from(NoAuth))
.build_existing()
.expect("bridge account should be valid")
}
#[allow(clippy::too_many_arguments)]
fn create_agglayer_faucet_builder(
seed: Word,
token_symbol: &str,
decimals: u8,
max_supply: Felt,
token_supply: Felt,
bridge_account_id: AccountId,
origin_token_address: &EthAddress,
origin_network: u32,
scale: u8,
metadata_hash: MetadataHash,
) -> AccountBuilder {
let agglayer_component = create_agglayer_faucet_component(
token_symbol,
decimals,
max_supply,
token_supply,
origin_token_address,
origin_network,
scale,
metadata_hash,
);
Account::builder(seed.into())
.account_type(AccountType::FungibleFaucet)
.storage_mode(AccountStorageMode::Network)
.with_component(agglayer_component)
.with_component(Ownable2Step::new(bridge_account_id))
.with_component(OwnerControlled::owner_only())
}
#[allow(clippy::too_many_arguments)]
pub fn create_agglayer_faucet(
seed: Word,
token_symbol: &str,
decimals: u8,
max_supply: Felt,
bridge_account_id: AccountId,
origin_token_address: &EthAddress,
origin_network: u32,
scale: u8,
metadata_hash: MetadataHash,
) -> Account {
create_agglayer_faucet_builder(
seed,
token_symbol,
decimals,
max_supply,
Felt::ZERO,
bridge_account_id,
origin_token_address,
origin_network,
scale,
metadata_hash,
)
.with_auth_component(AccountComponent::from(NoAuth))
.build()
.expect("agglayer faucet account should be valid")
}
#[cfg(any(feature = "testing", test))]
#[allow(clippy::too_many_arguments)]
pub fn create_existing_agglayer_faucet(
seed: Word,
token_symbol: &str,
decimals: u8,
max_supply: Felt,
token_supply: Felt,
bridge_account_id: AccountId,
origin_token_address: &EthAddress,
origin_network: u32,
scale: u8,
metadata_hash: MetadataHash,
) -> Account {
create_agglayer_faucet_builder(
seed,
token_symbol,
decimals,
max_supply,
token_supply,
bridge_account_id,
origin_token_address,
origin_network,
scale,
metadata_hash,
)
.with_auth_component(AccountComponent::from(NoAuth))
.build_existing()
.expect("agglayer faucet account should be valid")
}