/// Bridged Fungible Asset wrapper. /// /// A "bridge token" is an Aptos Fungible Asset (FA) whose `MintRef`, /// `BurnRef`, `TransferRef`, and `MutateMetadataRef` are stored inside the /// FA's own object address as a private `BridgeTokenRefs` resource. Only /// this module can borrow those refs, and the create/mint/burn/metadata /// entry points are `package`-visible, so the resource is effectively the /// bridge's exclusive minting and metadata capability for that token. module omni_bridge::bridge_token { use std::option; use std::string::{Self, String}; use aptos_framework::fungible_asset::{ Self, Metadata, MintRef, BurnRef, TransferRef, MutateMetadataRef }; use aptos_framework::object::{Self, Object}; use aptos_framework::primary_fungible_store; /// Per-token capability bundle. Keyed on the FA metadata object address. struct BridgeTokenRefs has key { mint_ref: MintRef, burn_ref: BurnRef, transfer_ref: TransferRef, /// Used to update mutable metadata (icon URI, project URI) after /// creation. Held by the bridge module so only `package`-visible /// functions can mutate. mutate_metadata_ref: MutateMetadataRef } /// Create a new bridge-controlled Fungible Asset and return its metadata /// object. `creator` must be a signer for an account that owns the new /// named object (the bridge module passes its resource-account signer). /// `seed` makes the address deterministic — the bridge uses /// `keccak256(near_token_id)` so the same `near_token_id` always maps to /// the same Aptos address. package fun create( creator: &signer, seed: vector, name: String, symbol: String, decimals: u8 ): Object { let constructor_ref = object::create_named_object(creator, seed); primary_fungible_store::create_primary_store_enabled_fungible_asset( &constructor_ref, option::none(), name, symbol, decimals, string::utf8(b""), string::utf8(b"") ); let mint_ref = fungible_asset::generate_mint_ref(&constructor_ref); let burn_ref = fungible_asset::generate_burn_ref(&constructor_ref); let transfer_ref = fungible_asset::generate_transfer_ref(&constructor_ref); let mutate_metadata_ref = fungible_asset::generate_mutate_metadata_ref(&constructor_ref); let object_signer = constructor_ref.generate_signer(); move_to( &object_signer, BridgeTokenRefs { mint_ref, burn_ref, transfer_ref, mutate_metadata_ref } ); constructor_ref.object_from_constructor_ref() } /// Mint `amount` of `metadata` directly into the recipient's primary store. package fun mint( metadata: Object, recipient: address, amount: u64 ) { let refs = &BridgeTokenRefs[metadata.object_address()]; let fa = refs.mint_ref.mint(amount); primary_fungible_store::deposit(recipient, fa); } /// Burn `amount` of `metadata` from `account`'s primary store. package fun burn( metadata: Object, account: address, amount: u64 ) { let refs = &BridgeTokenRefs[metadata.object_address()]; let store = primary_fungible_store::primary_store(account, metadata); refs.burn_ref.burn_from(store, amount); } /// True if `metadata` was deployed by this bridge. public fun is_bridge_token(metadata: Object): bool { exists(metadata.object_address()) } /// Update the FA's mutable metadata. Any `Option::None` argument is /// left unchanged. Bridge-only. package fun mutate_metadata( metadata: Object, icon_uri: option::Option, project_uri: option::Option ) { let refs = &BridgeTokenRefs[metadata.object_address()]; fungible_asset::mutate_metadata( &refs.mutate_metadata_ref, option::none(), // name option::none(), // symbol option::none(), // decimals icon_uri, project_uri ); } #[test_only] public fun test_create( creator: &signer, seed: vector, name: String, symbol: String, decimals: u8 ): Object { create(creator, seed, name, symbol, decimals) } #[test_only] public fun test_mint( metadata: Object, recipient: address, amount: u64 ) { mint(metadata, recipient, amount) } #[test_only] public fun test_burn( metadata: Object, account: address, amount: u64 ) { burn(metadata, account, amount) } }