Alva

Alva

programmer
github
telegram
email

Let's Move - 学 Move 得 Sui(二):完成 Coin 合约の上链デプロイ

letsmove

Let's Move は、より多くの人々が Move 言語を学ぶことを奨励する SUI のインセンティブプログラムです。

学習ログ (alva-lin)

タスク 2 - 2 つの Coin コントラクトのメインネットへのデプロイを完了する#

任务

  • Coin に関連する知識の学習を完了する

  • My Coin の学習を完了し、メインネットにデプロイする

  • Faucet Coin の学習を完了し、メインネットにデプロイする

  • My CoinFaucet Coin コントラクトの公開 package id を提出する

  • My Coin をアドレス 0x7b8e0864967427679b4e129f79dc332a885c6087ec9e187b53451a9006ee15f2 に送信する

主に Managed Coin ケース - Sui Move 入門 を参照

sui::coin ライブラリ#

Coin#

Coin コントラクトの作成には、主に sui::coin ライブラリで提供される構造体とメソッドが使用されます。

struct Coin<phantom T> has key, store {
    id: UID,
    balance: Balance<T>
}

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

Coin は key と store の能力を持ち、資産と見なされ、異なるアドレス間で移動可能であり、後でブロックエクスプローラーで自分が所有するすべての Coin を確認できます。

create_currency#

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>) {
    // Make sure there's only one instance of the type T
    assert!(sui::types::is_one_time_witness(&witness), EBadWitness);

    // Emit Currency metadata as an event.
    event::emit(CurrencyCreated<T> {
        decimals
    });

    (
        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
        }
    )
}

create_currency メソッドのパラメータ

パラメータ説明
decimals精度、分割された最小単位。 10^(-1*n)
symbolシンボル
name名称
description説明
icon_url画像

メソッドの戻り値は、TreasuryCapCoinMetadata の 2 つの値を含むタプルです。

ここで TreasuryCap は資産の一種で、一回限りの証人パターン によって単一のオブジェクトであることが保証され、その型宣言は以下の通りです。

/// Capability allowing the bearer to mint and burn
/// coins of type `T`. Transferable
struct TreasuryCap<phantom T> has key, store {
        id: UID,
        total_supply: Supply<T>
}
/// A Supply of T. Used for minting and burning.
/// Wrapped into a `TreasuryCap` in the `Coin` module.
struct Supply<phantom T> has store {
    value: u64
}

この total_supply 値は、現在の通貨 T の発行総量を追跡するため、TreasuryCap は 1 つだけで十分です。そして CoinMetadata は、現在の通貨のメタデータを保持します。

coin コントラクトコード#

sui フレームワークライブラリの充実のおかげで、mint (鋳造) と burn (消去) 機能を持つトークンコントラクトを作成するために必要なコードは非常に少ないです。

// file: my_coin.move
module new_coin::my_coin {
    use std::option;
    use sui::coin::{Self, Coin, TreasuryCap};
    use sui::transfer;
    use sui::tx_context::{Self, TxContext};

    struct MY_COIN has drop {}

    fun init(witness: MY_COIN, ctx: &mut TxContext) {
        let (treasury_cap, metadata) = coin::create_currency<MY_COIN>(
            witness,
            2,
            b"MY_COIN",
            b"MC",
            b"learning for letsmove, power by alva-lin",
            option::none(),
            ctx
        );

        transfer::public_freeze_object(metadata);
        transfer::public_transfer(treasury_cap, tx_context::sender(ctx));
    }

    public fun mint(
        treasury_cap: &mut TreasuryCap<MY_COIN>,
        amount: u64,
        recipient: address,
        ctx: &mut TxContext
    ) {
        coin::mint_and_transfer(treasury_cap, amount, recipient, ctx);
    }

    public fun burn(treasury_cap: &mut TreasuryCap<MY_COIN>, coin: Coin<MY_COIN>) {
        coin::burn(treasury_cap, coin);
    }

    #[test_only]
    public fun test_init(ctx: &mut TxContext) {
        init(MY_COIN {}, ctx);
    }
}

my_coin モジュールは、Witness モード に基づいて MY_COIN という名前の構造体を定義します。その後、init メソッドのパラメータに MY_COIN 型の witness リソースを追加し、モジュールがプッシュされた後に自動的に作成されます。

init メソッド内で、coin::create_currency メソッドを呼び出し、TreasuryCapCoinMetadata リソースを取得し、即座に CoinMetadata を凍結します。

TreasuryCapmint メソッドと burn メソッドを呼び出すための証明書として、発行者のアドレスに送信されます。

テスト#

テストコードは以下の通りで、複数の取引時間をシミュレートし、mint 操作と burn 操作を行います。

