Now we know how generics and witness patterns work, let's revisit the Coin
resource and the create_currency
method.
Now we understand how generics work. We can revisit the Coin
resource from sui::coin
. It's defined as the following:
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:
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.
Let's look at what coin::create_currency
actually does in its source code:
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.
The TreasuryCap
is an asset and is guaranteed to be a singleton object by the One Time Witness pattern:
/// 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
:
/// 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.
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.