Supra Fungible Asset (FA) Module

The Supra Framework's fungible asset module provides a comprehensive standard for creating, managing, and transferring fungible tokens on the Supra. This module enables the creation of fungible assets with any metadata object that is equipped with the Metadata resource.

Module Structure

module supra_framework::fungible_asset {
    use supra_framework::aggregator_v2;
    use supra_framework::create_signer;
    use supra_framework::event;
    use supra_framework::function_info;
    use supra_framework::object;
    use std::string;
    use std::features;
    use std::error;
    use std::option;
    use std::signer;
}

Friend Modules

The module declares the following friend relationships:

  • supra_framework::coin - For coin-to-FA migration support

  • supra_framework::primary_fungible_store - For primary store management

  • supra_framework::supra_account - For account integration

  • supra_framework::dispatchable_fungible_asset - For custom dispatch logic

Supply and Validation Constrants

const MAX_U128: u128 = 340282366920938463463374607431768211455;
const MAX_NAME_LENGTH: u64 = 32;
const MAX_SYMBOL_LENGTH: u64 = 10;
const MAX_DECIMALS: u8 = 32;
const MAX_URI_LENGTH: u64 = 512;

Core Data Structures

FungibleAsset

struct FungibleAsset {
    metadata: Object<Metadata>,
    amount: u64,
}

Represents a specific amount of fungible asset with type safety guarantees. This is ephemeral and cannot be stored directly - it must be deposited back into a store.

Metadata

#[resource_group_member(group = supra_framework::object::ObjectGroup)]
struct Metadata has key, copy, drop {
    name: String,           // Asset name, max 32 characters
    symbol: String,         // Asset symbol, max 10 characters  
    decimals: u8,           // Display decimals, max 32
    icon_uri: String,       // Icon URI, max 512 characters
    project_uri: String,    // Project URI, max 512 characters
}

FungibleStore

#[resource_group_member(group = supra_framework::object::ObjectGroup)]
struct FungibleStore has key {
    metadata: Object<Metadata>,  // The address of the base metadata object
    balance: u64,                // The balance of the fungible metadata
    frozen: bool,                // If true, only TransferRef can move in/out
}

Supply Management

#[resource_group_member(group = supra_framework::object::ObjectGroup)]
struct Supply has key {
    current: u128,
    maximum: Option<u128>,  // None = unlimited supply
}

#[resource_group_member(group = supra_framework::object::ObjectGroup)]
struct ConcurrentSupply has key {
    current: Aggregator<u128>,
}

Reference Types

struct MintRef has drop, store {
    metadata: Object<Metadata>
}

struct BurnRef has drop, store {
    metadata: Object<Metadata>
}

struct TransferRef has drop, store {
    metadata: Object<Metadata>
}

struct MutateMetadataRef has drop, store {
    metadata: Object<Metadata>
}

Dispatch Functions

#[resource_group_member(group = supra_framework::object::ObjectGroup)]
struct DispatchFunctionStore has key {
    withdraw_function: Option<FunctionInfo>,
    deposit_function: Option<FunctionInfo>,
    derived_balance_function: Option<FunctionInfo>,
}

Concurrent Balance Tracking

#[resource_group_member(group = supra_framework::object::ObjectGroup)]
struct ConcurrentFungibleBalance has key {
    balance: Aggregator<u64>,
}

Untransferable Assets

#[resource_group_member(group = supra_framework::object::ObjectGroup)]
struct Untransferable has key {}

Events

#[event]
struct Deposit has drop, store {
    store: address,
    amount: u64,
}

#[event]
struct Withdraw has drop, store {
    store: address,
    amount: u64,
}

#[event]
struct Frozen has drop, store {
    store: address,
    frozen: bool,
}

Utility Functions

inline fun default_to_concurrent_fungible_supply(): bool

Returns whether concurrent fungible supply is enabled by default.

inline fun allow_upgrade_to_concurrent_fungible_balance(): bool

Returns whether upgrading to concurrent fungible balance is allowed.

inline fun default_to_concurrent_fungible_balance(): bool

Returns whether concurrent fungible balance is enabled by default.

#[view]
public fun store_exists(store: address): bool

Returns whether the provided address has a store initialized.

inline fun store_exists_inline(store: address): bool

Inline version of store existence check for internal use.

inline fun concurrent_fungible_balance_exists_inline(store: address): bool

Returns whether the provided address has concurrent fungible balance initialized.

#[view]
public fun is_balance_at_least<T: key>(store: Object<T>, amount: u64): bool

Checks whether the balance of a store is >= amount.

public(friend) fun is_address_balance_at_least(store_addr: address, amount: u64): bool

