Skip to main content

Module 0x2::coin_manager

The purpose of a CoinManager is to allow access to all properties of a Coin on-chain from within a single shared object This includes access to the total supply and metadata In addition a optional maximum supply can be set and a custom additional Metadata field can be added.

use 0x1::ascii; use 0x1::option; use 0x1::string; use 0x1::type_name; use 0x2::balance; use 0x2::coin; use 0x2::dynamic_field; use 0x2::event; use 0x2::object; use 0x2::tx_context; use 0x2::url;

Resource CoinManager

Holds all related objects to a Coin in a convenient shared function

struct CoinManager<T> has store, key

Fields
id: object::UID
treasury_cap: coin::TreasuryCap<T>

The original TreasuryCap object as returned by create_currency

metadata: option::Option<coin::CoinMetadata<T>>

Metadata object, original one from the coin module, if available

immutable_metadata: option::Option<coin_manager::ImmutableCoinMetadata<T>>

Immutable Metadata object, only to be used as a last resort if the original metadata is frozen

maximum_supply: option::Option<u64>

Optional maximum supply, if set you can't mint more as this number - can only be set once

supply_immutable: bool

Flag indicating if the supply is considered immutable (TreasuryCap is exchanged for this)

metadata_immutable: bool

Flag indicating if the metadata is considered immutable (MetadataCap is exchanged for this)

Resource CoinManagerTreasuryCap

Like TreasuryCap, but for dealing with TreasuryCap inside CoinManager objects

struct CoinManagerTreasuryCap<T> has store, key

Fields

Resource CoinManagerMetadataCap

Metadata has it's own Cap, independent of the TreasuryCap

struct CoinManagerMetadataCap<T> has store, key

Fields

Struct ImmutableCoinMetadata

The immutable version of CoinMetadata, used in case of migrating from frozen objects to a CoinManager holding the metadata.

struct ImmutableCoinMetadata<T> has store

Fields
decimals: u8

Number of decimal places the coin uses. A coin with value N and decimals D should be shown as N / 10^D E.g., a coin with value 7002 and decimals 3 should be displayed as 7.002 This is metadata for display usage only.

name: string::String

Name for the token

symbol: ascii::String

Symbol for the token

description: string::String

Description of the token

icon_url: option::Option<url::Url>

URL for the token logo

Struct CoinManaged

Event triggered once Coin ownership is transfered to a new CoinManager

struct CoinManaged has copy, drop

Fields
coin_name: ascii::String

Struct TreasuryOwnershipRenounced

Event triggered if the ownership of the treasury part of a CoinManager is renounced

struct TreasuryOwnershipRenounced has copy, drop

Fields
coin_name: ascii::String

Struct MetadataOwnershipRenounced

Event triggered if the ownership of the metadata part of a CoinManager is renounced

struct MetadataOwnershipRenounced has copy, drop

Fields
coin_name: ascii::String

Constants

The error returned if additional metadata already exists and you try to overwrite

const EAdditionalMetadataAlreadyExists: u64 = 3;

The error returned if you try to edit nonexisting additional metadata

const EAdditionalMetadataDoesNotExist: u64 = 4;

The error returned if a attempt is made to change the maximum supply after setting it

const EMaximumSupplyAlreadySet: u64 = 1;

The error returned if a attempt is made to change the maximum supply that is lower than the total supply

const EMaximumSupplyLowerThanTotalSupply: u64 = 2;

The error returned when the maximum supply reached

const EMaximumSupplyReached: u64 = 0;

The error returned if you try to edit immutable metadata

const ENoMutableMetadata: u64 = 5;

Function new

Wraps all important objects related to a Coin inside a shared object

public fun new<T>(treasury_cap: coin::TreasuryCap<T>, metadata: coin::CoinMetadata<T>, ctx: &mut tx_context::TxContext): (coin_manager::CoinManagerTreasuryCap<T>, coin_manager::CoinManagerMetadataCap<T>, coin_manager::CoinManager<T>)

Implementation

