Skip to main content

Module sui::coin_registry

Defines the system object for managing coin data in a central registry. This module provides a centralized way to store and manage metadata for all currencies in the Sui ecosystem, including their supply information, regulatory status, and metadata capabilities.

use std::address;
use std::ascii;
use std::bcs;
use std::internal;
use std::option;
use std::string;
use std::type_name;
use std::u128;
use std::vector;
use sui::accumulator;
use sui::accumulator_settlement;
use sui::address;
use sui::bag;
use sui::balance;
use sui::bcs;
use sui::coin;
use sui::config;
use sui::deny_list;
use sui::derived_object;
use sui::dynamic_field;
use sui::dynamic_object_field;
use sui::event;
use sui::funds_accumulator;
use sui::hash;
use sui::hex;
use sui::object;
use sui::party;
use sui::protocol_config;
use sui::table;
use sui::transfer;
use sui::tx_context;
use sui::types;
use sui::url;
use sui::vec_map;
use sui::vec_set;

Struct CoinRegistry

System object found at address 0xc that stores coin data for all registered coin types. This is a shared object that acts as a central registry for coin metadata, supply information, and regulatory status.

public struct CoinRegistry has key
Click to open
Fields

Struct ExtraField

Store only object that enables more flexible coin data registration, allowing for additional fields to be added without changing the Currency structure.

public struct ExtraField has store
Click to open
Fields
0: std::type_name::TypeName
1: vector<u8>

Struct CurrencyKey

Key used to derive addresses when creating Currency<T> objects.

public struct CurrencyKey<phantom T> has copy, drop, store

Struct LegacyMetadataKey

Key used to store the legacy CoinMetadata for a Currency.

public struct LegacyMetadataKey has copy, drop, store

Struct MetadataCap

Capability object that gates metadata (name, description, icon_url, symbol) changes in the Currency. It can only be created (or claimed) once, and can be deleted to prevent changes to the Currency metadata.

public struct MetadataCap<phantom T> has key, store
Click to open
Fields

Struct Borrow

Potato callback for the legacy CoinMetadata borrowing.

public struct Borrow<phantom T>

Struct Currency

Currency stores metadata such as name, symbol, decimals, icon_url and description, as well as supply states (optional) and regulatory status.

public struct Currency<phantom T> has key
Click to open
Fields
id: sui::object::UID
decimals: u8
Number of decimal places the coin uses for display purposes.
name: std::string::String
Human-readable name for the coin.
symbol: std::string::String
Short symbol/ticker for the coin.
description: std::string::String
Detailed description of the coin.
icon_url: std::string::String
URL for the coin's icon/logo.
supply: std::option::Option<sui::coin_registry::SupplyState<T>>
Current supply state of the coin (fixed supply or unknown).
Note: We're using Option because SupplyState does not have drop, meaning we cannot swap out its value at a later state.
regulated: sui::coin_registry::RegulatedState
Regulatory status of the coin (regulated with deny cap or unknown)
treasury_cap_id: std::option::Option<sui::object::ID>
ID of the treasury cap for this coin type, if registered.
metadata_cap_id: sui::coin_registry::MetadataCapState
ID of the metadata capability for this coin type, if claimed.
extra_fields: sui::vec_map::VecMap<std::string::String, sui::coin_registry::ExtraField>
Additional fields for extensibility.

Struct CurrencyInitializer

Hot potato wrapper to enforce registration after "new_currency" data creation.
Destroyed in the finalize call and either transferred to the CoinRegistry (in case of an OTW registration) or shared directly (for dynamically created currencies).

public struct CurrencyInitializer<phantom T>
Click to open
Fields
currency: sui::coin_registry::Currency<T>
extra_fields: sui::bag::Bag
is_otw: bool

Enum SupplyState

Supply state marks the type of Currency Supply, which can be

  • Fixed: no minting or burning;
  • BurnOnly: no minting, burning is allowed;
  • Unknown: flexible (supply is controlled by its TreasuryCap);