Friend function to check if address balance is at least the specified amount.

Core Functions

Asset Creation

add_fungibility

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>

Creates a fungible asset by adding metadata and supply tracking to an existing object. This returns the capabilities to mint, burn, and transfer.

Parameters:

  • constructor_ref - Object constructor reference

  • maximum_supply - Maximum supply behavior:

    • option::none() - Unlimited supply monitoring

    • option::some(max) - Fixed supply with max as maximum

  • name - Asset name (≤32 characters)

  • symbol - Asset symbol (≤10 characters)

  • decimals - Decimal places (≤32)

  • icon_uri - Icon URI (≤512 characters)

  • project_uri - Project URI (≤512 characters)

Important: The object must be non-deletable. This function initializes either Supply or ConcurrentSupply

based on feature flags.

Reference Generation

generate_mint_ref

public fun generate_mint_ref(constructor_ref: &ConstructorRef): MintRef

Creates a mint reference that can be used to mint fungible assets. Can only be called at object creation time.

generate_burn_ref

public fun generate_burn_ref(constructor_ref: &ConstructorRef): BurnRef

Creates a burn reference that can be used to burn fungible assets. Can only be called at object creation time.

generate_transfer_ref

public fun generate_transfer_ref(constructor_ref: &ConstructorRef): TransferRef

Creates a transfer reference for freeze/unfreeze/transfer operations. Can only be called at object creation time.

generate_mutate_metadata_ref

public fun generate_mutate_metadata_ref(constructor_ref: &ConstructorRef): MutateMetadataRef

Creates a metadata mutation reference. Can only be called at object creation time.

Store Management

create_store

public fun create_store<T: key>(
    constructor_ref: &ConstructorRef,
    metadata: Object<T>,
): Object<FungibleStore>

Creates a store for holding fungible assets of a specific type. Applications can use this to create multiple stores for isolating fungible assets for different purposes.

remove_store

public fun remove_store(delete_ref: &DeleteRef)

Removes an empty store. The store must be completely empty prior to removal.

Asset Operations

mint

public fun mint(ref: &MintRef, amount: u64): FungibleAsset

Mints the specified amount of fungible asset.

mint_internal

public(friend) fun mint_internal(metadata: Object<Metadata>, amount: u64): FungibleAsset

Friend function for minting - can only be called by coin.move for migration.

mint_to

public fun mint_to<T: key>(ref: &MintRef, store: Object<T>, amount: u64)

Mints the specified amount directly to a destination store.

burn

public fun burn(ref: &BurnRef, fa: FungibleAsset)

Burns a fungible asset, removing it from circulation.

burn_internal

public(friend) fun burn_internal(fa: FungibleAsset): u64

Friend function for burning - can only be called by coin.move for migration.

burn_from

public fun burn_from<T: key>(ref: &BurnRef, store: Object<T>, amount: u64)

Burns the specified amount from the given store.

address_burn_from

public(friend) fun address_burn_from(ref: &BurnRef, store_addr: address, amount: u64)

Friend function to burn from a specific address.

Transfer Operations

transfer

public entry fun transfer<T: key>(
    sender: &signer,
    from: Object<T>,
    to: Object<T>,
    amount: u64,
)

Transfers an amount of fungible asset from one store to another. The sender must own the source store.

withdraw

public fun withdraw<T: key>(
    owner: &signer,
    store: Object<T>,
    amount: u64,
): FungibleAsset

Withdraws an amount of fungible asset from a store by the owner.

deposit

public fun deposit<T: key>(store: Object<T>, fa: FungibleAsset)

Deposits a fungible asset into a store.

Sanity Check Functions

withdraw_sanity_check

public(friend) fun withdraw_sanity_check<T: key>(
    owner: &signer,
    store: Object<T>,
    abort_on_dispatch: bool,
)

Checks the permissions and conditions for withdraw operations, including:

  • Owner verification

  • Dispatch function validation

  • Frozen state checking

deposit_sanity_check

public fun deposit_sanity_check<T: key>(
    store: Object<T>,
    abort_on_dispatch: bool
)

Validates conditions for deposit operations, including:

  • Dispatch function validation

  • Frozen state checking

Internal Operations

deposit_internal

public(friend) fun deposit_internal(store_addr: address, fa: FungibleAsset)

Internal function for depositing fungible assets with event emission.

withdraw_internal

public(friend) fun withdraw_internal(store_addr: address, amount: u64): FungibleAsset

Internal function for withdrawing fungible assets with event emission.

Reference-Based Operations

withdraw_with_ref