public fun new<T> ( treasury_cap: TreasuryCap<T>, metadata: CoinMetadata<T>, ctx: &mut TxContext, ): (CoinManagerTreasuryCap<T>, CoinManagerMetadataCap<T>, CoinManager<T>) {

let manager = CoinManager { id: object::new(ctx), treasury_cap, metadata: option::some(metadata), immutable_metadata: option::none(), maximum_supply: option::none(), supply_immutable: false, metadata_immutable: false };

event::emit(CoinManaged { coin_name: type_name::into_string(type_name::get<T>()) });

( CoinManagerTreasuryCap<T> { id: object::new(ctx) }, CoinManagerMetadataCap<T> { id: object::new(ctx) }, manager ) }

Function new_with_immutable_metadata

This function allows the same as new but under the assumption the Metadata can not be transfered This would typically be the case with Coin instances where the metadata is already frozen.

public fun new_with_immutable_metadata<T>(treasury_cap: coin::TreasuryCap<T>, metadata: &coin::CoinMetadata<T>, ctx: &mut tx_context::TxContext): (coin_manager::CoinManagerTreasuryCap<T>, coin_manager::CoinManager<T>)

Implementation

public fun new_with_immutable_metadata<T> ( treasury_cap: TreasuryCap<T>, metadata: &CoinMetadata<T>, ctx: &mut TxContext, ): (CoinManagerTreasuryCap<T>, CoinManager<T>) {

let metacopy = ImmutableCoinMetadata<T> { decimals: metadata.get_decimals(), name: metadata.get_name(), symbol: metadata.get_symbol(), description: metadata.get_description(), icon_url: metadata.get_icon_url() };

let manager = CoinManager { id: object::new(ctx), treasury_cap, metadata: option::none(), immutable_metadata: option::some(metacopy), maximum_supply: option::none(), supply_immutable: false, metadata_immutable: true };

event::emit(CoinManaged { coin_name: type_name::into_string(type_name::get<T>()) });

( CoinManagerTreasuryCap<T> { id: object::new(ctx) }, manager ) }

Function create

Convenience wrapper to create a new Coin and instantly wrap the cap inside a CoinManager

public fun create<T: drop>(witness: T, decimals: u8, symbol: vector<u8>, name: vector<u8>, description: vector<u8>, icon_url: option::Option<url::Url>, ctx: &mut tx_context::TxContext): (coin_manager::CoinManagerTreasuryCap<T>, coin_manager::CoinManagerMetadataCap<T>, coin_manager::CoinManager<T>)

Implementation

public fun create<T: drop> ( witness: T, decimals: u8, symbol: vector<u8>, name: vector<u8>, description: vector<u8>, icon_url: Option<Url>, ctx: &mut TxContext ): (CoinManagerTreasuryCap<T>, CoinManagerMetadataCap<T>, CoinManager<T>) {

let (cap, meta) = coin::create_currency( witness, decimals, symbol, name, description, icon_url, ctx );

new(cap, meta, ctx) }

Function add_additional_metadata

public fun add_additional_metadata<T, Value: store>(_: &coin_manager::CoinManagerMetadataCap<T>, manager: &mut coin_manager::CoinManager<T>, value: Value)

Implementation

public fun add_additional_metadata<T, Value: store>( : &CoinManagerMetadataCap<T>, manager: &mut CoinManager<T>, value: Value ) { assert!(!df::exists(&manager.id, b"additional_metadata"), EAdditionalMetadataAlreadyExists); df::add(&mut manager.id, b"additional_metadata", value); }

Function replace_additional_metadata

public fun replace_additional_metadata<T, Value: store, OldValue: store>(_: &coin_manager::CoinManagerMetadataCap<T>, manager: &mut coin_manager::CoinManager<T>, value: Value): OldValue

Implementation

public fun replace_additional_metadata<T, Value: store, OldValue: store>( : &CoinManagerMetadataCap<T>, manager: &mut CoinManager<T>, value: Value ): OldValue { assert!(df::exists(&manager.id, b"additional_metadata"), EAdditionalMetadataDoesNotExist); let old_value = df::remove<vector<u8>, OldValue>(&mut manager.id, b"additional_metadata"); df::add(&mut manager.id, b"additional_metadata", value); old_value }

Function additional_metadata

public fun additional_metadata<T, Value: store>(manager: &mut coin_manager::CoinManager<T>): &Value

