跳到主要内容

Coin

标准代币协议

Coin 是 Sui 上的标准代币协议

/// A coin of type `T` worth `value`. Transferable and storable
public struct Coin<phantom T> has key, store {
id: UID,
balance: Balance<T>
}

Coin 内部有一个 id 字段表面是一个对象,只有一个 类型为 Balance 的字段 我们把 Balance的源码也放出来

public struct Balance<phantom T> has store {
value: u64
}

Balance 类型只有一个类型为u64value字段 和一个泛型的占位符 T

示例: 创建一个 Coin

module coin_test::solo {
use sui::coin;
use sui::transfer::{public_freeze_object, public_transfer};
use sui::tx_context::sender;

public struct SOLO has drop {}

fun init(witness: SOLO, ctx: &mut TxContext) {
// 创建一个coin
let (treasuryCap, metadata) = coin::create_currency(
witness,
6, // decimals
b"USDC", // symbol
b"USDC", // name
b"Stable coin", // description
option::none(), // icon url
ctx
);

// 共享 metadata 所有权, 不可被修改
public_freeze_object(metadata);

// 铸币权发送给交易发起者
public_transfer(treasuryCap, sender(ctx));
}
}

命令行调用

sui client call --package 0x2 --module coin --function mint_and_transfer --args  <treasuryCap> <amount> <recipient> --type-args <package id>::<module name>::<witness name>

实际调用的是方法 sui::coin::mint_and_transfer

  • --args 指定方法参数
  • --type-args 指定方法接收的泛型

自定义铸币行为

treasuryCap 遵循的是 coin 标准的协议, 但可以自定义铸币行为

module coin_test::supply_coin {
use std::option;
use sui::balance;
use sui::balance::{Supply, supply_value};
use sui::coin;
use sui::coin::{treasury_into_supply, Coin, balance};
use sui::object;
use sui::transfer::{public_freeze_object, public_transfer, share_object};

public struct MintCap<phantom T> has key {
id: UID,
supply: Supply<T>
}

public struct SUPPLY_COIN has drop {}


fun init(witness: SUPPLY_COIN, ctx: &mut TxContext) {
// 创建一个coin
let (treasury, metadata) = coin::create_currency(
witness,
6, // decimals
b"USDC", // symbol
b"USDC", // name
b"Stable coin", // description
option::none(), // icon url
ctx
);

// 共享 metadata 所有权, 不可被修改
public_freeze_object(metadata);

// 销毁铸币权, 返回铸币权中保存的 supply 字段
let supply = treasury_into_supply(treasury);

let mintCap = MintCap {
id: object::new(ctx),
supply
};

share_object(mintCap);
}

public fun mint(mintCap: &mut MintCap<SUPPLY_COIN>, amount: u64, ctx: &mut TxContext): Coin<SUPPLY_COIN> {
let MintCap{id: _, supply} = mintCap;
if (supply_value(supply) + amount > 10000) abort 0;

let supply_balance = balance::increase_supply(&mut mintCap.supply, amount);
coin::from_balance(supply_balance, ctx)
}
}

锁定 Coin

module coin_lock::lock_coin {
use std::option;
use sui::balance::Balance;
use sui::coin;
use sui::coin::{TreasuryCap, balance};
use sui::object;
use sui::object::{UID, id};
use sui::transfer;
use sui::transfer::public_transfer;
use sui::tx_context::{Self, TxContext, sender};


const ErrNotRelease :u64 = 0x00001;

public struct LOCK_COIN has drop {}


public struct LockCoin has key {
id: UID,
balance: Balance<LOCK_COIN>,
release_time: u64
}


fun init(witness: LOCK_COIN, ctx: &mut TxContext) {
let (treasury, metadata) = coin::create_currency(witness, 6, b"USD", b"", b"", option::none(), ctx);
transfer::public_freeze_object(metadata);
transfer::public_transfer(treasury, tx_context::sender(ctx));
}


public entry fun mint_and_lock(
treasury: &mut TreasuryCap<LOCK_COIN>,
amount: u64,
lock_day: u64,
to: address,
ctx: &mut TxContext
) {
let coin = coin::mint(treasury, amount, ctx);
let current_ms = tx_context::epoch_timestamp_ms(ctx);

let lock = LockCoin {
id: object::new(ctx),
balance: coin::into_balance(coin),
release_time: current_ms + (lock_day * 24 * 3600 * 1000)
};

transfer::transfer(lock, to);
}

public entry fun unlock_coin(lock_coin: LockCoin, ctx: &mut TxContext) {

let current_ms = tx_context::epoch_timestamp_ms(ctx);
assert!(current_ms > lock_coin.release_time, ErrNotRelease);

let LockCoin { id,balance,release_time:_ }= lock_coin;

let unlock_coin = coin::from_balance(balance,ctx);

public_transfer(unlock_coin,sender(ctx));

object::delete(id);
}
}