sui-move进阶:coin.move源码分析coin.move是SuiMove中实现可替代代币(fungibletokens)的核心模块(实际上,因为sui"一切皆对象"和所有权的设计,也自然而然地可以用来实现NFT)。它提供了创建、管理和操作代币的基础工具,包括代币的生成、分割、合
coin.move 是 Sui Move 中实现可替代代币(fungible tokens)的核心模块(实际上,因为sui"一切皆对象"和所有权的设计,也自然而然地可以用来实现NFT)。它提供了创建、管理和操作代币的基础工具,包括代币的生成、分割、合并、供应量管理以及监管功能。
在本教程中,我将部分解析 coin.move 的设计与功能。
coin.move 旨在提供一套通用的代币操作接口,并支持高级功能如:
Coin 是代币的核心结构,用于表示某种类型 T 的代币及其余额。
public struct Coin<phantom T> has key, store {
    id: UID,
    balance: Balance<T>,
}
字段解析:
CoinMetadata 用于存储代币的元数据信息,如名称、符号、小数位数等。
public struct CoinMetadata<phantom T> has key, store {
    id: UID,
    decimals: u8,
    name: string::String,
    symbol: ascii::String,
    description: string::String,
    icon_url: Option<Url>,
}
字段解析:
TreasuryCap 用于管理代币的总供应量。
public struct TreasuryCap<phantom T> has key, store {
    id: UID,
    total_supply: Supply<T>,
}
功能解析:
DenyCapV2 为受监管代币提供高级功能,如地址限制和全局暂停。
public struct DenyCapV2<phantom T> has key, store {
    id: UID,
    allow_global_pause: bool,
}
功能解析:
通过 value 获取 Coin 的余额:
public fun value<T>(self: &Coin<T>): u64 {
    self.balance.value()
}
将一个代币分割为两部分:
public fun split<T>(self: &mut Coin<T>, split_amount: u64, ctx: &mut TxContext): Coin<T> {
    take(&mut self.balance, split_amount, ctx)
}
将两个代币合并:
public entry fun join<T>(self: &mut Coin<T>, c: Coin<T>) {
    let Coin { id, balance } = c;
    id.delete();
    self.balance.join(balance);
}
创建一个余额为 0 的占位代币:
public fun zero<T>(ctx: &mut TxContext): Coin<T> {
    Coin { id: object::new(ctx), balance: balance::zero() }
}
public fun total_supply<T>(cap: &TreasuryCap<T>): u64 {
    balance::supply_value(&cap.total_supply)
}
通过 TreasuryCap 创建新的代币:
public fun mint<T>(cap: &mut TreasuryCap<T>, value: u64, ctx: &mut TxContext): Coin<T> {
    Coin {
        id: object::new(ctx),
        balance: cap.total_supply.increase_supply(value),
    }
}
减少代币的总供应量:
public entry fun burn<T>(cap: &mut TreasuryCap<T>, c: Coin<T>): u64 {
    let Coin { id, balance } = c;
    id.delete();
    cap.total_supply.decrease_supply(balance)
}
添加地址到禁止列表:
public fun deny_list_v2_add<T>(
    deny_list: &mut DenyList,
    _deny_cap: &mut DenyCapV2<T>,
    addr: address,
    ctx: &mut TxContext,
) {
    let ty = type_name::get_with_original_ids<T>().into_string().into_bytes();
    deny_list.v2_add(DENY_LIST_COIN_INDEX, ty, addr, ctx)
}
立即禁止所有地址使用代币:
public fun deny_list_v2_enable_global_pause<T>(
    deny_list: &mut DenyList,
    deny_cap: &mut DenyCapV2<T>,
    ctx: &mut TxContext,
) {
    assert!(deny_cap.allow_global_pause, EGlobalPauseNotAllowed);
    let ty = type_name::get_with_original_ids<T>().into_string().into_bytes();
    deny_list.v2_enable_global_pause(DENY_LIST_COIN_INDEX, ty, ctx)
}
支持动态更新代币的元数据:
public entry fun update_name<T>(
    _treasury: &TreasuryCap<T>,
    metadata: &mut CoinMetadata<T>,
    name: string::String,
) {
    metadata.name = name;
}
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>) {
    (
        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,
        },
    )
}
注意这个witness,这里使用了一次性见证者的设计模式,我将在下一篇教程中进行讲述与探讨。
而我们同样可以创建被管理的代币:
public fun create_regulated_currency_v2<T: drop>(
    witness: T,
    decimals: u8,
    symbol: vector<u8>,
    name: vector<u8>,
    description: vector<u8>,
    icon_url: Option<Url>,
    allow_global_pause: bool,
    ctx: &mut TxContext,
): (TreasuryCap<T>, DenyCapV2<T>, CoinMetadata<T>) {
    let (treasury_cap, metadata) = create_currency(
        witness,
        decimals,
        symbol,
        name,
        description,
        icon_url,
        ctx,
    );
    let deny_cap = DenyCapV2 {
        id: object::new(ctx),
        allow_global_pause,
    };
    transfer::freeze_object(RegulatedCoinMetadata<T> {
        id: object::new(ctx),
        coin_metadata_object: object::id(&metadata),
        deny_cap_object: object::id(&deny_cap),
    });
    (treasury_cap, deny_cap, metadata)
}
源代码对其的解释是:
通过调用
create_currency创建一种新的货币类型,并附加了一项额外功能,允许将特定地址的代币冻结。当一个地址被添加到禁止列表时, 它将立即无法将该货币的代币用作交易的输入对象。
此外,从下一个纪元开始,这些地址将无法接收该货币的代币。
allow_global_pause标志启用了一个额外的 API,可禁止所有地址操作该货币的代币。需要注意的是,这不会影响禁止列表中针对单个地址的条目, 也不会更改 "contains" API 的返回结果。
另外,如果需要使用上述代币管理的相关功能,在创建代币时,我们必须调用create_regulated_currency_v2创建可被管理的代币。
Coin是sui链的基本资产,因此,理解和使用Coin也是sui move学习最重要的一部分。
还有一些额外的功能与特性我在本篇文章没有提到,希望大家主动去阅读源码,甚至编写用例进行调试。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!