Implementation

public fun additional_metadata<T, Value: store>( manager: &mut CoinManager<T> ): &Value { assert!(df::exists_(&manager.id, b"additional_metadata"), EAdditionalMetadataDoesNotExist); let meta: &Value = df::borrow(&manager.id, b"additional_metadata"); meta }

Function enforce_maximum_supply

A one-time callable function to set a maximum mintable supply on a coin. This can only be set once and is irrevertable.

public fun enforce_maximum_supply<T>(_: &coin_manager::CoinManagerTreasuryCap<T>, manager: &mut coin_manager::CoinManager<T>, maximum_supply: u64)

Implementation

public fun enforce_maximum_supply<T>( _: &CoinManagerTreasuryCap<T>, manager: &mut CoinManager<T>, maximum_supply: u64 ) { assert!(option::is_none(&manager.maximum_supply), EMaximumSupplyAlreadySet); assert!(total_supply(manager) <= maximum_supply, EMaximumSupplyLowerThanTotalSupply); option::fill(&mut manager.maximum_supply, maximum_supply); }

Function renounce_treasury_ownership

A irreversible action renouncing supply ownership which can be called if you hold the CoinManagerTreasuryCap. This action provides Coin holders with some assurances if called, namely that there will not be any new minting or changes to the supply from this point onward. The maximum supply will be set to the current supply and will not be changed any more afterwards.

public fun renounce_treasury_ownership<T>(cap: coin_manager::CoinManagerTreasuryCap<T>, manager: &mut coin_manager::CoinManager<T>)

Implementation

public fun renounce_treasury_ownership<T>( cap: CoinManagerTreasuryCap<T>, manager: &mut CoinManager<T> ) { // Deleting the Cap let CoinManagerTreasuryCap { id } = cap; object::delete(id);

// Updating the maximum supply to the total supply let total_supply = total_supply(manager); if(manager.has_maximum_supply()) { option::swap(&mut manager.maximum_supply, total_supply); } else { option::fill(&mut manager.maximum_supply, total_supply); };

// Setting ownership renounced to true manager.supply_immutable = true;

event::emit(TreasuryOwnershipRenounced { coin_name: type_name::into_string(type_name::get<T>()) }); }

Function renounce_metadata_ownership

A irreversible action renouncing manager ownership which can be called if you hold the CoinManagerMetadataCap. This action provides Coin holders with some assurances if called, namely that there will not be any changes to the metadata from this point onward.

public fun renounce_metadata_ownership<T>(cap: coin_manager::CoinManagerMetadataCap<T>, manager: &mut coin_manager::CoinManager<T>)

Implementation

public fun renounce_metadata_ownership<T>( cap: CoinManagerMetadataCap<T>, manager: &mut CoinManager<T> ) { // Deleting the Cap let CoinManagerMetadataCap { id } = cap; object::delete(id);

// Setting ownership renounced to true manager.metadata_immutable = true;

event::emit(MetadataOwnershipRenounced { coin_name: type_name::into_string(type_name::get<T>()) }); }

Function supply_is_immutable

Convenience function allowing users to query if the ownership of the supply of this Coin and thus the ability to mint new Coin has been renounced.

public fun supply_is_immutable<T>(manager: &coin_manager::CoinManager<T>): bool

Implementation

public fun supply_is_immutable<T>(manager: &CoinManager<T>): bool { manager.supply_immutable }

Function metadata_is_immutable

Convenience function allowing users to query if the ownership of the metadata management and thus the ability to change any of the metadata has been renounced.

public fun metadata_is_immutable<T>(manager: &coin_manager::CoinManager<T>): bool

Implementation

public fun metadata_is_immutable<T>(manager: &CoinManager<T>): bool { manager.metadata_immutable || option::is_some(&manager.immutable_metadata) }

Function metadata

public fun metadata<T>(manager: &coin_manager::CoinManager<T>): &coin::CoinMetadata<T>

Implementation

public fun metadata<T>(manager: &CoinManager<T>): &CoinMetadata<T> { option::borrow(&manager.metadata) }

Function immutable_metadata

