dispatchable_fungible_asset - [devnet]
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.
The dispatchable_fungible_asset wraps the existing fungible_asset module and adds the ability for token issuer to customize the logic for withdraw and deposit operations. For example:
- Deflation token: a fixed percentage of token will be destructed upon transfer.
 - Transfer allowlist: token can only be transfered to addresses in the allow list.
 - Predicated transfer: transfer can only happen when some certain predicate has been met.
 - Loyalty token: a fixed loyalty will be paid to a designated address when a fungible asset transfer happens
 
The api listed here intended to be an in-place replacement for defi applications that uses fungible_asset api directly and is safe for non-dispatchable (aka vanilla) fungible assets as well.
See AIP-73 for further discussion
use 0x1::error;use 0x1::features;use 0x1::function_info;use 0x1::fungible_asset;use 0x1::object;use 0x1::option;Constants
Feature is not activated yet on the network.
const ENOT_ACTIVATED: u64 = 3;Recipient is not getting the guaranteed value;
const EAMOUNT_MISMATCH: u64 = 2;Dispatch target is not loaded.
const ENOT_LOADED: u64 = 4;TransferRefStore doesn’t exist on the fungible asset type.
const ESTORE_NOT_FOUND: u64 = 1;Resources
TransferRefStore
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]struct TransferRefStore has keyFields
- 
transfer_ref: fungible_asset::TransferRef 
Functions
register_dispatch_functions
public 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 fun register_dispatch_functions(    constructor_ref: &ConstructorRef,    withdraw_function: Option<FunctionInfo>,    deposit_function: Option<FunctionInfo>,    derived_balance_function: Option<FunctionInfo>,) {    fungible_asset::register_dispatch_functions(        constructor_ref,        withdraw_function,        deposit_function,        derived_balance_function,    );    let store_obj = &object::generate_signer(constructor_ref);    move_to<TransferRefStore>(        store_obj,        TransferRefStore {            transfer_ref: fungible_asset::generate_transfer_ref(constructor_ref),        }    );}register_derive_supply_dispatch_function
public fun register_derive_supply_dispatch_function(constructor_ref: &object::ConstructorRef, dispatch_function: option::Option<function_info::FunctionInfo>)Implementation
public fun register_derive_supply_dispatch_function(    constructor_ref: &ConstructorRef,    dispatch_function: Option<FunctionInfo>) {    fungible_asset::register_derive_supply_dispatch_function(        constructor_ref,        dispatch_function    );}withdraw
Withdraw amount of the fungible asset from store by the owner.
The semantics of deposit will be governed by the function specified in DispatchFunctionStore.
public fun withdraw<T: key>(owner: &signer, store: object::Object<T>, amount: u64): fungible_asset::FungibleAssetImplementation
public fun withdraw<T: key>(    owner: &signer,    store: Object<T>,    amount: u64,): FungibleAsset acquires TransferRefStore {    fungible_asset::withdraw_sanity_check(owner, store, false);    fungible_asset::withdraw_permission_check(owner, store, amount);    let func_opt = fungible_asset::withdraw_dispatch_function(store);    if (option::is_some(&func_opt)) {        assert!(            features::dispatchable_fungible_asset_enabled(),            error::aborted(ENOT_ACTIVATED)        );        let func = option::borrow(&func_opt);        function_info::load_module_from_function(func);        let fa = dispatchable_withdraw(            store,            amount,            borrow_transfer_ref(store),            func,        );        fa    } else {        fungible_asset::unchecked_withdraw(object::object_address(&store), amount)    }}deposit
Deposit amount of the fungible asset to store.
The semantics of deposit will be governed by the function specified in DispatchFunctionStore.
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 TransferRefStore {    fungible_asset::deposit_sanity_check(store, false);    let func_opt = fungible_asset::deposit_dispatch_function(store);    if (option::is_some(&func_opt)) {        assert!(            features::dispatchable_fungible_asset_enabled(),            error::aborted(ENOT_ACTIVATED)        );        let func = option::borrow(&func_opt);        function_info::load_module_from_function(func);        dispatchable_deposit(            store,            fa,            borrow_transfer_ref(store),            func        )    } else {        fungible_asset::unchecked_deposit(object::object_address(&store), fa)    }}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.
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 TransferRefStore {    let fa = withdraw(sender, from, amount);    deposit(to, fa);}transfer_assert_minimum_deposit
Transfer an amount of fungible asset from from_store, which should be owned by sender, to receiver.
The recipient is guranteed to receive asset greater than the expected amount.
Note: it does not move the underlying object.
public entry fun transfer_assert_minimum_deposit<T: key>(sender: &signer, from: object::Object<T>, to: object::Object<T>, amount: u64, expected: u64)Implementation
public entry fun transfer_assert_minimum_deposit<T: key>(    sender: &signer,    from: Object<T>,    to: Object<T>,    amount: u64,    expected: u64) acquires TransferRefStore {    let start = fungible_asset::balance(to);    let fa = withdraw(sender, from, amount);    deposit(to, fa);    let end = fungible_asset::balance(to);    assert!(end - start >= expected, error::aborted(EAMOUNT_MISMATCH));}derived_balance
Get the derived value of store using the overloaded hook.
The semantics of value will be governed by the function specified in DispatchFunctionStore.
#[view]public fun derived_balance<T: key>(store: object::Object<T>): u64Implementation
public fun derived_balance<T: key>(store: Object<T>): u64 {    let func_opt = fungible_asset::derived_balance_dispatch_function(store);    if (option::is_some(&func_opt)) {        assert!(            features::dispatchable_fungible_asset_enabled(),            error::aborted(ENOT_ACTIVATED)        );        let func = option::borrow(&func_opt);        function_info::load_module_from_function(func);        dispatchable_derived_balance(store, func)    } else {        fungible_asset::balance(store)    }}is_derived_balance_at_least
Whether the derived value of store using the overloaded hook is at least amount
The semantics of value will be governed by the function specified in DispatchFunctionStore.
#[view]public fun is_derived_balance_at_least<T: key>(store: object::Object<T>, amount: u64): boolImplementation
public fun is_derived_balance_at_least<T: key>(store: Object<T>, amount: u64): bool {    let func_opt = fungible_asset::derived_balance_dispatch_function(store);    if (option::is_some(&func_opt)) {        assert!(            features::dispatchable_fungible_asset_enabled(),            error::aborted(ENOT_ACTIVATED)        );        let func = option::borrow(&func_opt);        function_info::load_module_from_function(func);        dispatchable_derived_balance(store, func) >= amount    } else {        fungible_asset::is_balance_at_least(store, amount)    }}derived_supply
Get the derived supply of the fungible asset using the overloaded hook.
The semantics of supply will be governed by the function specified in DeriveSupplyDispatch.
#[view]public fun derived_supply<T: key>(metadata: object::Object<T>): option::Option<u128>Implementation
public fun derived_supply<T: key>(metadata: Object<T>): Option<u128> {    let func_opt = fungible_asset::derived_supply_dispatch_function(metadata);    if (option::is_some(&func_opt)) {        assert!(            features::dispatchable_fungible_asset_enabled(),            error::aborted(ENOT_ACTIVATED)        );        let func = option::borrow(&func_opt);        function_info::load_module_from_function(func);        dispatchable_derived_supply(metadata, func)    } else {        fungible_asset::supply(metadata)    }}borrow_transfer_ref
fun borrow_transfer_ref<T: key>(metadata: object::Object<T>): &fungible_asset::TransferRefImplementation
inline fun borrow_transfer_ref<T: key>(metadata: Object<T>): &TransferRef {    let metadata_addr = object::object_address(        &fungible_asset::store_metadata(metadata)    );    assert!(        exists<TransferRefStore>(metadata_addr),        error::not_found(ESTORE_NOT_FOUND)    );    &borrow_global<TransferRefStore>(metadata_addr).transfer_ref}dispatchable_withdraw
fun dispatchable_withdraw<T: key>(store: object::Object<T>, amount: u64, transfer_ref: &fungible_asset::TransferRef, function: &function_info::FunctionInfo): fungible_asset::FungibleAssetImplementation
native fun dispatchable_withdraw<T: key>(    store: Object<T>,    amount: u64,    transfer_ref: &TransferRef,    function: &FunctionInfo,): FungibleAsset;dispatchable_deposit
fun dispatchable_deposit<T: key>(store: object::Object<T>, fa: fungible_asset::FungibleAsset, transfer_ref: &fungible_asset::TransferRef, function: &function_info::FunctionInfo)Implementation
native fun dispatchable_deposit<T: key>(    store: Object<T>,    fa: FungibleAsset,    transfer_ref: &TransferRef,    function: &FunctionInfo,);dispatchable_derived_balance
fun dispatchable_derived_balance<T: key>(store: object::Object<T>, function: &function_info::FunctionInfo): u64Implementation
native fun dispatchable_derived_balance<T: key>(    store: Object<T>,    function: &FunctionInfo,): u64;dispatchable_derived_supply
fun dispatchable_derived_supply<T: key>(metadata: object::Object<T>, function: &function_info::FunctionInfo): option::Option<u128>Implementation
native fun dispatchable_derived_supply<T: key>(    metadata: Object<T>,    function: &FunctionInfo,): Option<u128>;Specification
pragma verify = false;withdraw
public fun withdraw<T: key>(owner: &signer, store: object::Object<T>, amount: u64): fungible_asset::FungibleAssetmodifies global<permissioned_signer::PermissionStorage>(permissioned_signer::spec_permission_address(owner));modifies global<fungible_asset::FungibleStore>(object::object_address(store));modifies global<fungible_asset::ConcurrentFungibleBalance>(object::object_address(store));deposit
public fun deposit<T: key>(store: object::Object<T>, fa: fungible_asset::FungibleAsset)modifies global<fungible_asset::FungibleStore>(object::object_address(store));modifies global<fungible_asset::ConcurrentFungibleBalance>(object::object_address(store));dispatchable_withdraw
fun dispatchable_withdraw<T: key>(store: object::Object<T>, amount: u64, transfer_ref: &fungible_asset::TransferRef, function: &function_info::FunctionInfo): fungible_asset::FungibleAssetpragma opaque;dispatchable_deposit
fun dispatchable_deposit<T: key>(store: object::Object<T>, fa: fungible_asset::FungibleAsset, transfer_ref: &fungible_asset::TransferRef, function: &function_info::FunctionInfo)pragma opaque;dispatchable_derived_balance
fun dispatchable_derived_balance<T: key>(store: object::Object<T>, function: &function_info::FunctionInfo): u64pragma opaque;dispatchable_derived_supply
fun dispatchable_derived_supply<T: key>(metadata: object::Object<T>, function: &function_info::FunctionInfo): option::Option<u128>pragma opaque;