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.
- Resource
CoinManager
- Resource
CoinManagerTreasuryCap
- Resource
CoinManagerMetadataCap
- Struct
ImmutableCoinMetadata
- Struct
CoinManaged
- Struct
TreasuryOwnershipRenounced
- Struct
MetadataOwnershipRenounced
- Constants
- Function
new
- Function
new_with_immutable_metadata
- Function
create
- Function
add_additional_metadata
- Function
replace_additional_metadata
- Function
additional_metadata
- Function
enforce_maximum_supply
- Function
renounce_treasury_ownership
- Function
renounce_metadata_ownership
- Function
supply_is_immutable
- Function
metadata_is_immutable
- Function
metadata
- Function
immutable_metadata
- Function
total_supply
- Function
maximum_supply
- Function
available_supply
- Function
has_maximum_supply
- Function
supply_immut
- Function
mint
- Function
mint_balance
- Function
burn
- Function
mint_and_transfer
- Function
update_name
- Function
update_symbol
- Function
update_description
- Function
update_icon_url
- Function
decimals
- Function
name
- Function
symbol
- Function
description
- Function
icon_url
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 availableimmutable_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
id: object::UID
Resource CoinManagerMetadataCap
Metadata has it's own Cap, independent of the TreasuryCap
struct CoinManagerMetadataCap<T> has store, key
Fields
id: object::UID
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 anddecimals
D should be shown as N / 10^D E.g., a coin withvalue
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
}
}