public enum SupplyState<phantom T> has store
Click to open
Variants
Variant Fixed
Coin has a fixed supply with the given Supply object.
0: sui::balance::Supply<T>
Variant BurnOnly
Coin has a supply that can ONLY decrease.
0: sui::balance::Supply<T>
Variant Unknown
Supply information is not yet known or registered.

Enum RegulatedState

Regulated state of a coin type.

  • Regulated: DenyCap exists or a RegulatedCoinMetadata used to mark currency as regulated;
  • Unregulated: the currency was created without deny list;
  • Unknown: the regulatory status is unknown.
public enum RegulatedState has copy, drop, store
Click to open
Variants
Variant Regulated
Coin is regulated with a deny cap for address restrictions. allow_global_pause is None if the information is unknown (has not been migrated from DenyCapV2).
cap: sui::object::ID
allow_global_pause: std::option::Option<bool>
variant: u8
Variant Unregulated
The coin has been created without deny list.
Variant Unknown
Regulatory status is unknown.
Result of a legacy migration for that coin (from coin.move constructors)

Enum MetadataCapState

State of the MetadataCap for a single Currency.

public enum MetadataCapState has copy, drop, store
Click to open
Variants
Variant Claimed
The metadata cap has been claimed.
0: sui::object::ID
Variant Unclaimed
The metadata cap has not been claimed.
Variant Deleted
The metadata cap has been claimed and then deleted.

Constants

Metadata cap already claimed

#[error]
const EMetadataCapAlreadyClaimed: vector<u8> = b"Metadata cap already claimed";

Only the system address can create the registry

#[error]
const ENotSystemAddress: vector<u8> = b"Only the system can create the registry.";

Currency for this coin type already exists

#[error]
const ECurrencyAlreadyExists: vector<u8> = b"Currency for this coin type already exists.";

Attempt to set the deny list state permissionlessly while it has already been set.

#[error]
const EDenyListStateAlreadySet: vector<u8> = b"Cannot set the deny list state as it has already been set.";

Attempt to update Currency with legacy metadata after the MetadataCap has been claimed. Updates are only allowed if the MetadataCap has not yet been claimed or deleted.

#[error]
const ECannotUpdateManagedMetadata: vector<u8> = b"Cannot update metadata whose MetadataCap has already been claimed";

Attempt to set the symbol to a non-ASCII printable character

#[error]
const EInvalidSymbol: vector<u8> = b"Symbol has to be ASCII printable";
#[error]
const EDenyCapAlreadyCreated: vector<u8> = b"Cannot claim the deny cap twice";

Attempt to migrate legacy metadata for a Currency that already exists.

#[error]
const ECurrencyAlreadyRegistered: vector<u8> = b"Currency already registered";
#[error]
const EEmptySupply: vector<u8> = b"Supply cannot be empty";
#[error]
const ESupplyNotBurnOnly: vector<u8> = b"Cannot burn on a non burn-only supply";
#[error]
const EInvariantViolation: vector<u8> = b"Code invariant violation";
#[error]
const EDeletionNotSupported: vector<u8> = b"Deleting legacy metadata is not supported";
#[error]
const ENotOneTimeWitness: vector<u8> = b"Type is expected to be OTW";
#[error]
const EBorrowLegacyMetadata: vector<u8> = b"Cannot borrow legacy metadata for migrated currency";
#[error]
const EDuplicateBorrow: vector<u8> = b"Attempt to return duplicate borrowed CoinMetadata";

Incremental identifier for regulated coin versions in the deny list.
We start from 0 in the new system, which aligns with the state of DenyCapV2.

const REGULATED_COIN_VERSION: u8 = 0;

Marker used in metadata to indicate that the currency is not migrated.

const NEW_CURRENCY_MARKER: vector<u8> = vector[105, 115, 95, 110, 101, 119, 95, 99, 117, 114, 114, 101, 110, 99, 121];

Function new_currency

Creates a new currency.

Note: This constructor has no long term difference from new_currency_with_otw.
This can be called from the module that defines T any time after it has been published.