public fun immutable_metadata<T>(manager: &coin_manager::CoinManager<T>): &coin_manager::ImmutableCoinMetadata<T>

Implementation

public fun immutable_metadata<T>(manager: &CoinManager<T>): &ImmutableCoinMetadata<T> { option::borrow(&manager.immutable_metadata) }

Function total_supply

Get the total supply as a number

public fun total_supply<T>(manager: &coin_manager::CoinManager<T>): u64

Implementation

public fun total_supply<T>(manager: &CoinManager<T>): u64 { coin::total_supply(&manager.treasury_cap) }

Function maximum_supply

Get the maximum supply possible as a number. If no maximum set it's the maximum u64 possible

public fun maximum_supply<T>(manager: &coin_manager::CoinManager<T>): u64

Implementation

public fun maximum_supply<T>(manager: &CoinManager<T>): u64 { option::get_with_default(&manager.maximum_supply, 18_446_744_073_709_551_615u64) }

Function available_supply

Convenience function returning the remaining supply that can be minted still

public fun available_supply<T>(manager: &coin_manager::CoinManager<T>): u64

Implementation

public fun available_supply<T>(manager: &CoinManager<T>): u64 { maximum_supply(manager) - total_supply(manager) }

Function has_maximum_supply

Returns if a maximum supply has been set for this Coin or not

public fun has_maximum_supply<T>(manager: &coin_manager::CoinManager<T>): bool

Implementation

public fun has_maximum_supply<T>(manager: &CoinManager<T>): bool { option::is_some(&manager.maximum_supply) }

Function supply_immut

Get immutable reference to the treasury's Supply.

public fun supply_immut<T>(manager: &coin_manager::CoinManager<T>): &balance::Supply<T>

Implementation

public fun supply_immut<T>(manager: &CoinManager<T>): &Supply<T> { coin::supply_immut(&manager.treasury_cap) }

Function mint

Create a coin worth value and increase the total supply in cap accordingly.

public fun mint<T>(_: &coin_manager::CoinManagerTreasuryCap<T>, manager: &mut coin_manager::CoinManager<T>, value: u64, ctx: &mut tx_context::TxContext): coin::Coin<T>

Implementation

public fun mint<T>( _: &CoinManagerTreasuryCap<T>, manager: &mut CoinManager<T>, value: u64, ctx: &mut TxContext ): Coin<T> { assert!(total_supply(manager) + value <= maximum_supply(manager), EMaximumSupplyReached); coin::mint(&mut manager.treasury_cap, value, ctx) }

Function mint_balance

Mint some amount of T as a Balance and increase the total supply in cap accordingly. Aborts if value + cap.total_supply >= U64_MAX

public fun mint_balance<T>(_: &coin_manager::CoinManagerTreasuryCap<T>, manager: &mut coin_manager::CoinManager<T>, value: u64): balance::Balance<T>

Implementation

public fun mint_balance<T>( _: &CoinManagerTreasuryCap<T>, manager: &mut CoinManager<T>, value: u64 ): Balance<T> { assert!(total_supply(manager) + value <= maximum_supply(manager), EMaximumSupplyReached); coin::mint_balance(&mut manager.treasury_cap, value) }

Function burn

Destroy the coin c and decrease the total supply in cap accordingly.

public entry fun burn<T>(_: &coin_manager::CoinManagerTreasuryCap<T>, manager: &mut coin_manager::CoinManager<T>, c: coin::Coin<T>): u64

Implementation

public entry fun burn<T>( _: &CoinManagerTreasuryCap<T>, manager: &mut CoinManager<T>, c: Coin<T> ): u64 { coin::burn(&mut manager.treasury_cap, c) }

Function mint_and_transfer

Mint amount of Coin and send it to recipient. Invokes mint().

public fun mint_and_transfer<T>(_: &coin_manager::CoinManagerTreasuryCap<T>, manager: &mut coin_manager::CoinManager<T>, amount: u64, recipient: address, ctx: &mut tx_context::TxContext)

Implementation

public fun mint_and_transfer<T>( _: &CoinManagerTreasuryCap<T>, manager: &mut CoinManager<T>, amount: u64, recipient: address, ctx: &mut TxContext ) { assert!(total_supply(manager) + amount <= maximum_supply(manager), EMaximumSupplyReached); coin::mint_and_transfer(&mut manager.treasury_cap, amount, recipient, ctx) }