#[test_only]
module new_coin::my_coin_tests {
    use new_coin::my_coin::{Self, MY_COIN};
    use sui::coin::{Coin, TreasuryCap};
    use sui::test_scenario::{Self, next_tx, ctx};

    #[test]
    fun mint_burn() {
        // Initialize a mock sender address
        let addr1 = @0xA;

        // Begins a multi transaction scenario with addr1 as the sender
        let scenario = test_scenario::begin(addr1);

        // Run the coin module init function
        {
            my_coin::test_init(ctx(&mut scenario))
        };

        // Mint a `Coin<MY_COIN>` object
        next_tx(&mut scenario, addr1);
        {
            let treasurycap = test_scenario::take_from_sender<TreasuryCap<MY_COIN>>(&scenario);
            my_coin::mint(&mut treasurycap, 100, addr1, test_scenario::ctx(&mut scenario));
            test_scenario::return_to_address<TreasuryCap<MY_COIN>>(addr1, treasurycap);
        };

        // Burn a `Coin<MY_COIN>` object
        next_tx(&mut scenario, addr1);
        {
            let coin = test_scenario::take_from_sender<Coin<MY_COIN>>(&scenario);
            let treasurycap = test_scenario::take_from_sender<TreasuryCap<MY_COIN>>(&scenario);
            my_coin::burn(&mut treasurycap, coin);
            test_scenario::return_to_address<TreasuryCap<MY_COIN>>(addr1, treasurycap);
        };

        // Cleans up the scenario object
        test_scenario::end(scenario);
    }
}

公開#

まず、ネットワークを必要な環境に切り替えます。

sui client switch --env mainnet

プロジェクトフォルダ内で、以下のコマンドを実行して、パッケージを公開するか、モジュールを個別に公開します。

# publish package
sui client publish --gas-budget 30000

# または必要に応じてモジュールを公開
# publish module
# sui client publish sources/my_coin.move --gas-budget 30000

公開後の出力結果には、以下が含まれます。

  • Package: Object Changes > Published Objects ブロックに位置します。

  • CoinMetadata: Object Changes > Created Objects ブロックに位置します。

    その ObjectType は 0x2::coin::CoinMetadata<<Package ID>::<Module>::<Witness Type>> です。

  • TreasuryCap: Object Changes > Created Objects に位置します。

    その ObjectType は 0x2::coin::TreasuryCap<<Package ID>::<Module>::<Witness Type>> です。

Package IDTreasuryCap ID を記録します。

export PACKAGE_ID=0xf9623587d620d26024868578a3539642993e2da44598c3fcaa1f384f5327f6a5
export TREASURYCAP_ID=0x97233be4acd1688c93f2c60ce81350b993a810c6b4851e8cdf214402759fad88

鋳造と消去#

sui cli を使用して、モジュールの対応するモジュール関数を呼び出すことができます。

注意が必要なのは、希望するトークンの数量 = 渡す値 * 10^(-1*n) であり、ここで n は前述の公開されたコントラクトコードの decimals の値です。

この記事では、decimals の値は 2 です。100 枚のトークンを鋳造したい場合は、値を 10000 にする必要があります。

# 送信先のウォレットアドレス
export RECIPIENT_ADDRESS=<YOUR_WALLET_ADDRESS>
# mint
sui client call --gas-budget 3000 --package $PACKAGE_ID --module my_coin --function mint --args $TREASURYCAP_ID \"10000\" $RECIPIENT_ADDRESS

出力内容には、取引の詳細が表示されます。

または、取引ハッシュを取得して、SuiScan や他の sui ブロックエクスプローラーで取引の詳細を確認できます。

# 取引ハッシュの形式は以下のようになります。通常、出力内容の最初に表示されます。
Transaction Digest: <hash>

鋳造時の出力内容の中で、Object Changes > Created Objects ブロック内の ObjectType が 0x2::coin::Coin<<package>, <module>, <type>> のオブジェクトを見つけて、ObjectID を取得します。

この ObjectID が CoinID であり、変数として保存します。

コマンドライン出力の coin id が見つからない場合は、ブロックエクスプローラーから見つけることもできます。

how to find coin id

export COIN_ID=0x3460204ae7f9385df79dc963a17d8b11eb0fa7a699f7196fac80405e1777d36c

burn メソッドを呼び出して、通貨を消去します。

# 注意: gas 予算を増やす必要があります
# burn
sui client call --gas-budget 7500000 --package $PACKAGE_ID --module joker --function burn --args $TREASURYCAP_ID $COIN_ID

コマンドが成功すると、ウォレットから以前に鋳造した金額が削除されたことが確認できます。

トークンが消去された後、COIN ID を使用して直接ブロックエクスプローラーで検索することはできず、履歴取引から間接的にその記録を見つけることしかできません。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。