public fun new_currency<T: key>(registry: &mut sui::coin_registry::CoinRegistry, decimals: u8, symbol: std::string::String, name: std::string::String, description: std::string::String, icon_url: std::string::String, ctx: &mut sui::tx_context::TxContext): (sui::coin_registry::CurrencyInitializer<T>, sui::coin::TreasuryCap<T>)

Function new_currency_with_otw

Creates a new currency with using an OTW as proof of uniqueness.

This is a two-step operation:

  1. Currency is constructed in the init function and sent to the CoinRegistry;
  2. Currency is promoted to a shared object in the finalize_registration call;
public fun new_currency_with_otw<T: drop>(otw: T, decimals: u8, symbol: std::string::String, name: std::string::String, description: std::string::String, icon_url: std::string::String, ctx: &mut sui::tx_context::TxContext): (sui::coin_registry::CurrencyInitializer<T>, sui::coin::TreasuryCap<T>)

Function claim_metadata_cap

Claim a MetadataCap for a coin type.
Only allowed from the owner of TreasuryCap, and only once.

Aborts if the MetadataCap has already been claimed.
Deleted MetadataCap cannot be reclaimed.

public fun claim_metadata_cap<T>(currency: &mut sui::coin_registry::Currency<T>, _: &sui::coin::TreasuryCap<T>, ctx: &mut sui::tx_context::TxContext): sui::coin_registry::MetadataCap<T>

Function make_regulated

Allows converting a currency, on init, to regulated, which creates a DenyCapV2 object, and a denylist entry. Sets regulated state to Regulated.

This action is irreversible.

public fun make_regulated<T>(init: &mut sui::coin_registry::CurrencyInitializer<T>, allow_global_pause: bool, ctx: &mut sui::tx_context::TxContext): sui::coin::DenyCapV2<T>

Function make_supply_fixed_init

Initializer function to make the supply fixed.
Aborts if Supply is 0 to enforce minting during initialization.

public fun make_supply_fixed_init<T>(init: &mut sui::coin_registry::CurrencyInitializer<T>, cap: sui::coin::TreasuryCap<T>)

Function make_supply_burn_only_init

Initializer function to make the supply burn-only.
Aborts if Supply is 0 to enforce minting during initialization.

public fun make_supply_burn_only_init<T>(init: &mut sui::coin_registry::CurrencyInitializer<T>, cap: sui::coin::TreasuryCap<T>)

Function make_supply_fixed

Freeze the supply by destroying the TreasuryCap and storing it in the Currency.

public fun make_supply_fixed<T>(currency: &mut sui::coin_registry::Currency<T>, cap: sui::coin::TreasuryCap<T>)

Function make_supply_burn_only

Make the supply BurnOnly by giving up the TreasuryCap, and allowing burning of Coins through the Currency.

public fun make_supply_burn_only<T>(currency: &mut sui::coin_registry::Currency<T>, cap: sui::coin::TreasuryCap<T>)

Function finalize

Finalize the coin initialization, returning MetadataCap

public fun finalize<T>(builder: sui::coin_registry::CurrencyInitializer<T>, ctx: &mut sui::tx_context::TxContext): sui::coin_registry::MetadataCap<T>

Function finalize_and_delete_metadata_cap

Does the same as finalize, but also deletes the MetadataCap after finalization.

public fun finalize_and_delete_metadata_cap<T>(builder: sui::coin_registry::CurrencyInitializer<T>, ctx: &mut sui::tx_context::TxContext)

Function finalize_registration

The second step in the "otw" initialization of coin metadata, that takes in the Currency<T> that was transferred from init, and transforms it in to a "derived address" shared object.

Can be performed by anyone.

public fun finalize_registration<T>(registry: &mut sui::coin_registry::CoinRegistry, currency: sui::transfer::Receiving<sui::coin_registry::Currency<T>>, _ctx: &mut sui::tx_context::TxContext)

Function delete_metadata_cap

Delete the metadata cap making further updates of Currency metadata impossible.
This action is IRREVERSIBLE, and the MetadataCap can no longer be claimed.

