coin - [devnet]
This module provides the foundation for typesafe Coins.
use 0x1::account;use 0x1::aggregator;use 0x1::create_signer;use 0x1::error;use 0x1::event;use 0x1::features;use 0x1::fungible_asset;use 0x1::guid;use 0x1::object;use 0x1::option;use 0x1::optional_aggregator;use 0x1::permissioned_signer;use 0x1::primary_fungible_store;use 0x1::signer;use 0x1::string;use 0x1::system_addresses;use 0x1::table;use 0x1::type_info;use 0x1::vector;Constants
Maximum possible aggregatable coin value.
const MAX_U64: u128 = 18446744073709551615;Not enough coins to complete transaction
const EINSUFFICIENT_BALANCE: u64 = 6;const MAX_DECIMALS: u8 = 32;The value of aggregatable coin used for transaction fees redistribution does not fit in u64.
const EAGGREGATABLE_COIN_VALUE_TOO_LARGE: u64 = 14;APT pairing is not eanbled yet.
const EAPT_PAIRING_IS_NOT_ENABLED: u64 = 28;The BurnRef does not exist.
const EBURN_REF_NOT_FOUND: u64 = 25;The BurnRefReceipt does not match the BurnRef to be returned.
const EBURN_REF_RECEIPT_MISMATCH: u64 = 24;The coin converison map is not created yet.
const ECOIN_CONVERSION_MAP_NOT_FOUND: u64 = 27;The decimals of the coin is too large.
const ECOIN_DECIMALS_TOO_LARGE: u64 = 29;Address of account which is used to initialize a coin CoinType doesn’t match the deployer of module
const ECOIN_INFO_ADDRESS_MISMATCH: u64 = 1;CoinType is already initialized as a coin
const ECOIN_INFO_ALREADY_PUBLISHED: u64 = 2;CoinType hasn’t been initialized as a coin
const ECOIN_INFO_NOT_PUBLISHED: u64 = 3;Name of the coin is too long
const ECOIN_NAME_TOO_LONG: u64 = 12;Deprecated. Account already has CoinStore registered for CoinType
const ECOIN_STORE_ALREADY_PUBLISHED: u64 = 4;Account hasn’t registered CoinStore for CoinType
const ECOIN_STORE_NOT_PUBLISHED: u64 = 5;Cannot upgrade the total supply of coins to different implementation.
const ECOIN_SUPPLY_UPGRADE_NOT_SUPPORTED: u64 = 11;Symbol of the coin is too long
const ECOIN_SYMBOL_TOO_LONG: u64 = 13;The feature of migration from coin to fungible asset is not enabled.
const ECOIN_TO_FUNGIBLE_ASSET_FEATURE_NOT_ENABLED: u64 = 18;The coin type from the map does not match the calling function type argument.
const ECOIN_TYPE_MISMATCH: u64 = 17;Cannot destroy non-zero coins
const EDESTRUCTION_OF_NONZERO_TOKEN: u64 = 7;CoinStore is frozen. Coins cannot be deposited or withdrawn
const EFROZEN: u64 = 10;The migration process from coin to fungible asset is not enabled yet.
const EMIGRATION_FRAMEWORK_NOT_ENABLED: u64 = 26;The MintRef does not exist.
const EMINT_REF_NOT_FOUND: u64 = 21;The MintRefReceipt does not match the MintRef to be returned.
const EMINT_REF_RECEIPT_MISMATCH: u64 = 20;Error regarding paired coin type of the fungible asset metadata.
const EPAIRED_COIN: u64 = 15;Error regarding paired fungible asset metadata of a coin type.
const EPAIRED_FUNGIBLE_ASSET: u64 = 16;PairedFungibleAssetRefs resource does not exist.
const EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND: u64 = 19;The TransferRef does not exist.
const ETRANSFER_REF_NOT_FOUND: u64 = 23;The TransferRefReceipt does not match the TransferRef to be returned.
const ETRANSFER_REF_RECEIPT_MISMATCH: u64 = 22;const MAX_COIN_NAME_LENGTH: u64 = 32;const MAX_COIN_SYMBOL_LENGTH: u64 = 32;Structs
Coin
Core data structures Main structure representing a coin/token in an account’s custody.
struct Coin<CoinType> has storeFields
- 
value: u64 - Amount of coin this address has.
 
AggregatableCoin
DEPRECATED
#[deprecated]struct AggregatableCoin<CoinType> has storeFields
- 
value: aggregator::Aggregator - Amount of aggregatable coin this address has.
 
CoinDeposit
Module event emitted when some amount of a coin is deposited into an account.
#[event]struct CoinDeposit has drop, storeFields
- 
coin_type: string::String - 
account: address - 
amount: u64 
CoinWithdraw
Module event emitted when some amount of a coin is withdrawn from an account.
#[event]struct CoinWithdraw has drop, storeFields
- 
coin_type: string::String - 
account: address - 
amount: u64 
Deposit
#[event]#[deprecated]struct Deposit<CoinType> has drop, storeFields
- 
account: address - 
amount: u64 
Withdraw
#[event]#[deprecated]struct Withdraw<CoinType> has drop, storeFields
- 
account: address - 
amount: u64 
DepositEvent
Event emitted when some amount of a coin is deposited into an account.
struct DepositEvent has drop, storeFields
- 
amount: u64 
WithdrawEvent
Event emitted when some amount of a coin is withdrawn from an account.
struct WithdrawEvent has drop, storeFields
- 
amount: u64 
CoinEventHandleDeletion
Module event emitted when the event handles related to coin store is deleted.
Deprecated: replaced with CoinStoreDeletion
#[event]#[deprecated]struct CoinEventHandleDeletion has drop, storeFields
- 
event_handle_creation_address: address - 
deleted_deposit_event_handle_creation_number: u64 - 
deleted_withdraw_event_handle_creation_number: u64 
CoinStoreDeletion
Module event emitted when the event handles related to coin store is deleted.
#[event]struct CoinStoreDeletion has drop, storeFields
- 
coin_type: string::String - 
event_handle_creation_address: address - 
deleted_deposit_event_handle_creation_number: u64 - 
deleted_withdraw_event_handle_creation_number: u64 
PairCreation
Module event emitted when a new pair of coin and fungible asset is created.
#[event]struct PairCreation has drop, storeFields
- 
coin_type: type_info::TypeInfo - 
fungible_asset_metadata_address: address 
MintCapability
Capability required to mint coins.
struct MintCapability<CoinType> has copy, storeFields
- 
dummy_field: bool 
FreezeCapability
Capability required to freeze a coin store.
struct FreezeCapability<CoinType> has copy, storeFields
- 
dummy_field: bool 
BurnCapability
Capability required to burn coins.
struct BurnCapability<CoinType> has copy, storeFields
- 
dummy_field: bool 
MintRefReceipt
The hot potato receipt for flash borrowing MintRef.
struct MintRefReceiptFields
- 
metadata: object::Object<fungible_asset::Metadata> 
TransferRefReceipt
The hot potato receipt for flash borrowing TransferRef.
struct TransferRefReceiptFields
- 
metadata: object::Object<fungible_asset::Metadata> 
BurnRefReceipt
The hot potato receipt for flash borrowing BurnRef.
struct BurnRefReceiptFields
- 
metadata: object::Object<fungible_asset::Metadata> 
Resources
CoinStore
A holder of a specific coin types and associated event handles. These are kept in a single resource to ensure locality of data.
struct CoinStore<CoinType> has keyFields
- 
coin: coin::Coin<CoinType> - 
frozen: bool - 
deposit_events: event::EventHandle<coin::DepositEvent> - 
withdraw_events: event::EventHandle<coin::WithdrawEvent> 
SupplyConfig
Configuration that controls the behavior of total coin supply. If the field is set, coin creators are allowed to upgrade to parallelizable implementations.
#[deprecated]struct SupplyConfig has keyFields
- 
allow_upgrades: bool 
CoinInfo
Information about a specific coin type. Stored on the creator of the coin’s account.
struct CoinInfo<CoinType> has keyFields
- 
name: string::String - 
symbol: string::String - Symbol of the coin, usually a shorter version of the name. For example, Singapore Dollar is SGD.
 - 
decimals: u8 - 
 Number of decimals used to get its user representation.
 For example, if 
decimalsequals2, a balance of505coins should be displayed to a user as5.05(505 / 10 ** 2). - 
supply: option::Option<optional_aggregator::OptionalAggregator> - Amount of this coin type in existence.
 