Function update_name

Update the name of the coin in the CoinMetadata.

public fun update_name<T>(_: &coin_manager::CoinManagerMetadataCap<T>, manager: &mut coin_manager::CoinManager<T>, name: string::String)

Implementation

public fun update_name<T>( _: &CoinManagerMetadataCap<T>, manager: &mut CoinManager<T>, name: string::String ) { assert!(manager.metadata_is_immutable(), ENoMutableMetadata); coin::update_name(&manager.treasury_cap, option::borrow_mut(&mut manager.metadata), name) }

Function update_symbol

Update the symbol of the coin in the CoinMetadata.

public fun update_symbol<T>(_: &coin_manager::CoinManagerMetadataCap<T>, manager: &mut coin_manager::CoinManager<T>, symbol: ascii::String)

Implementation

public fun update_symbol<T>( _: &CoinManagerMetadataCap<T>, manager: &mut CoinManager<T>, symbol: ascii::String ) { assert!(manager.metadata_is_immutable(), ENoMutableMetadata); coin::update_symbol(&manager.treasury_cap, option::borrow_mut(&mut manager.metadata), symbol) }

Function update_description

Update the description of the coin in the CoinMetadata.

public fun update_description<T>(_: &coin_manager::CoinManagerMetadataCap<T>, manager: &mut coin_manager::CoinManager<T>, description: string::String)

Implementation

public fun update_description<T>( _: &CoinManagerMetadataCap<T>, manager: &mut CoinManager<T>, description: string::String ) { assert!(manager.metadata_is_immutable(), ENoMutableMetadata); coin::update_description(&manager.treasury_cap, option::borrow_mut(&mut manager.metadata), description) }

Function update_icon_url

Update the url of the coin in the CoinMetadata

public fun update_icon_url<T>(_: &coin_manager::CoinManagerMetadataCap<T>, manager: &mut coin_manager::CoinManager<T>, url: ascii::String)

Implementation

public fun update_icon_url<T>( _: &CoinManagerMetadataCap<T>, manager: &mut CoinManager<T>, url: ascii::String ) { assert!(manager.metadata_is_immutable(), ENoMutableMetadata); coin::update_icon_url(&manager.treasury_cap, option::borrow_mut(&mut manager.metadata), url) }

Function decimals

public fun decimals<T>(manager: &coin_manager::CoinManager<T>): u8

Implementation

public fun decimals<T>(manager: &CoinManager<T>): u8 { if(option::is_some(&manager.metadata)) { coin::get_decimals(option::borrow(&manager.metadata)) } else { option::borrow(&manager.immutable_metadata).decimals } }

Function name

public fun name<T>(manager: &coin_manager::CoinManager<T>): string::String

Implementation

public fun name<T>(manager: &CoinManager<T>): string::String { if(option::is_some(&manager.metadata)) { coin::get_name(option::borrow(&manager.metadata)) } else { option::borrow(&manager.immutable_metadata).name } }

Function symbol

public fun symbol<T>(manager: &coin_manager::CoinManager<T>): ascii::String

Implementation

public fun symbol<T>(manager: &CoinManager<T>): ascii::String { if(option::is_some(&manager.metadata)) { coin::get_symbol(option::borrow(&manager.metadata)) } else { option::borrow(&manager.immutable_metadata).symbol } }

Function description

public fun description<T>(manager: &coin_manager::CoinManager<T>): string::String

Implementation

public fun description<T>(manager: &CoinManager<T>): string::String { if(option::is_some(&manager.metadata)) { coin::get_description(option::borrow(&manager.metadata)) } else { option::borrow(&manager.immutable_metadata).description } }

Function icon_url

public fun icon_url<T>(manager: &coin_manager::CoinManager<T>): option::Option<url::Url>

Implementation

public fun icon_url<T>(manager: &CoinManager<T>): Option<Url> { if(option::is_some(&manager.metadata)) { coin::get_icon_url(option::borrow(&manager.metadata)) } else { option::borrow(&manager.immutable_metadata).icon_url } }