public fun delete_metadata_cap<T>(currency: &mut sui::coin_registry::Currency<T>, cap: sui::coin_registry::MetadataCap<T>)

Function burn

Burn the Coin if the Currency has a BurnOnly supply state.

public fun burn<T>(currency: &mut sui::coin_registry::Currency<T>, coin: sui::coin::Coin<T>)

Function burn_balance

Burn the Balance if the Currency has a BurnOnly supply state.

public fun burn_balance<T>(currency: &mut sui::coin_registry::Currency<T>, balance: sui::balance::Balance<T>)

Function set_name

Update the name of the Currency.

public fun set_name<T>(currency: &mut sui::coin_registry::Currency<T>, _: &sui::coin_registry::MetadataCap<T>, name: std::string::String)

Function set_description

Update the description of the Currency.

public fun set_description<T>(currency: &mut sui::coin_registry::Currency<T>, _: &sui::coin_registry::MetadataCap<T>, description: std::string::String)

Function set_icon_url

Update the icon URL of the Currency.

public fun set_icon_url<T>(currency: &mut sui::coin_registry::Currency<T>, _: &sui::coin_registry::MetadataCap<T>, icon_url: std::string::String)

Function set_treasury_cap_id

Register the treasury cap ID for a migrated Currency. All currencies created with new_currency or new_currency_with_otw have their treasury cap ID set during initialization.

public fun set_treasury_cap_id<T>(currency: &mut sui::coin_registry::Currency<T>, cap: &sui::coin::TreasuryCap<T>)

Function migrate_legacy_metadata

Register CoinMetadata in the CoinRegistry. This can happen only once, if the Currency did not exist yet. Further updates are possible through update_from_legacy_metadata.

public fun migrate_legacy_metadata<T>(registry: &mut sui::coin_registry::CoinRegistry, legacy: &sui::coin::CoinMetadata<T>, _ctx: &mut sui::tx_context::TxContext)

Function update_from_legacy_metadata

Update Currency from CoinMetadata if the MetadataCap is not claimed. After the MetadataCap is claimed, updates can only be made through set_* functions.

public fun update_from_legacy_metadata<T>(currency: &mut sui::coin_registry::Currency<T>, legacy: &sui::coin::CoinMetadata<T>)

Function delete_migrated_legacy_metadata

public fun delete_migrated_legacy_metadata<T>(_: &mut sui::coin_registry::Currency<T>, _: sui::coin::CoinMetadata<T>)

Function migrate_regulated_state_by_metadata

Allow migrating the regulated state by access to RegulatedCoinMetadata frozen object.
This is a permissionless operation which can be performed only once.

public fun migrate_regulated_state_by_metadata<T>(currency: &mut sui::coin_registry::Currency<T>, metadata: &sui::coin::RegulatedCoinMetadata<T>)

Function migrate_regulated_state_by_cap

Mark regulated state by showing the DenyCapV2 object for the Currency.

public fun migrate_regulated_state_by_cap<T>(currency: &mut sui::coin_registry::Currency<T>, cap: &sui::coin::DenyCapV2<T>)

Function borrow_legacy_metadata

Borrow the legacy CoinMetadata from a new Currency. To preserve the ID of the legacy CoinMetadata, we create it on request and then store it as a dynamic field for future borrows.

Borrow<T> ensures that the CoinMetadata is returned in the same transaction.

public fun borrow_legacy_metadata<T>(currency: &mut sui::coin_registry::Currency<T>, ctx: &mut sui::tx_context::TxContext): (sui::coin::CoinMetadata<T>, sui::coin_registry::Borrow<T>)

Function return_borrowed_legacy_metadata

Return the borrowed CoinMetadata and the Borrow potato to the Currency.

Note to self: Borrow requirement prevents deletion through this method.

public fun return_borrowed_legacy_metadata<T>(currency: &mut sui::coin_registry::Currency<T>, legacy: sui::coin::CoinMetadata<T>, borrow: sui::coin_registry::Borrow<T>, _ctx: &mut sui::tx_context::TxContext)

Function decimals

Get the number of decimal places for the coin type.