CoinConversionMap
The mapping between coin and fungible asset.
struct CoinConversionMap has keyFields
- 
coin_to_fungible_asset_map: table::Table<type_info::TypeInfo, object::Object<fungible_asset::Metadata>> 
PairedCoinType
The paired coin type info stored in fungible asset metadata object.
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]struct PairedCoinType has keyFields
- 
type: type_info::TypeInfo 
PairedFungibleAssetRefs
The refs of the paired fungible asset.
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]struct PairedFungibleAssetRefs has keyFields
- 
mint_ref_opt: option::Option<fungible_asset::MintRef> - 
transfer_ref_opt: option::Option<fungible_asset::TransferRef> - 
burn_ref_opt: option::Option<fungible_asset::BurnRef> 
MigrationFlag
The flag the existence of which indicates the primary fungible store is created by the migration from CoinStore.
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]#[deprecated]struct MigrationFlag has keyFields
- 
dummy_field: bool 
Ghost$supply
struct Ghost$supply<CoinType> has copy, drop, store, keyFields
- 
v: num 
Ghost$aggregate_supply
struct Ghost$aggregate_supply<CoinType> has copy, drop, store, keyFields
- 
v: num 
Functions
paired_metadata
Get the paired fungible asset metadata object of a coin type. If not exist, return option::none().
#[view]public fun paired_metadata<CoinType>(): option::Option<object::Object<fungible_asset::Metadata>>Implementation
public fun paired_metadata<CoinType>(): Option<Object<Metadata>> acquires CoinConversionMap {    if (exists<CoinConversionMap>(@aptos_framework)) {        let map =            &borrow_global<CoinConversionMap>(@aptos_framework).coin_to_fungible_asset_map;        let type = type_info::type_of<CoinType>();        if (table::contains(map, type)) {            return option::some(*table::borrow(map, type))        }    };    option::none()}create_coin_conversion_map
public entry fun create_coin_conversion_map(aptos_framework: &signer)Implementation
public entry fun create_coin_conversion_map(aptos_framework: &signer) {    system_addresses::assert_aptos_framework(aptos_framework);    if (!exists<CoinConversionMap>(@aptos_framework)) {        move_to(            aptos_framework,            CoinConversionMap { coin_to_fungible_asset_map: table::new() }        )    };}create_pairing
Create APT pairing by passing AptosCoin.
public entry fun create_pairing<CoinType>(aptos_framework: &signer)Implementation
public entry fun create_pairing<CoinType>(    aptos_framework: &signer) acquires CoinConversionMap, CoinInfo {    system_addresses::assert_aptos_framework(aptos_framework);    create_and_return_paired_metadata_if_not_exist<CoinType>(true);}is_apt
fun is_apt<CoinType>(): boolImplementation
inline fun is_apt<CoinType>(): bool {    type_info::type_name<CoinType>() == string::utf8(b"0x1::aptos_coin::AptosCoin")}create_and_return_paired_metadata_if_not_exist
fun create_and_return_paired_metadata_if_not_exist<CoinType>(allow_apt_creation: bool): object::Object<fungible_asset::Metadata>Implementation
inline fun create_and_return_paired_metadata_if_not_exist<CoinType>(    allow_apt_creation: bool): Object<Metadata> {    assert!(        exists<CoinConversionMap>(@aptos_framework),        error::not_found(ECOIN_CONVERSION_MAP_NOT_FOUND)    );    let map = borrow_global_mut<CoinConversionMap>(@aptos_framework);    let type = type_info::type_of<CoinType>();    if (!table::contains(&map.coin_to_fungible_asset_map, type)) {        let is_apt = is_apt<CoinType>();        assert!(            !is_apt || allow_apt_creation,            error::invalid_state(EAPT_PAIRING_IS_NOT_ENABLED)        );        let metadata_object_cref =            if (is_apt) {                object::create_sticky_object_at_address(                    @aptos_framework, @aptos_fungible_asset                )            } else {                object::create_named_object(                    &create_signer::create_signer(@aptos_fungible_asset),                    *string::bytes(&type_info::type_name<CoinType>())                )            };        primary_fungible_store::create_primary_store_enabled_fungible_asset(            &metadata_object_cref,            option::none(),            name<CoinType>(),            symbol<CoinType>(),            decimals<CoinType>(),            string::utf8(b""),            string::utf8(b"")        );
        let metadata_object_signer = &object::generate_signer(&metadata_object_cref);        let type = type_info::type_of<CoinType>();        move_to(metadata_object_signer, PairedCoinType { type });        let metadata_obj = object::object_from_constructor_ref(&metadata_object_cref);
        table::add(&mut map.coin_to_fungible_asset_map, type, metadata_obj);        event::emit(            PairCreation {                coin_type: type,                fungible_asset_metadata_address: object_address(&metadata_obj)            }        );
        // Generates all three refs        let mint_ref = fungible_asset::generate_mint_ref(&metadata_object_cref);        let transfer_ref =            fungible_asset::generate_transfer_ref(&metadata_object_cref);        let burn_ref = fungible_asset::generate_burn_ref(&metadata_object_cref);        move_to(            metadata_object_signer,            PairedFungibleAssetRefs {                mint_ref_opt: option::some(mint_ref),                transfer_ref_opt: option::some(transfer_ref),                burn_ref_opt: option::some(burn_ref)            }        );    };    *table::borrow(&map.coin_to_fungible_asset_map, type)}ensure_paired_metadata
Get the paired fungible asset metadata object of a coin type, create if not exist.
public(friend) fun ensure_paired_metadata<CoinType>(): object::Object<fungible_asset::Metadata>Implementation
public(friend) fun ensure_paired_metadata<CoinType>(): Object<Metadata> acquires CoinConversionMap, CoinInfo {    create_and_return_paired_metadata_if_not_exist<CoinType>(false)}paired_coin
Get the paired coin type of a fungible asset metadata object.
#[view]public fun paired_coin(metadata: object::Object<fungible_asset::Metadata>): option::Option<type_info::TypeInfo>Implementation
public fun paired_coin(metadata: Object<Metadata>): Option<TypeInfo> acquires PairedCoinType {    let metadata_addr = object::object_address(&metadata);    if (exists<PairedCoinType>(metadata_addr)) {        option::some(borrow_global<PairedCoinType>(metadata_addr).type)    } else {        option::none()    }}coin_to_fungible_asset
Conversion from coin to fungible asset
public fun coin_to_fungible_asset<CoinType>(coin: coin::Coin<CoinType>): fungible_asset::FungibleAssetImplementation
public fun coin_to_fungible_asset<CoinType>(    coin: Coin<CoinType>): FungibleAsset acquires CoinConversionMap, CoinInfo {    let metadata = ensure_paired_metadata<CoinType>();    let amount = burn_internal(coin);    fungible_asset::mint_internal(metadata, amount)}fungible_asset_to_coin
Conversion from fungible asset to coin. Not public to push the migration to FA.
fun fungible_asset_to_coin<CoinType>(fungible_asset: fungible_asset::FungibleAsset): coin::Coin<CoinType>Implementation
fun fungible_asset_to_coin<CoinType>(    fungible_asset: FungibleAsset): Coin<CoinType> acquires CoinInfo, PairedCoinType {    let metadata_addr =        object::object_address(&fungible_asset::metadata_from_asset(&fungible_asset));    assert!(        object::object_exists<PairedCoinType>(metadata_addr),        error::not_found(EPAIRED_COIN)    );    let coin_type_info = borrow_global<PairedCoinType>(metadata_addr).type;    assert!(        coin_type_info == type_info::type_of<CoinType>(),        error::invalid_argument(ECOIN_TYPE_MISMATCH)    );    let amount = fungible_asset::burn_internal(fungible_asset);    mint_internal<CoinType>(amount)}assert_paired_metadata_exists
fun assert_paired_metadata_exists<CoinType>(): object::Object<fungible_asset::Metadata>Implementation
inline fun assert_paired_metadata_exists<CoinType>(): Object<Metadata> {    let metadata_opt = paired_metadata<CoinType>();    assert!(        option::is_some(&metadata_opt), error::not_found(EPAIRED_FUNGIBLE_ASSET)    );    option::destroy_some(metadata_opt)}paired_mint_ref_exists
Check whether MintRef has not been taken.
#[view]public fun paired_mint_ref_exists<CoinType>(): boolImplementation
public fun paired_mint_ref_exists<CoinType>(): bool acquires CoinConversionMap, PairedFungibleAssetRefs {    let metadata = assert_paired_metadata_exists<CoinType>();    let metadata_addr = object_address(&metadata);    assert!(        exists<PairedFungibleAssetRefs>(metadata_addr),        error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)    );    option::is_some(        &borrow_global<PairedFungibleAssetRefs>(metadata_addr).mint_ref_opt    )}get_paired_mint_ref
Get the MintRef of paired fungible asset of a coin type from MintCapability.
public fun get_paired_mint_ref<CoinType>(_: &coin::MintCapability<CoinType>): (fungible_asset::MintRef, coin::MintRefReceipt)Implementation
public fun get_paired_mint_ref<CoinType>(    _: &MintCapability<CoinType>): (MintRef, MintRefReceipt) acquires CoinConversionMap, PairedFungibleAssetRefs {    let metadata = assert_paired_metadata_exists<CoinType>();    let metadata_addr = object_address(&metadata);    assert!(        exists<PairedFungibleAssetRefs>(metadata_addr),        error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)    );    let mint_ref_opt =        &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).mint_ref_opt;    assert!(option::is_some(mint_ref_opt), error::not_found(EMINT_REF_NOT_FOUND));    (option::extract(mint_ref_opt), MintRefReceipt { metadata })}return_paired_mint_ref
Return the MintRef with the hot potato receipt.
public fun return_paired_mint_ref(mint_ref: fungible_asset::MintRef, receipt: coin::MintRefReceipt)Implementation
public fun return_paired_mint_ref(    mint_ref: MintRef, receipt: MintRefReceipt) acquires PairedFungibleAssetRefs {    let MintRefReceipt { metadata } = receipt;    assert!(        fungible_asset::mint_ref_metadata(&mint_ref) == metadata,        error::invalid_argument(EMINT_REF_RECEIPT_MISMATCH)    );    let metadata_addr = object_address(&metadata);    let mint_ref_opt =        &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).mint_ref_opt;    option::fill(mint_ref_opt, mint_ref);}paired_transfer_ref_exists
Check whether TransferRef still exists.
#[view]public fun paired_transfer_ref_exists<CoinType>(): boolImplementation
public fun paired_transfer_ref_exists<CoinType>(): bool acquires CoinConversionMap, PairedFungibleAssetRefs {    let metadata = assert_paired_metadata_exists<CoinType>();    let metadata_addr = object_address(&metadata);    assert!(        exists<PairedFungibleAssetRefs>(metadata_addr),        error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)    );    option::is_some(        &borrow_global<PairedFungibleAssetRefs>(metadata_addr).transfer_ref_opt    )}get_paired_transfer_ref
Get the TransferRef of paired fungible asset of a coin type from FreezeCapability.
public fun get_paired_transfer_ref<CoinType>(_: &coin::FreezeCapability<CoinType>): (fungible_asset::TransferRef, coin::TransferRefReceipt)Implementation
public fun get_paired_transfer_ref<CoinType>(    _: &FreezeCapability<CoinType>): (TransferRef, TransferRefReceipt) acquires CoinConversionMap, PairedFungibleAssetRefs {    let metadata = assert_paired_metadata_exists<CoinType>();    let metadata_addr = object_address(&metadata);    assert!(        exists<PairedFungibleAssetRefs>(metadata_addr),        error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)    );    let transfer_ref_opt =        &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).transfer_ref_opt;    assert!(        option::is_some(transfer_ref_opt),        error::not_found(ETRANSFER_REF_NOT_FOUND)    );    (option::extract(transfer_ref_opt), TransferRefReceipt { metadata })}return_paired_transfer_ref
Return the TransferRef with the hot potato receipt.
public fun return_paired_transfer_ref(transfer_ref: fungible_asset::TransferRef, receipt: coin::TransferRefReceipt)Implementation
public fun return_paired_transfer_ref(    transfer_ref: TransferRef, receipt: TransferRefReceipt) acquires PairedFungibleAssetRefs {    let TransferRefReceipt { metadata } = receipt;    assert!(        fungible_asset::transfer_ref_metadata(&transfer_ref) == metadata,        error::invalid_argument(ETRANSFER_REF_RECEIPT_MISMATCH)    );    let metadata_addr = object_address(&metadata);    let transfer_ref_opt =        &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).transfer_ref_opt;    option::fill(transfer_ref_opt, transfer_ref);}paired_burn_ref_exists
Check whether BurnRef has not been taken.
#[view]public fun paired_burn_ref_exists<CoinType>(): boolImplementation
public fun paired_burn_ref_exists<CoinType>(): bool acquires CoinConversionMap, PairedFungibleAssetRefs {    let metadata = assert_paired_metadata_exists<CoinType>();    let metadata_addr = object_address(&metadata);    assert!(        exists<PairedFungibleAssetRefs>(metadata_addr),        error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)    );    option::is_some(        &borrow_global<PairedFungibleAssetRefs>(metadata_addr).burn_ref_opt    )}get_paired_burn_ref
Get the BurnRef of paired fungible asset of a coin type from BurnCapability.
public fun get_paired_burn_ref<CoinType>(_: &coin::BurnCapability<CoinType>): (fungible_asset::BurnRef, coin::BurnRefReceipt)Implementation
public fun get_paired_burn_ref<CoinType>(    _: &BurnCapability<CoinType>): (BurnRef, BurnRefReceipt) acquires CoinConversionMap, PairedFungibleAssetRefs {    let metadata = assert_paired_metadata_exists<CoinType>();    let metadata_addr = object_address(&metadata);    assert!(        exists<PairedFungibleAssetRefs>(metadata_addr),        error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)    );    let burn_ref_opt =        &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).burn_ref_opt;    assert!(option::is_some(burn_ref_opt), error::not_found(EBURN_REF_NOT_FOUND));    (option::extract(burn_ref_opt), BurnRefReceipt { metadata })}convert_and_take_paired_burn_ref
public fun convert_and_take_paired_burn_ref<CoinType>(burn_cap: coin::BurnCapability<CoinType>): fungible_asset::BurnRefImplementation
public fun convert_and_take_paired_burn_ref<CoinType>(    burn_cap: BurnCapability<CoinType>): BurnRef acquires CoinConversionMap, PairedFungibleAssetRefs {    destroy_burn_cap(burn_cap);    let metadata = assert_paired_metadata_exists<CoinType>();    let metadata_addr = object_address(&metadata);    assert!(        exists<PairedFungibleAssetRefs>(metadata_addr),        error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)    );    let burn_ref_opt =        &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).burn_ref_opt;    assert!(option::is_some(burn_ref_opt), error::not_found(EBURN_REF_NOT_FOUND));    option::extract(burn_ref_opt)}return_paired_burn_ref
Return the BurnRef with the hot potato receipt.
public fun return_paired_burn_ref(burn_ref: fungible_asset::BurnRef, receipt: coin::BurnRefReceipt)Implementation
public fun return_paired_burn_ref(    burn_ref: BurnRef, receipt: BurnRefReceipt) acquires PairedFungibleAssetRefs {    let BurnRefReceipt { metadata } = receipt;    assert!(        fungible_asset::burn_ref_metadata(&burn_ref) == metadata,        error::invalid_argument(EBURN_REF_RECEIPT_MISMATCH)    );    let metadata_addr = object_address(&metadata);    let burn_ref_opt =        &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).burn_ref_opt;    option::fill(burn_ref_opt, burn_ref);}borrow_paired_burn_ref
fun borrow_paired_burn_ref<CoinType>(_: &coin::BurnCapability<CoinType>): &fungible_asset::BurnRefImplementation
inline fun borrow_paired_burn_ref<CoinType>(    _: &BurnCapability<CoinType>): &BurnRef {    let metadata = assert_paired_metadata_exists<CoinType>();    let metadata_addr = object_address(&metadata);    assert!(        exists<PairedFungibleAssetRefs>(metadata_addr),        error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)    );    let burn_ref_opt =        &borrow_global<PairedFungibleAssetRefs>(metadata_addr).burn_ref_opt;    assert!(option::is_some(burn_ref_opt), error::not_found(EBURN_REF_NOT_FOUND));    option::borrow(burn_ref_opt)}allow_supply_upgrades
This should be called by on-chain governance to update the config and allow or disallow upgradability of total supply.
public fun allow_supply_upgrades(_aptos_framework: &signer, _allowed: bool)Implementation
public fun allow_supply_upgrades(    _aptos_framework: &signer, _allowed: bool) {    abort error::invalid_state(ECOIN_SUPPLY_UPGRADE_NOT_SUPPORTED)}calculate_amount_to_withdraw
fun calculate_amount_to_withdraw<CoinType>(account_addr: address, amount: u64): (u64, u64)Implementation
inline fun calculate_amount_to_withdraw<CoinType>(    account_addr: address, amount: u64): (u64, u64) {    let coin_balance = coin_balance<CoinType>(account_addr);    if (coin_balance >= amount) {        (amount, 0)    } else {        let metadata = paired_metadata<CoinType>();        if (option::is_some(&metadata)            && primary_fungible_store::primary_store_exists(                account_addr, option::destroy_some(metadata)            ))            (coin_balance, amount - coin_balance)        else abort error::invalid_argument(EINSUFFICIENT_BALANCE)    }}maybe_convert_to_fungible_store
fun maybe_convert_to_fungible_store<CoinType>(account: address)Implementation
fun maybe_convert_to_fungible_store<CoinType>(    account: address) acquires CoinStore, CoinConversionMap, CoinInfo {    if (exists<CoinStore<CoinType>>(account)) {        let CoinStore<CoinType> { coin, frozen, deposit_events, withdraw_events } =            move_from<CoinStore<CoinType>>(account);        if (is_coin_initialized<CoinType>() && coin.value > 0) {            let metadata = ensure_paired_metadata<CoinType>();            let store =                primary_fungible_store::ensure_primary_store_exists(                    account, metadata                );
            event::emit(                CoinStoreDeletion {                    coin_type: type_info::type_name<CoinType>(),                    event_handle_creation_address: guid::creator_address(                        event::guid(&deposit_events)                    ),                    deleted_deposit_event_handle_creation_number: guid::creation_num(                        event::guid(&deposit_events)                    ),                    deleted_withdraw_event_handle_creation_number: guid::creation_num(                        event::guid(&withdraw_events)                    )                }            );
            if (coin.value == 0) {                destroy_zero(coin);            } else {                fungible_asset::unchecked_deposit_with_no_events(                    object_address(&store),                    coin_to_fungible_asset(coin)                );            };
            // Note:            // It is possible the primary fungible store may already exist before this function call.            // In this case, if the account owns a frozen CoinStore and an unfrozen primary fungible store, this            // function would convert and deposit the rest coin into the primary store and freeze it to make the            // `frozen` semantic as consistent as possible.            if (frozen != fungible_asset::is_frozen(store)) {                fungible_asset::set_frozen_flag_internal(store, frozen);            }        } else {            destroy_zero(coin);        };        event::destroy_handle(deposit_events);        event::destroy_handle(withdraw_events);    };}assert_signer_has_permission
fun assert_signer_has_permission<CoinType>(account: &signer)Implementation
inline fun assert_signer_has_permission<CoinType>(account: &signer) {    if (permissioned_signer::is_permissioned_signer(account)) {        fungible_asset::withdraw_permission_check_by_address(            account,            primary_fungible_store::primary_store_address(                signer::address_of(account),                ensure_paired_metadata<CoinType>()            ),            0        );    }}migrate_to_fungible_store
Voluntarily migrate to fungible store for CoinType if not yet.
public entry fun migrate_to_fungible_store<CoinType>(account: &signer)Implementation
public entry fun migrate_to_fungible_store<CoinType>(    account: &signer) acquires CoinStore, CoinConversionMap, CoinInfo {    let account_addr = signer::address_of(account);    assert_signer_has_permission<CoinType>(account);    maybe_convert_to_fungible_store<CoinType>(account_addr);}migrate_coin_store_to_fungible_store
Migrate to fungible store for CoinType if not yet.
public entry fun migrate_coin_store_to_fungible_store<CoinType>(accounts: vector<address>)Implementation
public entry fun migrate_coin_store_to_fungible_store<CoinType>(    accounts: vector<address>) acquires CoinStore, CoinConversionMap, CoinInfo {    if (features::new_accounts_default_to_fa_store_enabled()        || features::new_accounts_default_to_fa_apt_store_enabled()) {        std::vector::for_each(            accounts,            |account| {                maybe_convert_to_fungible_store<CoinType>(account);            }        );    }}coin_address
A helper function that returns the address of CoinType.
fun coin_address<CoinType>(): addressImplementation
fun coin_address<CoinType>(): address {    let type_info = type_info::type_of<CoinType>();    type_info::account_address(&type_info)}balance
Returns the balance of owner for provided CoinType and its paired FA if exists.
#[view]public fun balance<CoinType>(owner: address): u64Implementation
public fun balance<CoinType>(owner: address): u64 acquires CoinConversionMap, CoinStore {    let paired_metadata = paired_metadata<CoinType>();    coin_balance<CoinType>(owner)        + if (option::is_some(&paired_metadata)) {            primary_fungible_store::balance(                owner, option::extract(&mut paired_metadata)            )        } else { 0 }}is_balance_at_least
Returns whether the balance of owner for provided CoinType and its paired FA is >= amount.
#[view]public fun is_balance_at_least<CoinType>(owner: address, amount: u64): boolImplementation
public fun is_balance_at_least<CoinType>(    owner: address, amount: u64): bool acquires CoinConversionMap, CoinStore {    let coin_balance = coin_balance<CoinType>(owner);    if (coin_balance >= amount) {        return true    };
    let paired_metadata = paired_metadata<CoinType>();    let left_amount = amount - coin_balance;    if (option::is_some(&paired_metadata)) {        primary_fungible_store::is_balance_at_least(            owner,            option::extract(&mut paired_metadata),            left_amount        )    } else { false }}coin_balance
fun coin_balance<CoinType>(owner: address): u64Implementation
inline fun coin_balance<CoinType>(owner: address): u64 {    if (exists<CoinStore<CoinType>>(owner)) {        borrow_global<CoinStore<CoinType>>(owner).coin.value    } else { 0 }}is_coin_initialized
Returns true if the type CoinType is an initialized coin.
#[view]public fun is_coin_initialized<CoinType>(): boolImplementation
public fun is_coin_initialized<CoinType>(): bool {    exists<CoinInfo<CoinType>>(coin_address<CoinType>())}is_coin_store_frozen
Returns true is account_addr has frozen the CoinStore or if it’s not registered at all
#[view]public fun is_coin_store_frozen<CoinType>(account_addr: address): boolImplementation
public fun is_coin_store_frozen<CoinType>(account_addr: address): bool acquires CoinStore {    if (!is_account_registered<CoinType>(account_addr)) {        return true    };
    let coin_store = borrow_global<CoinStore<CoinType>>(account_addr);    coin_store.frozen}is_account_registered
Returns true if account_addr is registered to receive CoinType.
#[view]public fun is_account_registered<CoinType>(_account_addr: address): boolImplementation
public fun is_account_registered<CoinType>(_account_addr: address): bool {    assert!(        is_coin_initialized<CoinType>(),        error::invalid_argument(ECOIN_INFO_NOT_PUBLISHED)    );    true}name
Returns the name of the coin.
#[view]public fun name<CoinType>(): string::StringImplementation
public fun name<CoinType>(): string::String acquires CoinInfo {    borrow_global<CoinInfo<CoinType>>(coin_address<CoinType>()).name}symbol
Returns the symbol of the coin, usually a shorter version of the name.
#[view]public fun symbol<CoinType>(): string::StringImplementation
public fun symbol<CoinType>(): string::String acquires CoinInfo {    borrow_global<CoinInfo<CoinType>>(coin_address<CoinType>()).symbol}decimals
Returns the number of decimals used to get its user representation.
For example, if decimals equals 2, a balance of 505 coins should
be displayed to a user as 5.05 (505 / 10 ** 2).
#[view]public fun decimals<CoinType>(): u8Implementation
public fun decimals<CoinType>(): u8 acquires CoinInfo {    borrow_global<CoinInfo<CoinType>>(coin_address<CoinType>()).decimals}supply
Returns the amount of coin in existence.
#[view]public fun supply<CoinType>(): option::Option<u128>Implementation
public fun supply<CoinType>(): Option<u128> acquires CoinInfo, CoinConversionMap {    let coin_supply = coin_supply<CoinType>();    let metadata = paired_metadata<CoinType>();    if (option::is_some(&metadata)) {        let fungible_asset_supply =            fungible_asset::supply(option::extract(&mut metadata));        if (option::is_some(&coin_supply)) {            let supply = option::borrow_mut(&mut coin_supply);            *supply = *supply + option::destroy_some(fungible_asset_supply);        };    };    coin_supply}coin_supply
Returns the amount of coin in existence.
#[view]public fun coin_supply<CoinType>(): option::Option<u128>Implementation
public fun coin_supply<CoinType>(): Option<u128> acquires CoinInfo {    let maybe_supply =        &borrow_global<CoinInfo<CoinType>>(coin_address<CoinType>()).supply;    if (option::is_some(maybe_supply)) {        // We do track supply, in this case read from optional aggregator.        let supply = option::borrow(maybe_supply);        let value = optional_aggregator::read(supply);        option::some(value)    } else {        option::none()    }}burn
Burn coin with capability.
The capability _cap should be passed as a reference to BurnCapability<CoinType>.
public fun burn<CoinType>(coin: coin::Coin<CoinType>, _cap: &coin::BurnCapability<CoinType>)Implementation
public fun burn<CoinType>(    coin: Coin<CoinType>, _cap: &BurnCapability<CoinType>) acquires CoinInfo {    burn_internal(coin);}burn_from
Burn coin from the specified account with capability.
The capability burn_cap should be passed as a reference to BurnCapability<CoinType>.
This function shouldn’t fail as it’s called as part of transaction fee burning.
Note: This bypasses CoinStore::frozen — coins within a frozen CoinStore can be burned.
public fun burn_from<CoinType>(account_addr: address, amount: u64, burn_cap: &coin::BurnCapability<CoinType>)Implementation
public fun burn_from<CoinType>(    account_addr: address, amount: u64, burn_cap: &BurnCapability<CoinType>) acquires CoinInfo, CoinConversionMap, PairedFungibleAssetRefs {    // Skip burning if amount is zero. This shouldn't error out as it's called as part of transaction fee burning.    if (amount == 0) { return };    fungible_asset::burn_from(        borrow_paired_burn_ref(burn_cap),        primary_fungible_store::primary_store(            account_addr, ensure_paired_metadata<CoinType>()        ),        amount    );}burn_from_for_gas
public(friend) fun burn_from_for_gas<CoinType>(account_addr: address, amount: u64, burn_cap: &coin::BurnCapability<CoinType>)Implementation
public(friend) fun burn_from_for_gas<CoinType>(    account_addr: address, amount: u64, burn_cap: &BurnCapability<CoinType>) acquires CoinInfo, CoinConversionMap, PairedFungibleAssetRefs {    // Skip burning if amount is zero. This shouldn't error out as it's called as part of transaction fee burning.    if (amount == 0) { return };
    fungible_asset::address_burn_from_for_gas(        borrow_paired_burn_ref(burn_cap),        primary_fungible_store::primary_store_address(            account_addr, ensure_paired_metadata<CoinType>()        ),        amount    );}deposit
Deposit the coin balance into the recipient’s account and emit an event.
public fun deposit<CoinType>(account_addr: address, coin: coin::Coin<CoinType>)Implementation
public fun deposit<CoinType>(    account_addr: address, coin: Coin<CoinType>) acquires CoinConversionMap, CoinInfo {    primary_fungible_store::deposit(account_addr, coin_to_fungible_asset(coin));}deposit_with_signer
public fun deposit_with_signer<CoinType>(account: &signer, coin: coin::Coin<CoinType>)Implementation
public fun deposit_with_signer<CoinType>(    account: &signer, coin: Coin<CoinType>) acquires CoinConversionMap, CoinInfo {    let metadata = ensure_paired_metadata<CoinType>();    let account_address = signer::address_of(account);    fungible_asset::refill_permission(        account,        coin.value,        primary_fungible_store::primary_store_address_inlined(            account_address, metadata        )    );    deposit(account_address, coin);}deposit_for_gas_fee
Deposit the coin balance into the recipient’s account without checking if the account is frozen. This is for internal use only and doesn’t emit an DepositEvent.
public(friend) fun deposit_for_gas_fee<CoinType>(account_addr: address, coin: coin::Coin<CoinType>)Implementation
public(friend) fun deposit_for_gas_fee<CoinType>(    account_addr: address, coin: Coin<CoinType>) acquires CoinConversionMap, CoinInfo {    let fa = coin_to_fungible_asset(coin);    let metadata = fungible_asset::asset_metadata(&fa);    let store =        primary_fungible_store::ensure_primary_store_exists(account_addr, metadata);    fungible_asset::unchecked_deposit_with_no_events(        object::object_address(&store), fa    );}destroy_zero
Destroys a zero-value coin. Calls will fail if the value in the passed-in token is non-zero
so it is impossible to “burn” any non-zero amount of Coin without having
a BurnCapability for the specific CoinType.
public fun destroy_zero<CoinType>(zero_coin: coin::Coin<CoinType>)Implementation
public fun destroy_zero<CoinType>(zero_coin: Coin<CoinType>) {    spec {        update supply<CoinType> = supply<CoinType> - zero_coin.value;    };    let Coin { value } = zero_coin;    assert!(value == 0, error::invalid_argument(EDESTRUCTION_OF_NONZERO_TOKEN))}extract
Extracts amount from the passed-in coin, where the original token is modified in place.
public fun extract<CoinType>(coin: &mut coin::Coin<CoinType>, amount: u64): coin::Coin<CoinType>Implementation
public fun extract<CoinType>(coin: &mut Coin<CoinType>, amount: u64): Coin<CoinType> {    assert!(coin.value >= amount, error::invalid_argument(EINSUFFICIENT_BALANCE));    spec {        update supply<CoinType> = supply<CoinType> - amount;    };    coin.value = coin.value - amount;    spec {        update supply<CoinType> = supply<CoinType> + amount;    };    Coin { value: amount }}extract_all
Extracts the entire amount from the passed-in coin, where the original token is modified in place.
public fun extract_all<CoinType>(coin: &mut coin::Coin<CoinType>): coin::Coin<CoinType>Implementation
public fun extract_all<CoinType>(coin: &mut Coin<CoinType>): Coin<CoinType> {    let total_value = coin.value;    spec {        update supply<CoinType> = supply<CoinType> - coin.value;    };    coin.value = 0;    spec {        update supply<CoinType> = supply<CoinType> + total_value;    };    Coin { value: total_value }}freeze_coin_store
Freeze a CoinStore to prevent transfers
#[legacy_entry_fun]public entry fun freeze_coin_store<CoinType>(account_addr: address, _freeze_cap: &coin::FreezeCapability<CoinType>)Implementation
public entry fun freeze_coin_store<CoinType>(    account_addr: address, _freeze_cap: &FreezeCapability<CoinType>) acquires CoinStore {    let coin_store = borrow_global_mut<CoinStore<CoinType>>(account_addr);    coin_store.frozen = true;}unfreeze_coin_store
Unfreeze a CoinStore to allow transfers
#[legacy_entry_fun]public entry fun unfreeze_coin_store<CoinType>(account_addr: address, _freeze_cap: &coin::FreezeCapability<CoinType>)Implementation
public entry fun unfreeze_coin_store<CoinType>(    account_addr: address, _freeze_cap: &FreezeCapability<CoinType>) acquires CoinStore {    let coin_store = borrow_global_mut<CoinStore<CoinType>>(account_addr);    coin_store.frozen = false;}upgrade_supply
Upgrade total supply to use a parallelizable implementation if it is available.
public entry fun upgrade_supply<CoinType>(_account: &signer)Implementation
public entry fun upgrade_supply<CoinType>(_account: &signer) {    abort error::invalid_state(ECOIN_SUPPLY_UPGRADE_NOT_SUPPORTED)}initialize
Creates a new Coin with given CoinType and returns minting/freezing/burning capabilities.
The given signer also becomes the account hosting the information  about the coin
(name, supply, etc.). Supply is initialized as non-parallelizable integer.
public fun initialize<CoinType>(account: &signer, name: string::String, symbol: string::String, decimals: u8, monitor_supply: bool): (coin::BurnCapability<CoinType>, coin::FreezeCapability<CoinType>, coin::MintCapability<CoinType>)Implementation
public fun initialize<CoinType>(    account: &signer,    name: string::String,    symbol: string::String,    decimals: u8,    monitor_supply: bool): (BurnCapability<CoinType>, FreezeCapability<CoinType>, MintCapability<CoinType>) acquires CoinInfo, CoinConversionMap {    initialize_internal(        account,        name,        symbol,        decimals,        monitor_supply,        false    )}initialize_with_parallelizable_supply
Same as initialize but supply can be initialized to parallelizable aggregator.
public(friend) fun initialize_with_parallelizable_supply<CoinType>(account: &signer, name: string::String, symbol: string::String, decimals: u8, monitor_supply: bool): (coin::BurnCapability<CoinType>, coin::FreezeCapability<CoinType>, coin::MintCapability<CoinType>)Implementation
public(friend) fun initialize_with_parallelizable_supply<CoinType>(    account: &signer,    name: string::String,    symbol: string::String,    decimals: u8,    monitor_supply: bool): (BurnCapability<CoinType>, FreezeCapability<CoinType>, MintCapability<CoinType>) acquires CoinInfo, CoinConversionMap {    system_addresses::assert_aptos_framework(account);    initialize_internal(        account,        name,        symbol,        decimals,        monitor_supply,        true    )}initialize_internal
fun initialize_internal<CoinType>(account: &signer, name: string::String, symbol: string::String, decimals: u8, monitor_supply: bool, parallelizable: bool): (coin::BurnCapability<CoinType>, coin::FreezeCapability<CoinType>, coin::MintCapability<CoinType>)Implementation
fun initialize_internal<CoinType>(    account: &signer,    name: string::String,    symbol: string::String,    decimals: u8,    monitor_supply: bool,    parallelizable: bool): (BurnCapability<CoinType>, FreezeCapability<CoinType>, MintCapability<CoinType>) acquires CoinInfo, CoinConversionMap {    let account_addr = signer::address_of(account);    assert_signer_has_permission<CoinType>(account);
    assert!(        coin_address<CoinType>() == account_addr,        error::invalid_argument(ECOIN_INFO_ADDRESS_MISMATCH)    );
    assert!(        !exists<CoinInfo<CoinType>>(account_addr),        error::already_exists(ECOIN_INFO_ALREADY_PUBLISHED)    );
    assert!(        string::length(&name) <= MAX_COIN_NAME_LENGTH,        error::invalid_argument(ECOIN_NAME_TOO_LONG)    );    assert!(        string::length(&symbol) <= MAX_COIN_SYMBOL_LENGTH,        error::invalid_argument(ECOIN_SYMBOL_TOO_LONG)    );    assert!(        decimals <= MAX_DECIMALS, error::invalid_argument(ECOIN_DECIMALS_TOO_LARGE)    );
    let coin_info = CoinInfo<CoinType> {        name,        symbol,        decimals,        supply: if (monitor_supply) {            option::some(optional_aggregator::new(parallelizable))        } else {            option::none()        }    };    move_to(account, coin_info);
    (        BurnCapability<CoinType> {},        FreezeCapability<CoinType> {},        MintCapability<CoinType> {}    )}merge
“Merges” the two given coins.  The coin passed in as dst_coin will have a value equal
to the sum of the two tokens (dst_coin and source_coin).
public fun merge<CoinType>(dst_coin: &mut coin::Coin<CoinType>, source_coin: coin::Coin<CoinType>)Implementation
public fun merge<CoinType>(    dst_coin: &mut Coin<CoinType>, source_coin: Coin<CoinType>) {    spec {        assume dst_coin.value + source_coin.value <= MAX_U64;    };    spec {        update supply<CoinType> = supply<CoinType> - source_coin.value;    };    let Coin { value } = source_coin;    spec {        update supply<CoinType> = supply<CoinType> + value;    };    dst_coin.value = dst_coin.value + value;}mint
Mint new Coin with capability.
The capability _cap should be passed as reference to MintCapability<CoinType>.
Returns minted Coin.
public fun mint<CoinType>(amount: u64, _cap: &coin::MintCapability<CoinType>): coin::Coin<CoinType>Implementation
public fun mint<CoinType>(    amount: u64, _cap: &MintCapability<CoinType>): Coin<CoinType> acquires CoinInfo {    mint_internal<CoinType>(amount)}register
public fun register<CoinType>(account: &signer)Implementation
public fun register<CoinType>(account: &signer) acquires CoinInfo, CoinConversionMap {    let account_addr = signer::address_of(account);    assert_signer_has_permission<CoinType>(account);    // Short-circuit and do nothing if account is already registered for CoinType.    if (is_account_registered<CoinType>(account_addr)) { return };
    account::register_coin<CoinType>(account_addr);}transfer
Transfers amount of coins CoinType from from to to.
public entry fun transfer<CoinType>(from: &signer, to: address, amount: u64)Implementation
public entry fun transfer<CoinType>(    from: &signer, to: address, amount: u64) acquires CoinConversionMap, CoinInfo {    let fa =        primary_fungible_store::withdraw(            from, ensure_paired_metadata<CoinType>(), amount        );    primary_fungible_store::deposit(to, fa);}value
Returns the value passed in coin.
public fun value<CoinType>(coin: &coin::Coin<CoinType>): u64Implementation
public fun value<CoinType>(coin: &Coin<CoinType>): u64 {    coin.value}withdraw
Withdraw specified amount of coin CoinType from the signing account.
public fun withdraw<CoinType>(account: &signer, amount: u64): coin::Coin<CoinType>Implementation
public fun withdraw<CoinType>(    account: &signer, amount: u64): Coin<CoinType> acquires CoinConversionMap, CoinInfo, PairedCoinType {    let fa =        primary_fungible_store::withdraw(            account, ensure_paired_metadata<CoinType>(), amount        );    fungible_asset_to_coin(fa)}zero
Create a new Coin<CoinType> with a value of 0.
public fun zero<CoinType>(): coin::Coin<CoinType>Implementation
public fun zero<CoinType>(): Coin<CoinType> {    spec {        update supply<CoinType> = supply<CoinType> + 0;    };    Coin<CoinType> { value: 0 }}destroy_freeze_cap
Destroy a freeze capability. Freeze capability is dangerous and therefore should be destroyed if not used.
public fun destroy_freeze_cap<CoinType>(freeze_cap: coin::FreezeCapability<CoinType>)Implementation
public fun destroy_freeze_cap<CoinType>(    freeze_cap: FreezeCapability<CoinType>) {    let FreezeCapability<CoinType> {} = freeze_cap;}destroy_mint_cap
Destroy a mint capability.
public fun destroy_mint_cap<CoinType>(mint_cap: coin::MintCapability<CoinType>)Implementation
public fun destroy_mint_cap<CoinType>(    mint_cap: MintCapability<CoinType>) {    let MintCapability<CoinType> {} = mint_cap;}destroy_burn_cap
Destroy a burn capability.
public fun destroy_burn_cap<CoinType>(burn_cap: coin::BurnCapability<CoinType>)Implementation
public fun destroy_burn_cap<CoinType>(    burn_cap: BurnCapability<CoinType>) {    let BurnCapability<CoinType> {} = burn_cap;}mint_internal
fun mint_internal<CoinType>(amount: u64): coin::Coin<CoinType>Implementation
fun mint_internal<CoinType>(amount: u64): Coin<CoinType> acquires CoinInfo {    if (amount == 0) {        return Coin<CoinType> { value: 0 }    };
    let maybe_supply =        &mut borrow_global_mut<CoinInfo<CoinType>>(coin_address<CoinType>()).supply;    if (option::is_some(maybe_supply)) {        let supply = option::borrow_mut(maybe_supply);        spec {            use aptos_framework::optional_aggregator;            use aptos_framework::aggregator;            assume optional_aggregator::is_parallelizable(supply) ==> (aggregator::spec_aggregator_get_val(                option::borrow(supply.aggregator)            )                + amount <= aggregator::spec_get_limit(option::borrow(supply.aggregator)));            assume !optional_aggregator::is_parallelizable(supply) ==>                (option::borrow(supply.integer).value + amount <= option::borrow(supply.integer).limit);        };        optional_aggregator::add(supply, (amount as u128));    };    spec {        update supply<CoinType> = supply<CoinType> + amount;    };    Coin<CoinType> { value: amount }}burn_internal
fun burn_internal<CoinType>(coin: coin::Coin<CoinType>): u64Implementation
fun burn_internal<CoinType>(coin: Coin<CoinType>): u64 acquires CoinInfo {    spec {        update supply<CoinType> = supply<CoinType> - coin.value;    };    let Coin { value: amount } = coin;    if (amount != 0) {        let maybe_supply =            &mut borrow_global_mut<CoinInfo<CoinType>>(coin_address<CoinType>()).supply;        if (option::is_some(maybe_supply)) {            let supply = option::borrow_mut(maybe_supply);            optional_aggregator::sub(supply, (amount as u128));        };    };    amount}Specification
High-level Requirements
| No. | Requirement | Criticality | Implementation | Enforcement | 
|---|---|---|---|---|
| 1 | Only the owner of a coin may mint, burn or freeze coins. | Critical | Acquiring capabilities for a particular CoinType may only occur if the caller has a signer for the module declaring that type. The initialize function returns these capabilities to the caller. | Formally Verified via upgrade_supply and initialize. | 
| 2 | Each coin may only be created exactly once. | Medium | The initialization function may only be called once. | Formally Verified via initialize. | 
| 3 | The merging of coins may only be done on coins of the same type. | Critical | The merge function is limited to merging coins of the same type only. | Formally Verified via merge. | 
| 4 | The supply of a coin is only affected by burn and mint operations. | High | Only mint and burn operations on a coin alter the total supply of coins. | Formally Verified via TotalSupplyNoChange. | 
| 5 | Users may register an account for a coin multiple times idempotently. | Medium | The register function should work idempotently. Importantly, it should not abort if the coin is already registered. | Formally verified via aborts_if on register. | 
| 6 | Coin operations should fail if the user has not registered for the coin. | Medium | Coin operations may succeed only on valid user coin registration. | Formally Verified via balance, burn_from, freeze, unfreeze, transfer and withdraw. | 
| 7 | It should always be possible to (1) determine if a coin exists, and (2) determine if a user registered an account with a particular coin. If a coin exists, it should always be possible to request the following information of the coin: (1) Name, (2) Symbol, and (3) Supply. | Low | The following functions should never abort: (1) is_coin_initialized, and (2) is_account_registered. The following functions should not abort if the coin exists: (1) name, (2) symbol, and (3) supply. | Formally Verified in corresponding functions: is_coin_initialized, is_account_registered, name, symbol and supply. | 
| 8 | Coin operations should fail if the user's CoinStore is frozen. | Medium | If the CoinStore of an address is frozen, coin operations are disallowed. | Formally Verified via withdraw, transfer and deposit. | 
| 9 | Utilizing AggregatableCoins does not violate other critical invariants, such as (4). | High | Utilizing AggregatableCoin does not change the real-supply of any token. | Formally Verified via TotalSupplyNoChange. | 
Module-level Specification
pragma verify = true;pragma aborts_if_is_partial;
global supply<CoinType>: num;
global aggregate_supply<CoinType>: num;apply TotalSupplyTracked<CoinType> to *<CoinType> except initialize, initialize_internal, initialize_with_parallelizable_supply;fun spec_fun_supply_tracked<CoinType>(val: u64, supply: Option<OptionalAggregator>): bool {   option::is_some(supply) ==>       val           == optional_aggregator::optional_aggregator_value(               option::borrow(supply)           )}schema TotalSupplyTracked<CoinType> {    ensures old(        spec_fun_supply_tracked<CoinType>(            supply<CoinType> + aggregate_supply<CoinType>,            global<CoinInfo<CoinType>>(type_info::type_of<CoinType>().account_address)            .supply        )    ) ==>        spec_fun_supply_tracked<CoinType>(            supply<CoinType> + aggregate_supply<CoinType>,            global<CoinInfo<CoinType>>(type_info::type_of<CoinType>().account_address)            .supply        );}fun spec_fun_supply_no_change<CoinType>(   old_supply: Option<OptionalAggregator>, supply: Option<OptionalAggregator>): bool {   option::is_some(old_supply) ==>       optional_aggregator::optional_aggregator_value(           option::borrow(old_supply)       ) == optional_aggregator::optional_aggregator_value(           option::borrow(supply)       )}schema TotalSupplyNoChange<CoinType> {    let old_supply = global<CoinInfo<CoinType>>(        type_info::type_of<CoinType>().account_address    ).supply;    let post supply = global<CoinInfo<CoinType>>(        type_info::type_of<CoinType>().account_address    ).supply;    ensures spec_fun_supply_no_change<CoinType>(old_supply, supply);}AggregatableCoin
#[deprecated]struct AggregatableCoin<CoinType> has store- 
value: aggregator::Aggregator - Amount of aggregatable coin this address has.
 
invariant aggregator::spec_get_limit(value) == MAX_U64;coin_to_fungible_asset
public fun coin_to_fungible_asset<CoinType>(coin: coin::Coin<CoinType>): fungible_asset::FungibleAssetpragma verify = false;let addr = type_info::type_of<CoinType>().account_address;modifies global<CoinInfo<CoinType>>(addr);fungible_asset_to_coin
fun fungible_asset_to_coin<CoinType>(fungible_asset: fungible_asset::FungibleAsset): coin::Coin<CoinType>pragma verify = false;allow_supply_upgrades
public fun allow_supply_upgrades(_aptos_framework: &signer, _allowed: bool)Can only be updated by @aptos_framework.
aborts_if true;maybe_convert_to_fungible_store
fun maybe_convert_to_fungible_store<CoinType>(account: address)pragma verify = false;modifies global<CoinInfo<CoinType>>(account);modifies global<CoinStore<CoinType>>(account);schema DepositAbortsIf<CoinType> {    account_addr: address;    let coin_store = global<CoinStore<CoinType>>(account_addr);    aborts_if !exists<CoinStore<CoinType>>(account_addr);    aborts_if coin_store.frozen;}coin_address
fun coin_address<CoinType>(): addressGet address by reflection.
pragma opaque;aborts_if [abstract] false;ensures [abstract] result == type_info::type_of<CoinType>().account_address;balance
#[view]public fun balance<CoinType>(owner: address): u64pragma verify = false;aborts_if !exists<CoinStore<CoinType>>(owner);ensures result == global<CoinStore<CoinType>>(owner).coin.value;is_coin_initialized
#[view]public fun is_coin_initialized<CoinType>(): bool// This enforces high-level requirement 7:aborts_if false;is_account_registered
#[view]public fun is_account_registered<CoinType>(_account_addr: address): boolpragma aborts_if_is_partial;aborts_if false;fun get_coin_supply_opt<CoinType>(): Option<OptionalAggregator> {   global<CoinInfo<CoinType>>(type_info::type_of<CoinType>().account_address).supply}fun spec_paired_metadata<CoinType>(): Option<Object<Metadata>> {   if (exists<CoinConversionMap>(@aptos_framework)) {       let map =           global<CoinConversionMap>(@aptos_framework).coin_to_fungible_asset_map;       if (table::spec_contains(map, type_info::type_of<CoinType>())) {           let metadata = table::spec_get(map, type_info::type_of<CoinType>());           option::spec_some(metadata)       } else {           option::spec_none()       }   } else {       option::spec_none()   }}fun spec_is_account_registered<CoinType>(account_addr: address): bool;pragma aborts_if_is_partial;aborts_if false;ensures [abstract] result    == spec_is_account_registered<CoinType>(_account_addr);schema CoinSubAbortsIf<CoinType> {    amount: u64;    let addr = type_info::type_of<CoinType>().account_address;    let maybe_supply = global<CoinInfo<CoinType>>(addr).supply;    include (option::is_some(        maybe_supply    )) ==> optional_aggregator::SubAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount };}schema CoinAddAbortsIf<CoinType> {    amount: u64;    let addr = type_info::type_of<CoinType>().account_address;    let maybe_supply = global<CoinInfo<CoinType>>(addr).supply;    include (option::is_some(        maybe_supply    )) ==> optional_aggregator::AddAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount };}name
#[view]public fun name<CoinType>(): string::String// This enforces high-level requirement 7:include AbortsIfNotExistCoinInfo<CoinType>;symbol
#[view]public fun symbol<CoinType>(): string::String// This enforces high-level requirement 7:include AbortsIfNotExistCoinInfo<CoinType>;decimals
#[view]public fun decimals<CoinType>(): u8include AbortsIfNotExistCoinInfo<CoinType>;supply
#[view]public fun supply<CoinType>(): option::Option<u128>pragma verify = false;coin_supply
#[view]public fun coin_supply<CoinType>(): option::Option<u128>let coin_addr = type_info::type_of<CoinType>().account_address;// This enforces high-level requirement 7:aborts_if !exists<CoinInfo<CoinType>>(coin_addr);let maybe_supply = global<CoinInfo<CoinType>>(coin_addr).supply;let supply = option::borrow(maybe_supply);let value = optional_aggregator::optional_aggregator_value(supply);ensures if (option::is_some(maybe_supply)) {    result == option::spec_some(value)} else {    option::is_none(result)};burn
public fun burn<CoinType>(coin: coin::Coin<CoinType>, _cap: &coin::BurnCapability<CoinType>)pragma verify = false;let addr = type_info::type_of<CoinType>().account_address;modifies global<CoinInfo<CoinType>>(addr);include AbortsIfNotExistCoinInfo<CoinType>;aborts_if coin.value == 0;include CoinSubAbortsIf<CoinType> { amount: coin.value };ensures supply<CoinType> == old(supply<CoinType>) - coin.value;burn_from
public fun burn_from<CoinType>(account_addr: address, amount: u64, burn_cap: &coin::BurnCapability<CoinType>)pragma verify = false;let addr = type_info::type_of<CoinType>().account_address;let coin_store = global<CoinStore<CoinType>>(account_addr);let post post_coin_store = global<CoinStore<CoinType>>(account_addr);modifies global<CoinInfo<CoinType>>(addr);modifies global<CoinStore<CoinType>>(account_addr);// This enforces high-level requirement 6:aborts_if amount != 0 && !exists<CoinInfo<CoinType>>(addr);aborts_if amount != 0 && !exists<CoinStore<CoinType>>(account_addr);aborts_if coin_store.coin.value < amount;let maybe_supply = global<CoinInfo<CoinType>>(addr).supply;let supply_aggr = option::borrow(maybe_supply);let value = optional_aggregator::optional_aggregator_value(supply_aggr);let post post_maybe_supply = global<CoinInfo<CoinType>>(addr).supply;let post post_supply = option::borrow(post_maybe_supply);let post post_value = optional_aggregator::optional_aggregator_value(post_supply);aborts_if option::is_some(maybe_supply) && value < amount;ensures post_coin_store.coin.value == coin_store.coin.value - amount;// This enforces high-level requirement 5 of the managed_coin module:ensures if (option::is_some(maybe_supply)) {    post_value == value - amount} else {    option::is_none(post_maybe_supply)};ensures supply<CoinType> == old(supply<CoinType>) - amount;deposit
public fun deposit<CoinType>(account_addr: address, coin: coin::Coin<CoinType>)account_addr is not frozen.
pragma verify = false;modifies global<CoinInfo<CoinType>>(account_addr);// This enforces high-level requirement 8:include DepositAbortsIf<CoinType>;ensures global<CoinStore<CoinType>>(account_addr).coin.value    == old(global<CoinStore<CoinType>>(account_addr)).coin.value + coin.value;deposit_for_gas_fee
public(friend) fun deposit_for_gas_fee<CoinType>(account_addr: address, coin: coin::Coin<CoinType>)pragma verify = false;modifies global<CoinStore<CoinType>>(account_addr);aborts_if !exists<CoinStore<CoinType>>(account_addr);ensures global<CoinStore<CoinType>>(account_addr).coin.value    == old(global<CoinStore<CoinType>>(account_addr)).coin.value + coin.value;destroy_zero
public fun destroy_zero<CoinType>(zero_coin: coin::Coin<CoinType>)The value of zero_coin must be 0.
aborts_if zero_coin.value > 0;extract
public fun extract<CoinType>(coin: &mut coin::Coin<CoinType>, amount: u64): coin::Coin<CoinType>aborts_if coin.value < amount;ensures result.value == amount;ensures coin.value == old(coin.value) - amount;extract_all
public fun extract_all<CoinType>(coin: &mut coin::Coin<CoinType>): coin::Coin<CoinType>ensures result.value == old(coin).value;ensures coin.value == 0;freeze_coin_store
#[legacy_entry_fun]public entry fun freeze_coin_store<CoinType>(account_addr: address, _freeze_cap: &coin::FreezeCapability<CoinType>)pragma verify = false;modifies global<CoinStore<CoinType>>(account_addr);// This enforces high-level requirement 6:aborts_if !exists<CoinStore<CoinType>>(account_addr);let post coin_store = global<CoinStore<CoinType>>(account_addr);ensures coin_store.frozen;unfreeze_coin_store
#[legacy_entry_fun]public entry fun unfreeze_coin_store<CoinType>(account_addr: address, _freeze_cap: &coin::FreezeCapability<CoinType>)pragma verify = false;modifies global<CoinStore<CoinType>>(account_addr);// This enforces high-level requirement 6:aborts_if !exists<CoinStore<CoinType>>(account_addr);let post coin_store = global<CoinStore<CoinType>>(account_addr);ensures !coin_store.frozen;upgrade_supply
public entry fun upgrade_supply<CoinType>(_account: &signer)The creator of CoinType must be @aptos_framework.
SupplyConfig allow upgrade.
aborts_if true;initialize
public fun initialize<CoinType>(account: &signer, name: string::String, symbol: string::String, decimals: u8, monitor_supply: bool): (coin::BurnCapability<CoinType>, coin::FreezeCapability<CoinType>, coin::MintCapability<CoinType>)let account_addr = signer::address_of(account);// This enforces high-level requirement 1:aborts_if type_info::type_of<CoinType>().account_address != account_addr;// This enforces high-level requirement 2:aborts_if exists<CoinInfo<CoinType>>(account_addr);aborts_if string::length(name) > MAX_COIN_NAME_LENGTH;aborts_if string::length(symbol) > MAX_COIN_SYMBOL_LENGTH;initialize_with_parallelizable_supply
public(friend) fun initialize_with_parallelizable_supply<CoinType>(account: &signer, name: string::String, symbol: string::String, decimals: u8, monitor_supply: bool): (coin::BurnCapability<CoinType>, coin::FreezeCapability<CoinType>, coin::MintCapability<CoinType>)let addr = signer::address_of(account);aborts_if addr != @aptos_framework;aborts_if monitor_supply    && !exists<aggregator_factory::AggregatorFactory>(@aptos_framework);include InitializeInternalSchema<CoinType> {    name: name.bytes,    symbol: symbol.bytes};ensures exists<CoinInfo<CoinType>>(addr);Make sure name and symbol are legal length.
Only the creator of CoinType can initialize.
schema InitializeInternalSchema<CoinType> {    account: signer;    name: vector<u8>;    symbol: vector<u8>;    let account_addr = signer::address_of(account);    let coin_address = type_info::type_of<CoinType>().account_address;    aborts_if coin_address != account_addr;    aborts_if exists<CoinInfo<CoinType>>(account_addr);    aborts_if len(name) > MAX_COIN_NAME_LENGTH;    aborts_if len(symbol) > MAX_COIN_SYMBOL_LENGTH;}initialize_internal
fun initialize_internal<CoinType>(account: &signer, name: string::String, symbol: string::String, decimals: u8, monitor_supply: bool, parallelizable: bool): (coin::BurnCapability<CoinType>, coin::FreezeCapability<CoinType>, coin::MintCapability<CoinType>)include InitializeInternalSchema<CoinType> {    name: name.bytes,    symbol: symbol.bytes};let account_addr = signer::address_of(account);let post coin_info = global<CoinInfo<CoinType>>(account_addr);let post supply = option::borrow(coin_info.supply);let post value = optional_aggregator::optional_aggregator_value(supply);let post limit = optional_aggregator::optional_aggregator_limit(supply);modifies global<CoinInfo<CoinType>>(account_addr);aborts_if monitor_supply    && parallelizable    && !exists<aggregator_factory::AggregatorFactory>(@aptos_framework);// This enforces high-level requirement 2 of the managed_coin module:ensures exists<CoinInfo<CoinType>>(account_addr)    && coin_info.name == name    && coin_info.symbol == symbol && coin_info.decimals == decimals;ensures if (monitor_supply) {    value == 0        && limit == MAX_U128        && (parallelizable == optional_aggregator::is_parallelizable(supply))} else {    option::is_none(coin_info.supply)};ensures result_1 == BurnCapability<CoinType> {};ensures result_2 == FreezeCapability<CoinType> {};ensures result_3 == MintCapability<CoinType> {};merge
public fun merge<CoinType>(dst_coin: &mut coin::Coin<CoinType>, source_coin: coin::Coin<CoinType>)// This enforces high-level requirement 3:ensures dst_coin.value == old(dst_coin.value) + source_coin.value;mint
public fun mint<CoinType>(amount: u64, _cap: &coin::MintCapability<CoinType>): coin::Coin<CoinType>let addr = type_info::type_of<CoinType>().account_address;modifies global<CoinInfo<CoinType>>(addr);register
public fun register<CoinType>(account: &signer)An account can only be registered once.
Updating Account.guid_creation_num will not overflow.
pragma verify = false;transfer
public entry fun transfer<CoinType>(from: &signer, to: address, amount: u64)from and to account not frozen.
from and to not the same address.
from account sufficient balance.
pragma verify = false;let account_addr_from = signer::address_of(from);let coin_store_from = global<CoinStore<CoinType>>(account_addr_from);let post coin_store_post_from = global<CoinStore<CoinType>>(account_addr_from);let coin_store_to = global<CoinStore<CoinType>>(to);let post coin_store_post_to = global<CoinStore<CoinType>>(to);// This enforces high-level requirement 6:aborts_if !exists<CoinStore<CoinType>>(account_addr_from);aborts_if !exists<CoinStore<CoinType>>(to);// This enforces high-level requirement 8:aborts_if coin_store_from.frozen;aborts_if coin_store_to.frozen;aborts_if coin_store_from.coin.value < amount;ensures account_addr_from != to ==>    coin_store_post_from.coin.value == coin_store_from.coin.value - amount;ensures account_addr_from != to ==>    coin_store_post_to.coin.value == coin_store_to.coin.value + amount;ensures account_addr_from == to ==>    coin_store_post_from.coin.value == coin_store_from.coin.value;withdraw
public fun withdraw<CoinType>(account: &signer, amount: u64): coin::Coin<CoinType>Account is not frozen and sufficient balance.
pragma verify = false;include WithdrawAbortsIf<CoinType>;modifies global<CoinStore<CoinType>>(account_addr);let account_addr = signer::address_of(account);let coin_store = global<CoinStore<CoinType>>(account_addr);let balance = coin_store.coin.value;let post coin_post = global<CoinStore<CoinType>>(account_addr).coin.value;ensures coin_post == balance - amount;ensures result == Coin<CoinType> { value: amount };schema WithdrawAbortsIf<CoinType> {    account: &signer;    amount: u64;    let account_addr = signer::address_of(account);    let coin_store = global<CoinStore<CoinType>>(account_addr);    let balance = coin_store.coin.value;    // This enforces high-level requirement 6:    aborts_if !exists<CoinStore<CoinType>>(account_addr);    // This enforces high-level requirement 8:    aborts_if coin_store.frozen;    aborts_if balance < amount;}mint_internal
fun mint_internal<CoinType>(amount: u64): coin::Coin<CoinType>let addr = type_info::type_of<CoinType>().account_address;modifies global<CoinInfo<CoinType>>(addr);aborts_if (amount != 0) && !exists<CoinInfo<CoinType>>(addr);ensures supply<CoinType> == old(supply<CoinType>) + amount;ensures result.value == amount;burn_internal
fun burn_internal<CoinType>(coin: coin::Coin<CoinType>): u64pragma verify = false;let addr = type_info::type_of<CoinType>().account_address;modifies global<CoinInfo<CoinType>>(addr);