fungible_asset - [mainnet]
This defines the fungible asset module that can issue fungible asset of any Metadata
object. The
metadata object can be any object that equipped with Metadata
resource.
use 0x1::aggregator_v2;use 0x1::create_signer;use 0x1::error;use 0x1::event;use 0x1::features;use 0x1::function_info;use 0x1::object;use 0x1::option;use 0x1::permissioned_signer;use 0x1::signer;use 0x1::string;
Constants
Maximum possible coin supply.
const MAX_U128: u128 = 340282366920938463463374607431768211455;
Trying to re-register dispatch hook on a fungible asset.
const EALREADY_REGISTERED: u64 = 29;
Amount cannot be zero.
const EAMOUNT_CANNOT_BE_ZERO: u64 = 1;
Cannot destroy non-empty fungible assets.
const EAMOUNT_IS_NOT_ZERO: u64 = 12;
Cannot register dispatch hook for APT.
const EAPT_NOT_DISPATCHABLE: u64 = 31;
Cannot destroy fungible stores with a non-zero balance.
const EBALANCE_IS_NOT_ZERO: u64 = 14;
Burn ref and fungible asset do not match.
const EBURN_REF_AND_FUNGIBLE_ASSET_MISMATCH: u64 = 13;
Burn ref and store do not match.
const EBURN_REF_AND_STORE_MISMATCH: u64 = 10;
Flag for Concurrent Supply not enabled
const ECONCURRENT_BALANCE_NOT_ENABLED: u64 = 32;
Flag for Concurrent Supply not enabled
const ECONCURRENT_SUPPLY_NOT_ENABLED: u64 = 22;
Decimals is over the maximum of 32
const EDECIMALS_TOO_LARGE: u64 = 17;
Provided deposit function type doesn’t meet the signature requirement.
const EDEPOSIT_FUNCTION_SIGNATURE_MISMATCH: u64 = 26;
Provided derived_balance function type doesn’t meet the signature requirement.
const EDERIVED_BALANCE_FUNCTION_SIGNATURE_MISMATCH: u64 = 27;
Provided derived_supply function type doesn’t meet the signature requirement.
const EDERIVED_SUPPLY_FUNCTION_SIGNATURE_MISMATCH: u64 = 33;
Fungible asset and store do not match.
const EFUNGIBLE_ASSET_AND_STORE_MISMATCH: u64 = 11;
Fungible asset do not match when merging.
const EFUNGIBLE_ASSET_MISMATCH: u64 = 6;
Fungible metadata does not exist on this account.
const EFUNGIBLE_METADATA_EXISTENCE: u64 = 30;
Flag for the existence of fungible store.
const EFUNGIBLE_STORE_EXISTENCE: u64 = 23;
Insufficient balance to withdraw or transfer.
const EINSUFFICIENT_BALANCE: u64 = 4;
Invalid withdraw/deposit on dispatchable token. The specified token has a dispatchable function hook. Need to invoke dispatchable_fungible_asset::withdraw/deposit to perform transfer.
const EINVALID_DISPATCHABLE_OPERATIONS: u64 = 28;
The fungible asset’s supply has exceeded maximum.
const EMAX_SUPPLY_EXCEEDED: u64 = 5;
The mint ref and the store do not match.
const EMINT_REF_AND_STORE_MISMATCH: u64 = 7;
Name of the fungible asset metadata is too long
const ENAME_TOO_LONG: u64 = 15;
Account is not the owner of metadata object.
const ENOT_METADATA_OWNER: u64 = 24;
Account is not the store’s owner.
const ENOT_STORE_OWNER: u64 = 8;
Fungibility is only available for non-deletable objects.
const EOBJECT_IS_DELETABLE: u64 = 18;
The balance ref and the fungible asset do not match.
const ERAW_BALANCE_REF_AND_FUNGIBLE_ASSET_MISMATCH: u64 = 34;
The supply ref and the fungible asset do not match.
const ERAW_SUPPLY_REF_AND_FUNGIBLE_ASSET_MISMATCH: u64 = 35;
Store is disabled from sending and receiving this fungible asset.
const ESTORE_IS_FROZEN: u64 = 3;
Supply resource is not found for a metadata object.
const ESUPPLY_NOT_FOUND: u64 = 21;
The fungible asset’s supply will be negative which should be impossible.
const ESUPPLY_UNDERFLOW: u64 = 20;
Symbol of the fungible asset metadata is too long
const ESYMBOL_TOO_LONG: u64 = 16;
The transfer ref and the fungible asset do not match.
const ETRANSFER_REF_AND_FUNGIBLE_ASSET_MISMATCH: u64 = 2;
Transfer ref and store do not match.
const ETRANSFER_REF_AND_STORE_MISMATCH: u64 = 9;
URI for the icon of the fungible asset metadata is too long
const EURI_TOO_LONG: u64 = 19;
Provided withdraw function type doesn’t meet the signature requirement.
const EWITHDRAW_FUNCTION_SIGNATURE_MISMATCH: u64 = 25;
signer don’t have the permission to perform withdraw operation
const EWITHDRAW_PERMISSION_DENIED: u64 = 36;
const MAX_DECIMALS: u8 = 32;
const MAX_NAME_LENGTH: u64 = 32;
const MAX_SYMBOL_LENGTH: u64 = 32;
const MAX_URI_LENGTH: u64 = 512;
Structs
FungibleAsset
FungibleAsset can be passed into function for type safety and to guarantee a specific amount. FungibleAsset is ephemeral and cannot be stored directly. It must be deposited back into a store.
struct FungibleAsset
Fields
-
metadata: object::Object<fungible_asset::Metadata>
-
amount: u64
MintRef
MintRef can be used to mint the fungible asset into an account’s store.
struct MintRef has drop, store
Fields
-
metadata: object::Object<fungible_asset::Metadata>
TransferRef
TransferRef can be used to allow or disallow the owner of fungible assets from transferring the asset and allow the holder of TransferRef to transfer fungible assets from any account.
struct TransferRef has drop, store
Fields
-
metadata: object::Object<fungible_asset::Metadata>
RawBalanceRef
RawBalanceRef will be used to access the raw balance for FAs that registered derived_balance
hook.
struct RawBalanceRef has drop, store
Fields
-
metadata: object::Object<fungible_asset::Metadata>
RawSupplyRef
RawSupplyRef will be used to access the raw supply for FAs that registered derived_supply
hook.
struct RawSupplyRef has drop, store
Fields
-
metadata: object::Object<fungible_asset::Metadata>
BurnRef
BurnRef can be used to burn fungible assets from a given holder account.
struct BurnRef has drop, store
Fields
-
metadata: object::Object<fungible_asset::Metadata>
MutateMetadataRef
MutateMetadataRef can be used to directly modify the fungible asset’s Metadata.
struct MutateMetadataRef has drop, store
Fields
-
metadata: object::Object<fungible_asset::Metadata>
Deposit
Emitted when fungible assets are deposited into a store.
#[event]struct Deposit has drop, store
Fields
-
store: address
-
amount: u64
Withdraw
Emitted when fungible assets are withdrawn from a store.
#[event]struct Withdraw has drop, store
Fields
-
store: address
-
amount: u64
Frozen
Emitted when a store’s frozen status is updated.
#[event]struct Frozen has drop, store
Fields
-
store: address
-
frozen: bool
FungibleStoreDeletion
Module event emitted when a fungible store is deleted.
#[event]struct FungibleStoreDeletion has drop, store
Fields
-
store: address
-
owner: address
-
metadata: address
DepositEvent
#[deprecated]struct DepositEvent has drop, store
Fields
-
amount: u64
WithdrawEvent
#[deprecated]struct WithdrawEvent has drop, store
Fields
-
amount: u64
FrozenEvent
#[deprecated]struct FrozenEvent has drop, store
Fields
-
frozen: bool
Resources
Supply
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]struct Supply has key
Fields
-
current: u128
-
maximum: option::Option<u128>
ConcurrentSupply
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]struct ConcurrentSupply has key
Fields
-
current: aggregator_v2::Aggregator<u128>
Metadata
Metadata of a Fungible asset
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]struct Metadata has copy, drop, key
Fields
-
name: string::String
- Name of the fungible metadata, i.e., "USDT".
-
symbol: string::String
- Symbol of the fungible metadata, usually a shorter version of the name. For example, Singapore Dollar is SGD.
-
decimals: u8
-
Number of decimals used for display purposes.
For example, if
decimals
equals2
, a balance of505
coins should be displayed to a user as5.05
(505 / 10 ** 2
). -
icon_uri: string::String
- The Uniform Resource Identifier (uri) pointing to an image that can be used as the icon for this fungible asset.
-
project_uri: string::String
- The Uniform Resource Identifier (uri) pointing to the website for the fungible asset.
Untransferable
Defines a FungibleAsset
, such that all FungibleStore
s stores are untransferable at
the object layer.
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]struct Untransferable has key
Fields
-
dummy_field: bool
FungibleStore
The store object that holds fungible assets of a specific type associated with an account.
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]struct FungibleStore has key
Fields
-
metadata: object::Object<fungible_asset::Metadata>
- The address of the base metadata object.
-
balance: u64
- The balance of the fungible metadata.
-
frozen: bool
-
If true, owner transfer is disabled that only
TransferRef
can move in/out from this store.
DispatchFunctionStore
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]struct DispatchFunctionStore has key
Fields
-
withdraw_function: option::Option<function_info::FunctionInfo>
-
deposit_function: option::Option<function_info::FunctionInfo>
-
derived_balance_function: option::Option<function_info::FunctionInfo>
DeriveSupply
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]struct DeriveSupply has key
Fields
-
dispatch_function: option::Option<function_info::FunctionInfo>
ConcurrentFungibleBalance
The store object that holds concurrent fungible asset balance.
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]struct ConcurrentFungibleBalance has key
Fields
-
balance: aggregator_v2::Aggregator<u64>
- The balance of the fungible metadata.
FungibleAssetEvents
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]#[deprecated]struct FungibleAssetEvents has key
Fields
-
deposit_events: event::EventHandle<fungible_asset::DepositEvent>
-
withdraw_events: event::EventHandle<fungible_asset::WithdrawEvent>
-
frozen_events: event::EventHandle<fungible_asset::FrozenEvent>
Functions
default_to_concurrent_fungible_supply
fun default_to_concurrent_fungible_supply(): bool
Implementation
inline fun default_to_concurrent_fungible_supply(): bool { features::concurrent_fungible_assets_enabled()}
allow_upgrade_to_concurrent_fungible_balance
fun allow_upgrade_to_concurrent_fungible_balance(): bool
Implementation
inline fun allow_upgrade_to_concurrent_fungible_balance(): bool { features::concurrent_fungible_balance_enabled()}
default_to_concurrent_fungible_balance
fun default_to_concurrent_fungible_balance(): bool
Implementation
inline fun default_to_concurrent_fungible_balance(): bool { features::default_to_concurrent_fungible_balance_enabled()}
add_fungibility
Make an existing object fungible by adding the Metadata resource. This returns the capabilities to mint, burn, and transfer. maximum_supply defines the behavior of maximum supply when monitoring:
- option::none(): Monitoring unlimited supply (width of the field - MAX_U128 is the implicit maximum supply) if option::some(MAX_U128) is used, it is treated as unlimited supply.
- option::some(max): Monitoring fixed supply with
max
as the maximum supply.
public fun add_fungibility(constructor_ref: &object::ConstructorRef, maximum_supply: option::Option<u128>, name: string::String, symbol: string::String, decimals: u8, icon_uri: string::String, project_uri: string::String): object::Object<fungible_asset::Metadata>
Implementation
public fun add_fungibility( constructor_ref: &ConstructorRef, maximum_supply: Option<u128>, name: String, symbol: String, decimals: u8, icon_uri: String, project_uri: String,): Object<Metadata> { assert!(!object::can_generate_delete_ref(constructor_ref), error::invalid_argument(EOBJECT_IS_DELETABLE)); let metadata_object_signer = &object::generate_signer(constructor_ref); assert!(string::length(&name) <= MAX_NAME_LENGTH, error::out_of_range(ENAME_TOO_LONG)); assert!(string::length(&symbol) <= MAX_SYMBOL_LENGTH, error::out_of_range(ESYMBOL_TOO_LONG)); assert!(decimals <= MAX_DECIMALS, error::out_of_range(EDECIMALS_TOO_LARGE)); assert!(string::length(&icon_uri) <= MAX_URI_LENGTH, error::out_of_range(EURI_TOO_LONG)); assert!(string::length(&project_uri) <= MAX_URI_LENGTH, error::out_of_range(EURI_TOO_LONG)); move_to(metadata_object_signer, Metadata { name, symbol, decimals, icon_uri, project_uri, } );
if (default_to_concurrent_fungible_supply()) { let unlimited = option::is_none(&maximum_supply); move_to(metadata_object_signer, ConcurrentSupply { current: if (unlimited) { aggregator_v2::create_unbounded_aggregator() } else { aggregator_v2::create_aggregator(option::extract(&mut maximum_supply)) }, }); } else { move_to(metadata_object_signer, Supply { current: 0, maximum: maximum_supply }); };
object::object_from_constructor_ref<Metadata>(constructor_ref)}
set_untransferable
Set that only untransferable stores can be created for this fungible asset.
public fun set_untransferable(constructor_ref: &object::ConstructorRef)
Implementation
public fun set_untransferable(constructor_ref: &ConstructorRef) { let metadata_addr = object::address_from_constructor_ref(constructor_ref); assert!(exists<Metadata>(metadata_addr), error::not_found(EFUNGIBLE_METADATA_EXISTENCE)); let metadata_signer = &object::generate_signer(constructor_ref); move_to(metadata_signer, Untransferable {});}
is_untransferable
Returns true if the FA is untransferable.
#[view]public fun is_untransferable<T: key>(metadata: object::Object<T>): bool
Implementation
public fun is_untransferable<T: key>(metadata: Object<T>): bool { exists<Untransferable>(object::object_address(&metadata))}
register_dispatch_functions
Create a fungible asset store whose transfer rule would be overloaded by the provided function.
public(friend) fun register_dispatch_functions(constructor_ref: &object::ConstructorRef, withdraw_function: option::Option<function_info::FunctionInfo>, deposit_function: option::Option<function_info::FunctionInfo>, derived_balance_function: option::Option<function_info::FunctionInfo>)
Implementation
public(friend) fun register_dispatch_functions( constructor_ref: &ConstructorRef, withdraw_function: Option<FunctionInfo>, deposit_function: Option<FunctionInfo>, derived_balance_function: Option<FunctionInfo>,) { // Verify that caller type matches callee type so wrongly typed function cannot be registered. option::for_each_ref(&withdraw_function, |withdraw_function| { let dispatcher_withdraw_function_info = function_info::new_function_info_from_address( @aptos_framework, string::utf8(b"dispatchable_fungible_asset"), string::utf8(b"dispatchable_withdraw"), );
assert!( function_info::check_dispatch_type_compatibility( &dispatcher_withdraw_function_info, withdraw_function ), error::invalid_argument( EWITHDRAW_FUNCTION_SIGNATURE_MISMATCH ) ); });
option::for_each_ref(&deposit_function, |deposit_function| { let dispatcher_deposit_function_info = function_info::new_function_info_from_address( @aptos_framework, string::utf8(b"dispatchable_fungible_asset"), string::utf8(b"dispatchable_deposit"), ); // Verify that caller type matches callee type so wrongly typed function cannot be registered. assert!( function_info::check_dispatch_type_compatibility( &dispatcher_deposit_function_info, deposit_function ), error::invalid_argument( EDEPOSIT_FUNCTION_SIGNATURE_MISMATCH ) ); });
option::for_each_ref(&derived_balance_function, |balance_function| { let dispatcher_derived_balance_function_info = function_info::new_function_info_from_address( @aptos_framework, string::utf8(b"dispatchable_fungible_asset"), string::utf8(b"dispatchable_derived_balance"), ); // Verify that caller type matches callee type so wrongly typed function cannot be registered. assert!( function_info::check_dispatch_type_compatibility( &dispatcher_derived_balance_function_info, balance_function ), error::invalid_argument( EDERIVED_BALANCE_FUNCTION_SIGNATURE_MISMATCH ) ); }); register_dispatch_function_sanity_check(constructor_ref); assert!( !exists<DispatchFunctionStore>( object::address_from_constructor_ref(constructor_ref) ), error::already_exists(EALREADY_REGISTERED) );
let store_obj = &object::generate_signer(constructor_ref);
// Store the overload function hook. move_to<DispatchFunctionStore>( store_obj, DispatchFunctionStore { withdraw_function, deposit_function, derived_balance_function, } );}
register_derive_supply_dispatch_function
Define the derived supply dispatch with the provided function.
public(friend) fun register_derive_supply_dispatch_function(constructor_ref: &object::ConstructorRef, dispatch_function: option::Option<function_info::FunctionInfo>)
Implementation
public(friend) fun register_derive_supply_dispatch_function( constructor_ref: &ConstructorRef, dispatch_function: Option<FunctionInfo>) { // Verify that caller type matches callee type so wrongly typed function cannot be registered. option::for_each_ref(&dispatch_function, |supply_function| { let function_info = function_info::new_function_info_from_address( @aptos_framework, string::utf8(b"dispatchable_fungible_asset"), string::utf8(b"dispatchable_derived_supply"), ); // Verify that caller type matches callee type so wrongly typed function cannot be registered. assert!( function_info::check_dispatch_type_compatibility( &function_info, supply_function ), error::invalid_argument( EDERIVED_SUPPLY_FUNCTION_SIGNATURE_MISMATCH ) ); }); register_dispatch_function_sanity_check(constructor_ref); assert!( !exists<DeriveSupply>( object::address_from_constructor_ref(constructor_ref) ), error::already_exists(EALREADY_REGISTERED) );
let store_obj = &object::generate_signer(constructor_ref);
// Store the overload function hook. move_to<DeriveSupply>( store_obj, DeriveSupply { dispatch_function } );}
register_dispatch_function_sanity_check
Check the requirements for registering a dispatchable function.
fun register_dispatch_function_sanity_check(constructor_ref: &object::ConstructorRef)
Implementation
inline fun register_dispatch_function_sanity_check( constructor_ref: &ConstructorRef,) { // Cannot register hook for APT. assert!( object::address_from_constructor_ref(constructor_ref) != @aptos_fungible_asset, error::permission_denied(EAPT_NOT_DISPATCHABLE) ); assert!( !object::can_generate_delete_ref(constructor_ref), error::invalid_argument(EOBJECT_IS_DELETABLE) ); assert!( exists<Metadata>( object::address_from_constructor_ref(constructor_ref) ), error::not_found(EFUNGIBLE_METADATA_EXISTENCE), );}
generate_mint_ref
Creates a mint ref that can be used to mint fungible assets from the given fungible object’s constructor ref. This can only be called at object creation time as constructor_ref is only available then.
public fun generate_mint_ref(constructor_ref: &object::ConstructorRef): fungible_asset::MintRef
Implementation
public fun generate_mint_ref(constructor_ref: &ConstructorRef): MintRef { let metadata = object::object_from_constructor_ref<Metadata>(constructor_ref); MintRef { metadata }}
generate_burn_ref
Creates a burn ref that can be used to burn fungible assets from the given fungible object’s constructor ref. This can only be called at object creation time as constructor_ref is only available then.
public fun generate_burn_ref(constructor_ref: &object::ConstructorRef): fungible_asset::BurnRef
Implementation
public fun generate_burn_ref(constructor_ref: &ConstructorRef): BurnRef { let metadata = object::object_from_constructor_ref<Metadata>(constructor_ref); BurnRef { metadata }}
generate_transfer_ref
Creates a transfer ref that can be used to freeze/unfreeze/transfer fungible assets from the given fungible object’s constructor ref. This can only be called at object creation time as constructor_ref is only available then.
public fun generate_transfer_ref(constructor_ref: &object::ConstructorRef): fungible_asset::TransferRef
Implementation
public fun generate_transfer_ref(constructor_ref: &ConstructorRef): TransferRef { let metadata = object::object_from_constructor_ref<Metadata>(constructor_ref); TransferRef { metadata }}
generate_raw_balance_ref
Creates a balance ref that can be used to access raw balance of fungible assets from the given fungible object’s constructor ref. This can only be called at object creation time as constructor_ref is only available then.
public fun generate_raw_balance_ref(constructor_ref: &object::ConstructorRef): fungible_asset::RawBalanceRef
Implementation
public fun generate_raw_balance_ref(constructor_ref: &ConstructorRef): RawBalanceRef { let metadata = object::object_from_constructor_ref<Metadata>(constructor_ref); RawBalanceRef { metadata }}
generate_raw_supply_ref
Creates a supply ref that can be used to access raw supply of fungible assets from the given fungible object’s constructor ref. This can only be called at object creation time as constructor_ref is only available then.
public fun generate_raw_supply_ref(constructor_ref: &object::ConstructorRef): fungible_asset::RawSupplyRef
Implementation
public fun generate_raw_supply_ref(constructor_ref: &ConstructorRef): RawSupplyRef { let metadata = object::object_from_constructor_ref<Metadata>(constructor_ref); RawSupplyRef { metadata }}
generate_mutate_metadata_ref
Creates a mutate metadata ref that can be used to change the metadata information of fungible assets from the given fungible object’s constructor ref. This can only be called at object creation time as constructor_ref is only available then.
public fun generate_mutate_metadata_ref(constructor_ref: &object::ConstructorRef): fungible_asset::MutateMetadataRef
Implementation
public fun generate_mutate_metadata_ref(constructor_ref: &ConstructorRef): MutateMetadataRef { let metadata = object::object_from_constructor_ref<Metadata>(constructor_ref); MutateMetadataRef { metadata }}
supply
Get the current supply from the metadata
object.
Note: This function will abort on FAs with derived_supply
hook set up.
Use dispatchable_fungible_asset::supply
instead if you intend to work with those FAs.
#[view]public fun supply<T: key>(metadata: object::Object<T>): option::Option<u128>
Implementation
public fun supply<T: key>(metadata: Object<T>): Option<u128> acquires Supply, ConcurrentSupply { assert!( !has_supply_dispatch_function(object::object_address(&metadata)), error::invalid_argument(EINVALID_DISPATCHABLE_OPERATIONS) ); supply_impl(metadata)}
supply_impl
fun supply_impl<T: key>(metadata: object::Object<T>): option::Option<u128>
Implementation
fun supply_impl<T: key>(metadata: Object<T>): Option<u128> acquires Supply, ConcurrentSupply { let metadata_address = object::object_address(&metadata); if (exists<ConcurrentSupply>(metadata_address)) { let supply = borrow_global<ConcurrentSupply>(metadata_address); option::some(supply.current.read()) } else if (exists<Supply>(metadata_address)) { let supply = borrow_global<Supply>(metadata_address); option::some(supply.current) } else { option::none() }}
maximum
Get the maximum supply from the metadata
object.
If supply is unlimited (or set explicitly to MAX_U128), none is returned
#[view]public fun maximum<T: key>(metadata: object::Object<T>): option::Option<u128>
Implementation
public fun maximum<T: key>(metadata: Object<T>): Option<u128> acquires Supply, ConcurrentSupply { let metadata_address = object::object_address(&metadata); if (exists<ConcurrentSupply>(metadata_address)) { let supply = borrow_global<ConcurrentSupply>(metadata_address); let max_value = supply.current.max_value(); if (max_value == MAX_U128) { option::none() } else { option::some(max_value) } } else if (exists<Supply>(metadata_address)) { let supply = borrow_global<Supply>(metadata_address); supply.maximum } else { option::none() }}
name
Get the name of the fungible asset from the metadata
object.
#[view]public fun name<T: key>(metadata: object::Object<T>): string::String
Implementation
public fun name<T: key>(metadata: Object<T>): String acquires Metadata { borrow_fungible_metadata(&metadata).name}
symbol
Get the symbol of the fungible asset from the metadata
object.
#[view]public fun symbol<T: key>(metadata: object::Object<T>): string::String
Implementation
public fun symbol<T: key>(metadata: Object<T>): String acquires Metadata { borrow_fungible_metadata(&metadata).symbol}
decimals
Get the decimals from the metadata
object.
#[view]public fun decimals<T: key>(metadata: object::Object<T>): u8
Implementation
public fun decimals<T: key>(metadata: Object<T>): u8 acquires Metadata { borrow_fungible_metadata(&metadata).decimals}
icon_uri
Get the icon uri from the metadata
object.
#[view]public fun icon_uri<T: key>(metadata: object::Object<T>): string::String
Implementation
public fun icon_uri<T: key>(metadata: Object<T>): String acquires Metadata { borrow_fungible_metadata(&metadata).icon_uri}
project_uri
Get the project uri from the metadata
object.
#[view]public fun project_uri<T: key>(metadata: object::Object<T>): string::String
Implementation
public fun project_uri<T: key>(metadata: Object<T>): String acquires Metadata { borrow_fungible_metadata(&metadata).project_uri}
metadata
Get the metadata struct from the metadata
object.
#[view]public fun metadata<T: key>(metadata: object::Object<T>): fungible_asset::Metadata
Implementation
public fun metadata<T: key>(metadata: Object<T>): Metadata acquires Metadata { *borrow_fungible_metadata(&metadata)}
store_exists
Return whether the provided address has a store initialized.
#[view]public fun store_exists(store: address): bool
Implementation
public fun store_exists(store: address): bool { store_exists_inline(store)}
store_exists_inline
Return whether the provided address has a store initialized.
fun store_exists_inline(store: address): bool
Implementation
inline fun store_exists_inline(store: address): bool { exists<FungibleStore>(store)}
concurrent_fungible_balance_exists_inline
Return whether the provided address has a concurrent fungible balance initialized, at the fungible store address.
fun concurrent_fungible_balance_exists_inline(store: address): bool
Implementation
inline fun concurrent_fungible_balance_exists_inline(store: address): bool { exists<ConcurrentFungibleBalance>(store)}
metadata_from_asset
Return the underlying metadata object
public fun metadata_from_asset(fa: &fungible_asset::FungibleAsset): object::Object<fungible_asset::Metadata>
Implementation
public fun metadata_from_asset(fa: &FungibleAsset): Object<Metadata> { fa.metadata}
store_metadata
Return the underlying metadata object.
#[view]public fun store_metadata<T: key>(store: object::Object<T>): object::Object<fungible_asset::Metadata>
Implementation
public fun store_metadata<T: key>(store: Object<T>): Object<Metadata> acquires FungibleStore { borrow_store_resource(&store).metadata}
amount
Return the amount
of a given fungible asset.
public fun amount(fa: &fungible_asset::FungibleAsset): u64
Implementation
public fun amount(fa: &FungibleAsset): u64 { fa.amount}
balance
Get the balance of a given store.
Note: This function will abort on FAs with derived_balance
hook set up.
Use dispatchable_fungible_asset::balance
instead if you intend to work with those FAs.
#[view]public fun balance<T: key>(store: object::Object<T>): u64
Implementation
public fun balance<T: key>(store: Object<T>): u64 acquires FungibleStore, ConcurrentFungibleBalance, DispatchFunctionStore { let fa_store = borrow_store_resource(&store); assert!( !has_balance_dispatch_function(fa_store.metadata), error::invalid_argument(EINVALID_DISPATCHABLE_OPERATIONS) ); balance_impl(store)}
balance_impl
fun balance_impl<T: key>(store: object::Object<T>): u64
Implementation
fun balance_impl<T: key>(store: Object<T>): u64 acquires FungibleStore, ConcurrentFungibleBalance { let store_addr = object::object_address(&store); if (store_exists_inline(store_addr)) { let store_balance = borrow_store_resource(&store).balance; if (store_balance == 0 && concurrent_fungible_balance_exists_inline(store_addr)) { let balance_resource = borrow_global<ConcurrentFungibleBalance>(store_addr); balance_resource.balance.read() } else { store_balance } } else { 0 }}
is_balance_at_least
Check whether the balance of a given store is >= amount
.
#[view]public fun is_balance_at_least<T: key>(store: object::Object<T>, amount: u64): bool
Implementation
public fun is_balance_at_least<T: key>(store: Object<T>, amount: u64): bool acquires FungibleStore, ConcurrentFungibleBalance { let store_addr = object::object_address(&store); is_address_balance_at_least(store_addr, amount)}
is_address_balance_at_least
Check whether the balance of a given store is >= amount
.
public(friend) fun is_address_balance_at_least(store_addr: address, amount: u64): bool
Implementation
public(friend) fun is_address_balance_at_least(store_addr: address, amount: u64): bool acquires FungibleStore, ConcurrentFungibleBalance { if (store_exists_inline(store_addr)) { let store_balance = borrow_global<FungibleStore>(store_addr).balance; if (store_balance == 0 && concurrent_fungible_balance_exists_inline(store_addr)) { let balance_resource = borrow_global<ConcurrentFungibleBalance>(store_addr); balance_resource.balance.is_at_least(amount) } else { store_balance >= amount } } else { amount == 0 }}
is_frozen
Return whether a store is frozen.
If the store has not been created, we default to returning false so deposits can be sent to it.
#[view]public fun is_frozen<T: key>(store: object::Object<T>): bool
Implementation
public fun is_frozen<T: key>(store: Object<T>): bool acquires FungibleStore { let store_addr = object::object_address(&store); store_exists_inline(store_addr) && borrow_global<FungibleStore>(store_addr).frozen}
is_store_dispatchable
Return whether a fungible asset type is dispatchable.
#[view]public fun is_store_dispatchable<T: key>(store: object::Object<T>): bool
Implementation
public fun is_store_dispatchable<T: key>(store: Object<T>): bool acquires FungibleStore { let fa_store = borrow_store_resource(&store); let metadata_addr = object::object_address(&fa_store.metadata); exists<DispatchFunctionStore>(metadata_addr)}
deposit_dispatch_function
public fun deposit_dispatch_function<T: key>(store: object::Object<T>): option::Option<function_info::FunctionInfo>
Implementation
public fun deposit_dispatch_function<T: key>(store: Object<T>): Option<FunctionInfo> acquires FungibleStore, DispatchFunctionStore { let fa_store = borrow_store_resource(&store); let metadata_addr = object::object_address(&fa_store.metadata); if(exists<DispatchFunctionStore>(metadata_addr)) { borrow_global<DispatchFunctionStore>(metadata_addr).deposit_function } else { option::none() }}
has_deposit_dispatch_function
fun has_deposit_dispatch_function(metadata: object::Object<fungible_asset::Metadata>): bool
Implementation
fun has_deposit_dispatch_function(metadata: Object<Metadata>): bool acquires DispatchFunctionStore { let metadata_addr = object::object_address(&metadata); // Short circuit on APT for better perf if(metadata_addr != @aptos_fungible_asset && exists<DispatchFunctionStore>(metadata_addr)) { option::is_some(&borrow_global<DispatchFunctionStore>(metadata_addr).deposit_function) } else { false }}
withdraw_dispatch_function
public fun withdraw_dispatch_function<T: key>(store: object::Object<T>): option::Option<function_info::FunctionInfo>
Implementation
public fun withdraw_dispatch_function<T: key>(store: Object<T>): Option<FunctionInfo> acquires FungibleStore, DispatchFunctionStore { let fa_store = borrow_store_resource(&store); let metadata_addr = object::object_address(&fa_store.metadata); if(exists<DispatchFunctionStore>(metadata_addr)) { borrow_global<DispatchFunctionStore>(metadata_addr).withdraw_function } else { option::none() }}
has_withdraw_dispatch_function
fun has_withdraw_dispatch_function(metadata: object::Object<fungible_asset::Metadata>): bool
Implementation
fun has_withdraw_dispatch_function(metadata: Object<Metadata>): bool acquires DispatchFunctionStore { let metadata_addr = object::object_address(&metadata); // Short circuit on APT for better perf if (metadata_addr != @aptos_fungible_asset && exists<DispatchFunctionStore>(metadata_addr)) { option::is_some(&borrow_global<DispatchFunctionStore>(metadata_addr).withdraw_function) } else { false }}
has_balance_dispatch_function
fun has_balance_dispatch_function(metadata: object::Object<fungible_asset::Metadata>): bool
Implementation
fun has_balance_dispatch_function(metadata: Object<Metadata>): bool acquires DispatchFunctionStore { let metadata_addr = object::object_address(&metadata); // Short circuit on APT for better perf if (metadata_addr != @aptos_fungible_asset && exists<DispatchFunctionStore>(metadata_addr)) { option::is_some(&borrow_global<DispatchFunctionStore>(metadata_addr).derived_balance_function) } else { false }}
has_supply_dispatch_function
fun has_supply_dispatch_function(metadata_addr: address): bool
Implementation
fun has_supply_dispatch_function(metadata_addr: address): bool { // Short circuit on APT for better perf if (metadata_addr != @aptos_fungible_asset) { exists<DeriveSupply>(metadata_addr) } else { false }}
derived_balance_dispatch_function
public(friend) fun derived_balance_dispatch_function<T: key>(store: object::Object<T>): option::Option<function_info::FunctionInfo>
Implementation
public(friend) fun derived_balance_dispatch_function<T: key>(store: Object<T>): Option<FunctionInfo> acquires FungibleStore, DispatchFunctionStore { let fa_store = borrow_store_resource(&store); let metadata_addr = object::object_address(&fa_store.metadata); if (exists<DispatchFunctionStore>(metadata_addr)) { borrow_global<DispatchFunctionStore>(metadata_addr).derived_balance_function } else { option::none() }}
derived_supply_dispatch_function
public(friend) fun derived_supply_dispatch_function<T: key>(metadata: object::Object<T>): option::Option<function_info::FunctionInfo>
Implementation
public(friend) fun derived_supply_dispatch_function<T: key>(metadata: Object<T>): Option<FunctionInfo> acquires DeriveSupply { let metadata_addr = object::object_address(&metadata); if (exists<DeriveSupply>(metadata_addr)) { borrow_global<DeriveSupply>(metadata_addr).dispatch_function } else { option::none() }}
asset_metadata
public fun asset_metadata(fa: &fungible_asset::FungibleAsset): object::Object<fungible_asset::Metadata>
Implementation
public fun asset_metadata(fa: &FungibleAsset): Object<Metadata> { fa.metadata}
mint_ref_metadata
Get the underlying metadata object from the MintRef
.
public fun mint_ref_metadata(ref: &fungible_asset::MintRef): object::Object<fungible_asset::Metadata>
Implementation
public fun mint_ref_metadata(ref: &MintRef): Object<Metadata> { ref.metadata}
transfer_ref_metadata
Get the underlying metadata object from the TransferRef
.
public fun transfer_ref_metadata(ref: &fungible_asset::TransferRef): object::Object<fungible_asset::Metadata>
Implementation
public fun transfer_ref_metadata(ref: &TransferRef): Object<Metadata> { ref.metadata}
burn_ref_metadata
Get the underlying metadata object from the BurnRef
.
public fun burn_ref_metadata(ref: &fungible_asset::BurnRef): object::Object<fungible_asset::Metadata>
Implementation
public fun burn_ref_metadata(ref: &BurnRef): Object<Metadata> { ref.metadata}
object_from_metadata_ref
Get the underlying metadata object from the MutateMetadataRef
.
public fun object_from_metadata_ref(ref: &fungible_asset::MutateMetadataRef): object::Object<fungible_asset::Metadata>
Implementation
public fun object_from_metadata_ref(ref: &MutateMetadataRef): Object<Metadata> { ref.metadata}
transfer
Transfer an amount
of fungible asset from from_store
, which should be owned by sender
, to receiver
.
Note: it does not move the underlying object.
This function can be in-place replaced by dispatchable_fungible_asset::transfer
. You should use
that function unless you DO NOT want to support fungible assets with dispatchable hooks.
public entry fun transfer<T: key>(sender: &signer, from: object::Object<T>, to: object::Object<T>, amount: u64)
Implementation
public entry fun transfer<T: key>( sender: &signer, from: Object<T>, to: Object<T>, amount: u64,) acquires FungibleStore, DispatchFunctionStore, ConcurrentFungibleBalance { let fa = withdraw(sender, from, amount); deposit(to, fa);}
create_store
Allow an object to hold a store for fungible assets. Applications can use this to create multiple stores for isolating fungible assets for different purposes.
public fun create_store<T: key>(constructor_ref: &object::ConstructorRef, metadata: object::Object<T>): object::Object<fungible_asset::FungibleStore>
Implementation
public fun create_store<T: key>( constructor_ref: &ConstructorRef, metadata: Object<T>,): Object<FungibleStore> { let store_obj = &object::generate_signer(constructor_ref); move_to(store_obj, FungibleStore { metadata: object::convert(metadata), balance: 0, frozen: false, });
if (is_untransferable(metadata)) { object::set_untransferable(constructor_ref); };
if (default_to_concurrent_fungible_balance()) { move_to(store_obj, ConcurrentFungibleBalance { balance: aggregator_v2::create_unbounded_aggregator(), }); };
object::object_from_constructor_ref<FungibleStore>(constructor_ref)}
remove_store
Used to delete a store. Requires the store to be completely empty prior to removing it
public fun remove_store(delete_ref: &object::DeleteRef)
Implementation
public fun remove_store(delete_ref: &DeleteRef) acquires FungibleStore, FungibleAssetEvents, ConcurrentFungibleBalance { let store = object::object_from_delete_ref<FungibleStore>(delete_ref); let addr = object::object_address(&store); let FungibleStore { metadata, balance, frozen: _} = move_from<FungibleStore>(addr); assert!(balance == 0, error::permission_denied(EBALANCE_IS_NOT_ZERO));
if (concurrent_fungible_balance_exists_inline(addr)) { let ConcurrentFungibleBalance { balance } = move_from<ConcurrentFungibleBalance>(addr); assert!(balance.read() == 0, error::permission_denied(EBALANCE_IS_NOT_ZERO)); };
// Cleanup deprecated event handles if exist. if (exists<FungibleAssetEvents>(addr)) { let FungibleAssetEvents { deposit_events, withdraw_events, frozen_events, } = move_from<FungibleAssetEvents>(addr); event::destroy_handle(deposit_events); event::destroy_handle(withdraw_events); event::destroy_handle(frozen_events); }; event::emit(FungibleStoreDeletion { store: addr, owner: object::owner(store), metadata: object::object_address(&metadata), });}
withdraw
Withdraw amount
of the fungible asset from store
by the owner.
Note: This function can be in-place replaced by dispatchable_fungible_asset::withdraw
. You should use
that function unless you DO NOT want to support fungible assets with dispatchable hooks.
public fun withdraw<T: key>(owner: &signer, store: object::Object<T>, amount: u64): fungible_asset::FungibleAsset
Implementation
public fun withdraw<T: key>( owner: &signer, store: Object<T>, amount: u64,): FungibleAsset acquires FungibleStore, DispatchFunctionStore, ConcurrentFungibleBalance { withdraw_sanity_check(owner, store, true); withdraw_permission_check(owner, store, amount); unchecked_withdraw(object::object_address(&store), amount)}
withdraw_permission_check
Check the permission for withdraw operation.
public(friend) fun withdraw_permission_check<T: key>(owner: &signer, store: object::Object<T>, amount: u64)
Implementation
public(friend) fun withdraw_permission_check<T: key>( owner: &signer, store: Object<T>, amount: u64,) { assert!(permissioned_signer::check_permission_consume(owner, amount as u256, WithdrawPermission::ByStore { store_address: object::object_address(&store), }), error::permission_denied(EWITHDRAW_PERMISSION_DENIED));}
withdraw_permission_check_by_address
Check the permission for withdraw operation.
public(friend) fun withdraw_permission_check_by_address(owner: &signer, store_address: address, amount: u64)
Implementation
public(friend) fun withdraw_permission_check_by_address( owner: &signer, store_address: address, amount: u64,) { assert!(permissioned_signer::check_permission_consume(owner, amount as u256, WithdrawPermission::ByStore { store_address, }), error::permission_denied(EWITHDRAW_PERMISSION_DENIED));}
withdraw_sanity_check
Check the permission for withdraw operation.
public(friend) fun withdraw_sanity_check<T: key>(owner: &signer, store: object::Object<T>, abort_on_dispatch: bool)
Implementation
public(friend) fun withdraw_sanity_check<T: key>( owner: &signer, store: Object<T>, abort_on_dispatch: bool,) acquires FungibleStore, DispatchFunctionStore { withdraw_sanity_check_impl( signer::address_of(owner), store, abort_on_dispatch, )}
withdraw_sanity_check_impl
fun withdraw_sanity_check_impl<T: key>(owner_address: address, store: object::Object<T>, abort_on_dispatch: bool)
Implementation
inline fun withdraw_sanity_check_impl<T: key>( owner_address: address, store: Object<T>, abort_on_dispatch: bool,) acquires FungibleStore, DispatchFunctionStore { assert!(object::owns(store, owner_address), error::permission_denied(ENOT_STORE_OWNER)); let fa_store = borrow_store_resource(&store); assert!( !abort_on_dispatch || !has_withdraw_dispatch_function(fa_store.metadata), error::invalid_argument(EINVALID_DISPATCHABLE_OPERATIONS) ); assert!(!fa_store.frozen, error::permission_denied(ESTORE_IS_FROZEN));}
deposit_sanity_check
Deposit amount
of the fungible asset to store
.
public fun deposit_sanity_check<T: key>(store: object::Object<T>, abort_on_dispatch: bool)
Implementation
public fun deposit_sanity_check<T: key>( store: Object<T>, abort_on_dispatch: bool) acquires FungibleStore, DispatchFunctionStore { let fa_store = borrow_store_resource(&store); assert!( !abort_on_dispatch || !has_deposit_dispatch_function(fa_store.metadata), error::invalid_argument(EINVALID_DISPATCHABLE_OPERATIONS) ); assert!(!fa_store.frozen, error::permission_denied(ESTORE_IS_FROZEN));}
deposit
Deposit amount
of the fungible asset to store
.
Note: This function can be in-place replaced by dispatchable_fungible_asset::deposit
. You should use
that function unless you DO NOT want to support fungible assets with dispatchable hooks.
public fun deposit<T: key>(store: object::Object<T>, fa: fungible_asset::FungibleAsset)
Implementation
public fun deposit<T: key>(store: Object<T>, fa: FungibleAsset) acquires FungibleStore, DispatchFunctionStore, ConcurrentFungibleBalance { deposit_sanity_check(store, true); unchecked_deposit(object::object_address(&store), fa);}
mint
Mint the specified amount
of the fungible asset.
public fun mint(ref: &fungible_asset::MintRef, amount: u64): fungible_asset::FungibleAsset
Implementation
public fun mint(ref: &MintRef, amount: u64): FungibleAsset acquires Supply, ConcurrentSupply { let metadata = ref.metadata; mint_internal(metadata, amount)}
mint_internal
CAN ONLY BE CALLED BY coin.move for migration.
public(friend) fun mint_internal(metadata: object::Object<fungible_asset::Metadata>, amount: u64): fungible_asset::FungibleAsset
Implementation
public(friend) fun mint_internal( metadata: Object<Metadata>, amount: u64): FungibleAsset acquires Supply, ConcurrentSupply { increase_supply(&metadata, amount); FungibleAsset { metadata, amount }}
mint_to
Mint the specified amount
of the fungible asset to a destination store.
public fun mint_to<T: key>(ref: &fungible_asset::MintRef, store: object::Object<T>, amount: u64)
Implementation
public fun mint_to<T: key>(ref: &MintRef, store: Object<T>, amount: u64)acquires FungibleStore, Supply, ConcurrentSupply, DispatchFunctionStore, ConcurrentFungibleBalance { deposit_sanity_check(store, false); unchecked_deposit(object::object_address(&store), mint(ref, amount));}
set_frozen_flag
Enable/disable a store’s ability to do direct transfers of the fungible asset.
public fun set_frozen_flag<T: key>(ref: &fungible_asset::TransferRef, store: object::Object<T>, frozen: bool)
Implementation
public fun set_frozen_flag<T: key>( ref: &TransferRef, store: Object<T>, frozen: bool,) acquires FungibleStore { assert!( ref.metadata == store_metadata(store), error::invalid_argument(ETRANSFER_REF_AND_STORE_MISMATCH), ); set_frozen_flag_internal(store, frozen)}
set_frozen_flag_internal
public(friend) fun set_frozen_flag_internal<T: key>(store: object::Object<T>, frozen: bool)
Implementation
public(friend) fun set_frozen_flag_internal<T: key>( store: Object<T>, frozen: bool) acquires FungibleStore { let store_addr = object::object_address(&store); borrow_global_mut<FungibleStore>(store_addr).frozen = frozen;
event::emit(Frozen { store: store_addr, frozen });}
burn
Burns a fungible asset
public fun burn(ref: &fungible_asset::BurnRef, fa: fungible_asset::FungibleAsset)
Implementation
public fun burn(ref: &BurnRef, fa: FungibleAsset) acquires Supply, ConcurrentSupply { assert!( ref.metadata == metadata_from_asset(&fa), error::invalid_argument(EBURN_REF_AND_FUNGIBLE_ASSET_MISMATCH) ); burn_internal(fa);}
burn_internal
CAN ONLY BE CALLED BY coin.move for migration.
public(friend) fun burn_internal(fa: fungible_asset::FungibleAsset): u64
Implementation
public(friend) fun burn_internal( fa: FungibleAsset): u64 acquires Supply, ConcurrentSupply { let FungibleAsset { metadata, amount } = fa; decrease_supply(&metadata, amount); amount}
burn_from
Burn the amount
of the fungible asset from the given store.
public fun burn_from<T: key>(ref: &fungible_asset::BurnRef, store: object::Object<T>, amount: u64)
Implementation
public fun burn_from<T: key>( ref: &BurnRef, store: Object<T>, amount: u64) acquires FungibleStore, Supply, ConcurrentSupply, ConcurrentFungibleBalance { // ref metadata match is checked in burn() call burn(ref, unchecked_withdraw(object::object_address(&store), amount));}
address_burn_from_for_gas
Burn the amount
of the fungible asset from the given store for gas charge.
public(friend) fun address_burn_from_for_gas(ref: &fungible_asset::BurnRef, store_addr: address, amount: u64)
Implementation
public(friend) fun address_burn_from_for_gas( ref: &BurnRef, store_addr: address, amount: u64) acquires FungibleStore, Supply, ConcurrentSupply, ConcurrentFungibleBalance { // ref metadata match is checked in burn() call burn(ref, unchecked_withdraw_with_no_events(store_addr, amount));}
withdraw_with_ref
Withdraw amount
of the fungible asset from the store
ignoring frozen
.
public fun withdraw_with_ref<T: key>(ref: &fungible_asset::TransferRef, store: object::Object<T>, amount: u64): fungible_asset::FungibleAsset
Implementation
public fun withdraw_with_ref<T: key>( ref: &TransferRef, store: Object<T>, amount: u64): FungibleAsset acquires FungibleStore, ConcurrentFungibleBalance { assert!( ref.metadata == store_metadata(store), error::invalid_argument(ETRANSFER_REF_AND_STORE_MISMATCH), ); unchecked_withdraw(object::object_address(&store), amount)}
deposit_with_ref
Deposit the fungible asset into the store
ignoring frozen
.
public fun deposit_with_ref<T: key>(ref: &fungible_asset::TransferRef, store: object::Object<T>, fa: fungible_asset::FungibleAsset)
Implementation
public fun deposit_with_ref<T: key>( ref: &TransferRef, store: Object<T>, fa: FungibleAsset) acquires FungibleStore, ConcurrentFungibleBalance { assert!( ref.metadata == fa.metadata, error::invalid_argument(ETRANSFER_REF_AND_FUNGIBLE_ASSET_MISMATCH) ); unchecked_deposit(object::object_address(&store), fa);}
transfer_with_ref
Transfer amount
of the fungible asset with TransferRef
even it is frozen.
public fun transfer_with_ref<T: key>(transfer_ref: &fungible_asset::TransferRef, from: object::Object<T>, to: object::Object<T>, amount: u64)
Implementation
public fun transfer_with_ref<T: key>( transfer_ref: &TransferRef, from: Object<T>, to: Object<T>, amount: u64,) acquires FungibleStore, ConcurrentFungibleBalance { let fa = withdraw_with_ref(transfer_ref, from, amount); deposit_with_ref(transfer_ref, to, fa);}
balance_with_ref
Access raw balance of a store using RawBalanceRef
public fun balance_with_ref<T: key>(ref: &fungible_asset::RawBalanceRef, store: object::Object<T>): u64
Implementation
public fun balance_with_ref<T: key>( ref: &RawBalanceRef, store: Object<T>,): u64 acquires FungibleStore, ConcurrentFungibleBalance { assert!( ref.metadata == store_metadata(store), error::invalid_argument(ERAW_BALANCE_REF_AND_FUNGIBLE_ASSET_MISMATCH) ); balance_impl(store)}
supply_with_ref
Access raw supply of a FA using RawSupplyRef
public fun supply_with_ref<T: key>(ref: &fungible_asset::RawSupplyRef, metadata: object::Object<T>): option::Option<u128>
Implementation
public fun supply_with_ref<T: key>( ref: &RawSupplyRef, metadata: Object<T>,): Option<u128> acquires Supply, ConcurrentSupply { assert!( object::object_address(&ref.metadata) == object::object_address(&metadata), error::invalid_argument(ERAW_BALANCE_REF_AND_FUNGIBLE_ASSET_MISMATCH) ); supply_impl(metadata)}
mutate_metadata
Mutate specified fields of the fungible asset’s Metadata
.
public fun mutate_metadata(metadata_ref: &fungible_asset::MutateMetadataRef, name: option::Option<string::String>, symbol: option::Option<string::String>, decimals: option::Option<u8>, icon_uri: option::Option<string::String>, project_uri: option::Option<string::String>)
Implementation
public fun mutate_metadata( metadata_ref: &MutateMetadataRef, name: Option<String>, symbol: Option<String>, decimals: Option<u8>, icon_uri: Option<String>, project_uri: Option<String>,) acquires Metadata { let metadata_address = object::object_address(&metadata_ref.metadata); let mutable_metadata = borrow_global_mut<Metadata>(metadata_address);
if (option::is_some(&name)){ let name = option::extract(&mut name); assert!(string::length(&name) <= MAX_NAME_LENGTH, error::out_of_range(ENAME_TOO_LONG)); mutable_metadata.name = name; }; if (option::is_some(&symbol)){ let symbol = option::extract(&mut symbol); assert!(string::length(&symbol) <= MAX_SYMBOL_LENGTH, error::out_of_range(ESYMBOL_TOO_LONG)); mutable_metadata.symbol = symbol; }; if (option::is_some(&decimals)){ let decimals = option::extract(&mut decimals); assert!(decimals <= MAX_DECIMALS, error::out_of_range(EDECIMALS_TOO_LARGE)); mutable_metadata.decimals = decimals; }; if (option::is_some(&icon_uri)){ let icon_uri = option::extract(&mut icon_uri); assert!(string::length(&icon_uri) <= MAX_URI_LENGTH, error::out_of_range(EURI_TOO_LONG)); mutable_metadata.icon_uri = icon_uri; }; if (option::is_some(&project_uri)){ let project_uri = option::extract(&mut project_uri); assert!(string::length(&project_uri) <= MAX_URI_LENGTH, error::out_of_range(EURI_TOO_LONG)); mutable_metadata.project_uri = project_uri; };}
zero
Create a fungible asset with zero amount. This can be useful when starting a series of computations where the initial value is 0.
public fun zero<T: key>(metadata: object::Object<T>): fungible_asset::FungibleAsset
Implementation
public fun zero<T: key>(metadata: Object<T>): FungibleAsset { FungibleAsset { metadata: object::convert(metadata), amount: 0, }}
extract
Extract a given amount from the given fungible asset and return a new one.
public fun extract(fungible_asset: &mut fungible_asset::FungibleAsset, amount: u64): fungible_asset::FungibleAsset
Implementation
public fun extract(fungible_asset: &mut FungibleAsset, amount: u64): FungibleAsset { assert!(fungible_asset.amount >= amount, error::invalid_argument(EINSUFFICIENT_BALANCE)); fungible_asset.amount = fungible_asset.amount - amount; FungibleAsset { metadata: fungible_asset.metadata, amount, }}
merge
“Merges” the two given fungible assets. The fungible asset passed in as dst_fungible_asset
will have a value
equal to the sum of the two (dst_fungible_asset
and src_fungible_asset
).
public fun merge(dst_fungible_asset: &mut fungible_asset::FungibleAsset, src_fungible_asset: fungible_asset::FungibleAsset)
Implementation
public fun merge(dst_fungible_asset: &mut FungibleAsset, src_fungible_asset: FungibleAsset) { let FungibleAsset { metadata, amount } = src_fungible_asset; assert!(metadata == dst_fungible_asset.metadata, error::invalid_argument(EFUNGIBLE_ASSET_MISMATCH)); dst_fungible_asset.amount = dst_fungible_asset.amount + amount;}
destroy_zero
Destroy an empty fungible asset.
public fun destroy_zero(fungible_asset: fungible_asset::FungibleAsset)
Implementation
public fun destroy_zero(fungible_asset: FungibleAsset) { let FungibleAsset { amount, metadata: _ } = fungible_asset; assert!(amount == 0, error::invalid_argument(EAMOUNT_IS_NOT_ZERO));}
unchecked_deposit_with_no_events_inline
fun unchecked_deposit_with_no_events_inline(store_addr: address, fa: fungible_asset::FungibleAsset): u64
Implementation
inline fun unchecked_deposit_with_no_events_inline( store_addr: address, fa: FungibleAsset): u64 acquires FungibleStore, ConcurrentFungibleBalance { let FungibleAsset { metadata, amount } = fa; assert!(exists<FungibleStore>(store_addr), error::not_found(EFUNGIBLE_STORE_EXISTENCE)); let store = borrow_global_mut<FungibleStore>(store_addr); assert!(metadata == store.metadata, error::invalid_argument(EFUNGIBLE_ASSET_AND_STORE_MISMATCH));
if (amount != 0) { if (store.balance == 0 && concurrent_fungible_balance_exists_inline(store_addr)) { let balance_resource = borrow_global_mut<ConcurrentFungibleBalance>(store_addr); balance_resource.balance.add(amount); } else { store.balance = store.balance + amount; }; }; amount}
unchecked_deposit
public(friend) fun unchecked_deposit(store_addr: address, fa: fungible_asset::FungibleAsset)
Implementation
public(friend) fun unchecked_deposit( store_addr: address, fa: FungibleAsset) acquires FungibleStore, ConcurrentFungibleBalance { let amount = unchecked_deposit_with_no_events_inline(store_addr, fa); if (amount != 0) { event::emit(Deposit { store: store_addr, amount }); }}
unchecked_deposit_with_no_events
public(friend) fun unchecked_deposit_with_no_events(store_addr: address, fa: fungible_asset::FungibleAsset)
Implementation
public(friend) fun unchecked_deposit_with_no_events( store_addr: address, fa: FungibleAsset) acquires FungibleStore, ConcurrentFungibleBalance { unchecked_deposit_with_no_events_inline(store_addr, fa);}
unchecked_withdraw
Extract amount
of the fungible asset from store
emitting event.
public(friend) fun unchecked_withdraw(store_addr: address, amount: u64): fungible_asset::FungibleAsset
Implementation
public(friend) fun unchecked_withdraw( store_addr: address, amount: u64): FungibleAsset acquires FungibleStore, ConcurrentFungibleBalance { let fa = unchecked_withdraw_with_no_events(store_addr, amount); if (amount != 0) { event::emit<Withdraw>(Withdraw { store: store_addr, amount }); }; fa}
unchecked_withdraw_with_no_events
Extract amount
of the fungible asset from store
w/o emitting event.
fun unchecked_withdraw_with_no_events(store_addr: address, amount: u64): fungible_asset::FungibleAsset
Implementation
inline fun unchecked_withdraw_with_no_events( store_addr: address, amount: u64,): FungibleAsset acquires FungibleStore, ConcurrentFungibleBalance { assert!(exists<FungibleStore>(store_addr), error::not_found(EFUNGIBLE_STORE_EXISTENCE));
let store = borrow_global_mut<FungibleStore>(store_addr); let metadata = store.metadata; if (amount != 0) { if (store.balance == 0 && concurrent_fungible_balance_exists_inline(store_addr)) { let balance_resource = borrow_global_mut<ConcurrentFungibleBalance>(store_addr); assert!( balance_resource.balance.try_sub(amount), error::invalid_argument(EINSUFFICIENT_BALANCE) ); } else { assert!(store.balance >= amount, error::invalid_argument(EINSUFFICIENT_BALANCE)); store.balance = store.balance - amount; }; }; FungibleAsset { metadata, amount }}
increase_supply
Increase the supply of a fungible asset by minting.
fun increase_supply<T: key>(metadata: &object::Object<T>, amount: u64)
Implementation
fun increase_supply<T: key>(metadata: &Object<T>, amount: u64) acquires Supply, ConcurrentSupply { if (amount == 0) { return }; let metadata_address = object::object_address(metadata);
if (exists<ConcurrentSupply>(metadata_address)) { let supply = borrow_global_mut<ConcurrentSupply>(metadata_address); assert!( supply.current.try_add(amount as u128), error::out_of_range(EMAX_SUPPLY_EXCEEDED) ); } else if (exists<Supply>(metadata_address)) { let supply = borrow_global_mut<Supply>(metadata_address); if (option::is_some(&supply.maximum)) { let max = *option::borrow_mut(&mut supply.maximum); assert!( max - supply.current >= (amount as u128), error::out_of_range(EMAX_SUPPLY_EXCEEDED) ) }; supply.current = supply.current + (amount as u128); } else { abort error::not_found(ESUPPLY_NOT_FOUND) }}
decrease_supply
Decrease the supply of a fungible asset by burning.
fun decrease_supply<T: key>(metadata: &object::Object<T>, amount: u64)
Implementation
fun decrease_supply<T: key>(metadata: &Object<T>, amount: u64) acquires Supply, ConcurrentSupply { if (amount == 0) { return }; let metadata_address = object::object_address(metadata);
if (exists<ConcurrentSupply>(metadata_address)) { let supply = borrow_global_mut<ConcurrentSupply>(metadata_address);
assert!( supply.current.try_sub(amount as u128), error::out_of_range(ESUPPLY_UNDERFLOW) ); } else if (exists<Supply>(metadata_address)) { assert!(exists<Supply>(metadata_address), error::not_found(ESUPPLY_NOT_FOUND)); let supply = borrow_global_mut<Supply>(metadata_address); assert!( supply.current >= (amount as u128), error::invalid_state(ESUPPLY_UNDERFLOW) ); supply.current = supply.current - (amount as u128); } else { assert!(false, error::not_found(ESUPPLY_NOT_FOUND)); }}
borrow_fungible_metadata
fun borrow_fungible_metadata<T: key>(metadata: &object::Object<T>): &fungible_asset::Metadata
Implementation
inline fun borrow_fungible_metadata<T: key>( metadata: &Object<T>): &Metadata acquires Metadata { let addr = object::object_address(metadata); borrow_global<Metadata>(addr)}
borrow_fungible_metadata_mut
fun borrow_fungible_metadata_mut<T: key>(metadata: &object::Object<T>): &mut fungible_asset::Metadata
Implementation
inline fun borrow_fungible_metadata_mut<T: key>( metadata: &Object<T>): &mut Metadata acquires Metadata { let addr = object::object_address(metadata); borrow_global_mut<Metadata>(addr)}
borrow_store_resource
fun borrow_store_resource<T: key>(store: &object::Object<T>): &fungible_asset::FungibleStore
Implementation
inline fun borrow_store_resource<T: key>(store: &Object<T>): &FungibleStore acquires FungibleStore { let store_addr = object::object_address(store); assert!(exists<FungibleStore>(store_addr), error::not_found(EFUNGIBLE_STORE_EXISTENCE)); borrow_global<FungibleStore>(store_addr)}
upgrade_to_concurrent
public fun upgrade_to_concurrent(ref: &object::ExtendRef)
Implementation
public fun upgrade_to_concurrent( ref: &ExtendRef,) acquires Supply { let metadata_object_address = object::address_from_extend_ref(ref); let metadata_object_signer = object::generate_signer_for_extending(ref); assert!( features::concurrent_fungible_assets_enabled(), error::invalid_argument(ECONCURRENT_SUPPLY_NOT_ENABLED) ); assert!(exists<Supply>(metadata_object_address), error::not_found(ESUPPLY_NOT_FOUND)); let Supply { current, maximum, } = move_from<Supply>(metadata_object_address);
let unlimited = option::is_none(&maximum); let supply = ConcurrentSupply { current: if (unlimited) { aggregator_v2::create_unbounded_aggregator_with_value(current) } else { aggregator_v2::create_aggregator_with_value(current, option::extract(&mut maximum)) }, }; move_to(&metadata_object_signer, supply);}
upgrade_store_to_concurrent
public entry fun upgrade_store_to_concurrent<T: key>(owner: &signer, store: object::Object<T>)
Implementation
public entry fun upgrade_store_to_concurrent<T: key>( owner: &signer, store: Object<T>,) acquires FungibleStore { assert!(object::owns(store, signer::address_of(owner)), error::permission_denied(ENOT_STORE_OWNER)); assert!(!is_frozen(store), error::invalid_argument(ESTORE_IS_FROZEN)); assert!(allow_upgrade_to_concurrent_fungible_balance(), error::invalid_argument(ECONCURRENT_BALANCE_NOT_ENABLED)); ensure_store_upgraded_to_concurrent_internal(object::object_address(&store));}
ensure_store_upgraded_to_concurrent_internal
Ensure a known FungibleStore
has ConcurrentFungibleBalance
.
fun ensure_store_upgraded_to_concurrent_internal(fungible_store_address: address)
Implementation
fun ensure_store_upgraded_to_concurrent_internal( fungible_store_address: address,) acquires FungibleStore { if (exists<ConcurrentFungibleBalance>(fungible_store_address)) { return }; let store = borrow_global_mut<FungibleStore>(fungible_store_address); let balance = aggregator_v2::create_unbounded_aggregator_with_value(store.balance); store.balance = 0; let object_signer = create_signer::create_signer(fungible_store_address); move_to(&object_signer, ConcurrentFungibleBalance { balance });}
grant_permission_by_store
Permission management
Master signer grant permissioned signer ability to withdraw a given amount of fungible asset.
public fun grant_permission_by_store<T: key>(master: &signer, permissioned: &signer, store: object::Object<T>, amount: u64)
Implementation
public fun grant_permission_by_store<T: key>( master: &signer, permissioned: &signer, store: Object<T>, amount: u64) { permissioned_signer::authorize_increase( master, permissioned, amount as u256, WithdrawPermission::ByStore { store_address: object::object_address(&store), } )}
grant_permission_by_address
public(friend) fun grant_permission_by_address(master: &signer, permissioned: &signer, store_address: address, amount: u64)
Implementation
public(friend) fun grant_permission_by_address( master: &signer, permissioned: &signer, store_address: address, amount: u64) { permissioned_signer::authorize_increase( master, permissioned, amount as u256, WithdrawPermission::ByStore { store_address } )}
refill_permission
public(friend) fun refill_permission(permissioned: &signer, amount: u64, store_address: address)
Implementation
public(friend) fun refill_permission( permissioned: &signer, amount: u64, store_address: address,) { permissioned_signer::increase_limit( permissioned, amount as u256, WithdrawPermission::ByStore { store_address } )}
revoke_permission
Removing permissions from permissioned signer.
#[deprecated]public fun revoke_permission(_permissioned: &signer, _token_type: object::Object<fungible_asset::Metadata>)
Implementation
public fun revoke_permission(_permissioned: &signer, _token_type: Object<Metadata>) { abort 0}
Specification
High-level Requirements
No. | Requirement | Criticality | Implementation | Enforcement |
---|---|---|---|---|
1 | The metadata associated with the fungible asset is subject to precise size constraints. | Medium | The add_fungibility function has size limitations for the name, symbol, number of decimals, icon_uri, and project_uri field of the Metadata resource. | This has been audited. |
2 | Adding fungibility to an existing object should initialize the metadata and supply resources and store them under the metadata object address. | Low | The add_fungibility function initializes the Metadata and Supply resources and moves them under the metadata object. | Audited that the Metadata and Supply resources are initialized properly. |
3 | Generating mint, burn and transfer references can only be done at object creation time and if the object was added fungibility. | Low | The following functions generate the related references of the Metadata object: 1. generate_mint_ref 2. generate_burn_ref 3. generate_transfer_ref | Audited that the Metadata object exists within the constructor ref. |
4 | Only the owner of a store should be allowed to withdraw fungible assets from it. | High | The fungible_asset::withdraw function ensures that the signer owns the store by asserting that the object address matches the address of the signer. | Audited that the address of the signer owns the object. |
5 | The transfer, withdrawal and deposit operation should never change the current supply of the fungible asset. | High | The transfer function withdraws the fungible assets from the store and deposits them to the receiver. The withdraw function extracts the fungible asset from the fungible asset store. The deposit function adds the balance to the fungible asset store. | Audited that the supply before and after the operation remains constant. |
6 | The owner of the store should only be able to withdraw a certain amount if its store has sufficient balance and is not frozen, unless the withdrawal is performed with a reference, and afterwards the store balance should be decreased. | High | The withdraw function ensures that the store is not frozen before calling withdraw_internal which ensures that the withdrawing amount is greater than 0 and less than the total balance from the store. The withdraw_with_ref ensures that the reference's metadata matches the store metadata. | Audited that it aborts if the withdrawing store is frozen. Audited that it aborts if the store doesn't have sufficient balance. Audited that the balance of the withdrawing store is reduced by amount. |
7 | Only the same type of fungible assets should be deposited in a fungible asset store, if the store is not frozen, unless the deposit is performed with a reference, and afterwards the store balance should be increased. | High | The deposit function ensures that store is not frozen and proceeds to call the deposit_internal function which validates the store's metadata and the depositing asset's metadata followed by increasing the store balance by the given amount. The deposit_with_ref ensures that the reference's metadata matches the depositing asset's metadata. | Audited that it aborts if the store is frozen. Audited that it aborts if the asset and asset store are different. Audited that the store's balance is increased by the deposited amount. |
8 | An object should only be allowed to hold one store for fungible assets. | Medium | The create_store function initializes a new FungibleStore resource and moves it under the object address. | Audited that the resource was moved under the object. |
9 | When a new store is created, the balance should be set by default to the value zero. | High | The create_store function initializes a new fungible asset store with zero balance and stores it under the given construtorRef object. | Audited that the store is properly initialized with zero balance. |
10 | A store should only be deleted if its balance is zero. | Medium | The remove_store function validates the store's balance and removes the store under the object address. | Audited that aborts if the balance of the store is not zero. Audited that store is removed from the object address. |
11 | Minting and burning should alter the total supply value, and the store balances. | High | The mint process increases the total supply by the amount minted using the increase_supply function. The burn process withdraws the burn amount from the given store and decreases the total supply by the amount burned using the decrease_supply function. | Audited the mint and burn functions that the supply was adjusted accordingly. |
12 | It must not be possible to burn an amount of fungible assets larger than their current supply. | High | The burn process ensures that the store has enough balance to burn, by asserting that the supply.current >= amount inside the decrease_supply function. | Audited that it aborts if the provided store doesn't have sufficient balance. |
13 | Enabling or disabling store's frozen status should only be done with a valid transfer reference. | High | The set_frozen_flag function ensures that the TransferRef is provided via function argument and that the store's metadata matches the metadata from the reference. It then proceeds to update the frozen flag of the store. | Audited that it aborts if the metadata doesn't match. Audited that the frozen flag is updated properly. |
14 | Extracting a specific amount from the fungible asset should be possible only if the total amount that it holds is greater or equal to the provided amount. | High | The extract function validates that the fungible asset has enough balance to extract and then updates it by subtracting the extracted amount. | Audited that it aborts if the asset didn't have sufficient balance. Audited that the balance of the asset is updated. Audited that the extract function returns the extracted asset. |
15 | Merging two fungible assets should only be possible if both share the same metadata. | Medium | The merge function validates the metadata of the src and dst asset. | Audited that it aborts if the metadata of the src and dst are not the same. |
16 | Post merging two fungible assets, the source asset should have the amount value equal to the sum of the two. | High | The merge function increases dst_fungible_asset.amount by src_fungible_asset.amount. | Audited that the dst_fungible_asset balance is increased by amount. |
17 | Fungible assets with zero balance should be destroyed when the amount reaches value 0. | Medium | The destroy_zero ensures that the balance of the asset has the value 0 and destroy the asset. | Audited that it aborts if the balance of the asset is non zero. |
Module-level Specification
pragma verify=false;
Enum WithdrawPermission
enum WithdrawPermission has copy, drop, store
Variants
ByStore
Fields
-
store_address: address