public fun decimals<T>(currency: &sui::coin_registry::Currency<T>): u8

Function name

Get the human-readable name of the coin.

public fun name<T>(currency: &sui::coin_registry::Currency<T>): std::string::String

Function symbol

Get the symbol/ticker of the coin.

public fun symbol<T>(currency: &sui::coin_registry::Currency<T>): std::string::String

Function description

Get the description of the coin.

public fun description<T>(currency: &sui::coin_registry::Currency<T>): std::string::String

Function icon_url

Get the icon URL for the coin.

public fun icon_url<T>(currency: &sui::coin_registry::Currency<T>): std::string::String

Function is_metadata_cap_claimed

Check if the metadata capability has been claimed for this Currency type.

public fun is_metadata_cap_claimed<T>(currency: &sui::coin_registry::Currency<T>): bool

Function is_metadata_cap_deleted

Check if the metadata capability has been deleted for this Currency type.

public fun is_metadata_cap_deleted<T>(currency: &sui::coin_registry::Currency<T>): bool

Function metadata_cap_id

Get the metadata cap ID, or none if it has not been claimed.

public fun metadata_cap_id<T>(currency: &sui::coin_registry::Currency<T>): std::option::Option<sui::object::ID>

Function treasury_cap_id

Get the treasury cap ID for this coin type, if registered.

public fun treasury_cap_id<T>(currency: &sui::coin_registry::Currency<T>): std::option::Option<sui::object::ID>

Function deny_cap_id

Get the deny cap ID for this coin type, if it's a regulated coin.
Returns None if:

  • The Currency is not regulated;
  • The Currency is migrated from legacy, and its regulated state has not been set;
public fun deny_cap_id<T>(currency: &sui::coin_registry::Currency<T>): std::option::Option<sui::object::ID>

Function is_supply_fixed

Check if the supply is fixed.

public fun is_supply_fixed<T>(currency: &sui::coin_registry::Currency<T>): bool

Function is_supply_burn_only

Check if the supply is burn-only.

public fun is_supply_burn_only<T>(currency: &sui::coin_registry::Currency<T>): bool

Function is_regulated

Check if the currency is regulated.

public fun is_regulated<T>(currency: &sui::coin_registry::Currency<T>): bool

Function total_supply

Get the total supply for the Currency<T> if the Supply is in fixed or burn-only state. Returns None if the SupplyState is Unknown.

public fun total_supply<T>(currency: &sui::coin_registry::Currency<T>): std::option::Option<u64>

Function exists

Check if coin data exists for the given type T in the registry.

public fun exists<T>(registry: &sui::coin_registry::CoinRegistry): bool

Function is_migrated_from_legacy

Whether the currency is migrated from legacy.

fun is_migrated_from_legacy<T>(currency: &sui::coin_registry::Currency<T>): bool

Function to_legacy_metadata

Create a new legacy CoinMetadata from a Currency.

fun to_legacy_metadata<T>(currency: &sui::coin_registry::Currency<T>, ctx: &mut sui::tx_context::TxContext): sui::coin::CoinMetadata<T>

Function create

Create and share the singleton CoinRegistry -- this function is called exactly once, during the upgrade epoch.
Only the system address (0x0) can create the registry.

fun create(ctx: &sui::tx_context::TxContext)

Macro function finalize_impl

Internal macro to keep implementation between build and test modes.

macro fun finalize_impl<$T>($builder: sui::coin_registry::CurrencyInitializer<$T>, $ctx: &mut sui::tx_context::TxContext): (sui::coin_registry::Currency<$T>, sui::coin_registry::MetadataCap<$T>)

Macro function migrate_legacy_metadata_impl

Internal macro to keep implementation between build and test modes.

macro fun migrate_legacy_metadata_impl<$T>($registry: &mut sui::coin_registry::CoinRegistry, $legacy: &sui::coin::CoinMetadata<$T>): sui::coin_registry::Currency<$T>

Macro function is_ascii_printable

Nit: consider adding this function to std::string in the future.

macro fun is_ascii_printable($s: &std::string::String): bool