public fun withdraw_with_ref<T: key>(
    ref: &TransferRef,
    store: Object<T>,
    amount: u64
): FungibleAsset

Withdraws fungible assets using a TransferRef, ignoring frozen status.

deposit_with_ref

public fun deposit_with_ref<T: key>(
    ref: &TransferRef,
    store: Object<T>,
    fa: FungibleAsset
)

Deposits fungible assets using a TransferRef, ignoring frozen status.

transfer_with_ref

public fun transfer_with_ref<T: key>(
    transfer_ref: &TransferRef,
    from: Object<T>,
    to: Object<T>,
    amount: u64,
)

Transfers fungible assets with TransferRef even if stores are frozen.

Asset Manipulation

extract

public fun extract(
    fungible_asset: &mut FungibleAsset,
    amount: u64,
): FungibleAsset

Extracts a given amount from a fungible asset and returns a new one.

merge

public fun merge(
    dst_fungible_asset: &mut FungibleAsset,
    src_fungible_asset: FungibleAsset
)

Merges two fungible assets. The destination asset will have the sum of both amounts.

zero

public fun zero<T: key>(metadata: Object<T>): FungibleAsset

Creates a fungible asset with zero amount. Useful for starting computations.

destroy_zero

public fun destroy_zero(fungible_asset: FungibleAsset)

Destroys an empty fungible asset.

Metadata Accessor Functions

metadata_from_asset

public fun metadata_from_asset(fa: &FungibleAsset): Object<Metadata>

Returns the underlying metadata object from a fungible asset.

store_metadata

#[view]
public fun store_metadata<T: key>(store: Object<T>): Object<Metadata>

Returns the underlying metadata object from a store.

amount

public fun amount(fa: &FungibleAsset): u64

Returns the amount of a given fungible asset.

asset_metadata

public fun asset_metadata(fa: &FungibleAsset): Object<Metadata>

Returns the metadata object from a fungible asset.

mint_ref_metadata

public fun mint_ref_metadata(ref: &MintRef): Object<Metadata>

Gets the underlying metadata object from a MintRef.

transfer_ref_metadata

public fun transfer_ref_metadata(ref: &TransferRef): Object<Metadata>

Gets the underlying metadata object from a TransferRef.

burn_ref_metadata

public fun burn_ref_metadata(ref: &BurnRef): Object<Metadata>

Gets the underlying metadata object from a BurnRef.

object_from_metadata_ref

public fun object_from_metadata_ref(ref: &MutateMetadataRef): Object<Metadata>

Gets the underlying metadata object from a MutateMetadataRef.

View Functions

#[view]
public fun supply<T: key>(metadata: Object<T>): Option<u128>

Returns the current supply from the metadata object.

#[view]
public fun maximum<T: key>(metadata: Object<T>): Option<u128>

Returns the maximum supply. Returns none if unlimited.

#[view]
public fun name<T: key>(metadata: Object<T>): String

Returns the name of the fungible asset.

#[view]
public fun symbol<T: key>(metadata: Object<T>): String

Returns the symbol of the fungible asset.

#[view]
public fun decimals<T: key>(metadata: Object<T>): u8

Returns the decimals from the metadata object.

#[view]
public fun icon_uri<T: key>(metadata: Object<T>): String

Returns the icon URI from the metadata object.

#[view]
public fun project_uri<T: key>(metadata: Object<T>): String

Returns the project URI from the metadata object.

#[view]
public fun metadata<T: key>(metadata: Object<T>): Metadata

Returns the complete metadata struct from the metadata object.

#[view]
public fun balance<T: key>(store: Object<T>): u64

Returns the balance of a given store.

#[view]
public fun is_frozen<T: key>(store: Object<T>): bool

Returns whether a store is frozen. Defaults to false if store doesn't exist.

Migration Support

Supra provides migration support from the legacy coin standard through friend functions:

// Friend functions for coin migration
public(friend) fun mint_internal(metadata: Object<Metadata>, amount: u64): FungibleAsset
public(friend) fun burn_internal(fa: FungibleAsset): u64

Testing Support

The module includes comprehensive test functions for development:

#[test_only]
public fun create_test_token(creator: &signer): (ConstructorRef, Object<TestToken>)

#[test_only]
public fun init_test_metadata(constructor_ref: &ConstructorRef): (MintRef, TransferRef, BurnRef, MutateMetadataRef)

#[test_only]
public fun create_fungible_asset(creator: &signer): (MintRef, TransferRef, BurnRef, MutateMetadataRef, Object<Metadata>)

#[test_only]
public fun create_test_store<T: key>(owner: &signer, metadata: Object<T>): Object<FungibleStore>

Last updated