代币与余额 - take、put、transfer、zero、destroy_zero
新开发人员在 Sui 中对 Coin 常见的困惑之一是,有一个看起来相似的 Balance 对象:
public struct Coin<phantom T> has key, store {
id: UID,
balance: Balance<T>
}
/// 可存储的余额 - Coin 类型的内部结构体。
/// 可用于存储不需要 key 能力的代币。
public struct Balance<phantom T> has store {
value: u64
}
Coin 和 Balance 的区别究竟是什么,什么时候应该使用其中一个?最佳对比如下:
- Coin 对象更像一个钱包。Coin 钱包有一个内部余额,现金(Balance)可以从中取出并存入另一个 Coin 钱包对象中。
- Balance 就像现金。它不能单独存储,需要放入钱包或口袋。开发人员可以选择创建自己的“口袋”对象来存储 Balance。
从技术上讲,由于 Coin 对象也具有 store 能力,开发人员可以将整个 Coin 钱包放入他们自定义的对象中。 然而,这样做相当奇怪,在这种情况下应该使用 Balance,因为 Coin 已经像一个容器。 此外,将 Coin 钱包对象包装到另一个对象中实际上会将其从全局对象存储中移除,正如我们在对象课程中讨论的那样。这通常是不希望的,因为这会使钱包“消失”。
entry fun transfer_coins(from_wallet: &mut Coin<MYCOIN>, amount: u64, to_wallet: &mut Coin<MYCOIN>, ctx: &mut TxContext) {
let cash = coin::take(coin::balance_mut(from_wallet), amount, ctx);
coin::put(coin::balance_mut(to_wallet), cash);
}
在上述示例中,我们从 from_wallet Coin
对象中取出一些代币并存入 to_wallet Coin
对象中。注意,只有 from_wallet
和 to_wallet
的所有者可以调用 transfer_coins
。我们需要使用 coin::balance_mut
来获取 Coin 对象的内部余额,因为结构体字段在定义模块(在这种情况下为 coin)之外是不可见的。
Sui 中的 Coin 模块不提供直接从一个 Coin 对象转移到另一个 Coin 对象的功能。开发人员需要手动使用 take
和 put
来完成转移。
Coin 模块中的一些其他函数是:
balance(&Coin)
: 返回 Coin 对象的余额。zero()
: 创建一个余额为零的 Coin 对象(空钱包)。destroy_zero()
: 销毁一个空钱包。一个有非零余额的钱包不能被销毁,必须先将其中的代币转移到其他地方。