在自定义对象中存储 Balance 和 Coin

如前几节课讨论的那样,Coin 和 Store 对象都具有 store 能力,可以嵌入到其他结构体中(在 Coin 的情况下,因为它是一个对象结构体,所以是“包装”)。

public struct MyObjectWithBalance has key {
    id: UID,
    balance: Balance<MYCOIN>,
}

public struct MyObjectWithCoin has key {
    id: UID,
    coins: Coin<MYCOIN>,
}

正如前一课所讨论的那样,更常见的是存储 Balance 而不是 Coin。但为什么有人会在自定义结构体中存储 Balance 呢? 这种结构最常见的原因是代币由智能合约或模块程序化地拥有。 例如,用户可以建立一个市场,用户可以列出他们自己的代币以与其他代币进行交易。在这种情况下,当买家出现时,我们不希望卖家也必须签署购买交易。 如果买家只需签署并交易自动完成——他们收到他们购买的代币,而支付的代币从他们的钱包(Coin 对象)中取出,这会更顺畅。

public struct Listing<phantom CoinType> has key {
    id: UID,
    seller: address,
    listed_coins: Balance<CoinType>,
    amount_asked: u64,
}

public fun buy_coins<CoinType>(listing: Listing<CoinType>, payment: Coin<SUI>): Balance<CoinType> {
    let Listing<CoinType> { id, seller, listed_coins, amount_asked } = listing;
    object::delete(id);
    assert!(coin::value(&payment) == amount_asked, EINSUFFICIENT_PAYMENT);
    transfer::public_transfer(payment, seller);
    listed_coins
}

在上述示例中,卖家可以创建一个列表,将他们想要出售的代币直接作为共享对象包含在内。列出的代币包含在列表对象中。 一旦买家带着付款出现,列表可以被销毁以返回内部列出的代币作为 Balance<CoinType>。 在 PTB(可编程交易块)中,卖家可以选择将 Balance<CoinType> 合并到他们拥有的任何同类型的 Coin 对象中。

请注意,CoinType 之前有一个 phantom 关键字。这是必需的,因为 Listing 的字段中没有一个直接是 CoinType 类型。 我们看到的是 Balance<CoinType>,但 CoinType 在这里用作泛型而不是直接类型。简而言之,如果类型仅在一个或多个字段中用作泛型,则结构体需要使用 phantom 关键字。

还需注意的是,我们在这里使用泛型 <CoinType>,因此该系统可以适用于任何代币类型!