The Coin
Resource and create_currency
Method
Now we know how generics and witness patterns work, let's revisit the Coin
resource and the create_currency
method.
The Coin
Resource
Now we understand how generics work. We can revisit the Coin
resource from sui::coin
. It's defined as the following:
#![allow(unused)] fn main() { public struct Coin<phantom T> has key, store { id: UID, balance: Balance<T> } }
The Coin
resource type is a struct that has a generic type T
and two fields, id
and balance
. id
is of the type sui::object::UID
, which we have already seen before.
balance
is of the type sui::balance::Balance
, and is defined as:
#![allow(unused)] fn main() { public struct Balance<phantom T> has store { value: u64 } }
Recall our discussion on phantom
, The type T
is used in Coin
only as an argument to another phantom type for Balance
, and in Balance
, it's not used in any of its fields, thus T
is a phantom
type parameter.
Coin<T>
serves as a transferrable asset representation of a certain amount of the fungible token type T
that can be transferred between addresses or consumed by smart contract function calls.
The create_currency
Method
Let's look at what coin::create_currency
actually does in its source code:
#![allow(unused)] fn main() { public fun create_currency<T: drop>( witness: T, decimals: u8, symbol: vector<u8>, name: vector<u8>, description: vector<u8>, icon_url: Option<Url>, ctx: &mut TxContext ): (TreasuryCap<T>, CoinMetadata<T>) { // Make sure there's only one instance of the type T assert!(sui::types::is_one_time_witness(&witness), EBadWitness); // Emit Currency metadata as an event. event::emit(CurrencyCreated<T> { decimals }); ( TreasuryCap { id: object::new(ctx), total_supply: balance::create_supply(witness) }, CoinMetadata { id: object::new(ctx), decimals, name: string::utf8(name), symbol: ascii::string(symbol), description: string::utf8(description), icon_url } ) } }
The assert checks that the witness
resource passed in is a One Time Witness using the sui::types::is_one_time_witness
method from the Sui Framework.
The method creates and returns two objects, one is the TreasuryCap
resource and the other is a CoinMetadata
resource.
TreasuryCap
The TreasuryCap
is an asset and is guaranteed to be a singleton object by the One Time Witness pattern:
#![allow(unused)] fn main() { /// Capability allowing the bearer to mint and burn /// coins of type `T`. Transferable public struct TreasuryCap<phantom T> has key, store { id: UID, total_supply: Supply<T> } }
It wraps a singleton field total_supply
of type Balance::Supply
:
#![allow(unused)] fn main() { /// A Supply of T. Used for minting and burning. /// Wrapped into a `TreasuryCap` in the `Coin` module. public struct Supply<phantom T> has store { value: u64 } }
Supply<T>
tracks the total amount of the given custom fungible token of type T
currently circulating. You can see why this field must be a singleton, as having multiple Supply
instances for a single token type makes no sense.
CoinMetadata
This is a resource that stores the metadata of the fungible token that has been created. It includes the following fields:
decimals
: the precision of this custom fungible tokenname
: the name of this custom fungible tokensymbol
: the token symbol of this custom fungible tokendescription
: the description of this custom fungible tokenicon_url
: the URL to the icon file of this custom fungible token
The information contained in CoinMetadata
can be thought of as a basic and lightweight fungible token standard of Sui, and can be used by wallets and explorers to display fungible tokens created using the sui::coin
module.