huahua

huahua

手取り足取り教える代币スワップの実現!Move言語とSuiチェーンの開発実践

シリーズ記事目次#

Task1:hello move🚪
Task2:move coin🚪
Task3:move nft🚪
Task4:move game🚪
Task5:move swap🚪
Task6:sdk ptb🚪

もっと素晴らしいコンテンツをお楽しみに!✌️


@TOC


前書き#

前回の記事《Task4:move game》では、Move プログラミング言語がブロックチェーン上のインタラクティブゲームにどのように応用されるかを探求し、実用的な価値を持つじゃんけんゲームのスマートコントラクトを実装しました。このタスクを通じて、資金プールの管理、ブロックチェーン上の公平性の確保、スマートコントラクトに基づくゲームのインタラクションの重要な技術を学び、Move の理解と実践をさらに深めました。

本記事では、Task5: move swapに焦点を当て、Move に基づくトークン交換のスマートコントラクトの実装に挑戦します。このタスクを通じて、ユーザーがブロックチェーン上で 2 種類のトークンを安全かつ迅速に交換できる基本モデルを構築します。本タスクは、Move が分散型金融(DeFi)分野での潜在能力をさらに示し、以下の重要な技術ポイントを習得する手助けをします:

  • ブロックチェーン上のトークンプールを設計・管理する方法;
  • スマートコントラクトを通じてトークン交換のビジネスロジックを実装する方法;
  • トークン交換の安全性と効率を確保する方法。

実装の過程では、task2で定義した 2 種類のトークンHUAHUAHUA1223_COINHUAHUAHUA1223_FAUCET_COINを使用し、交換比率を設定してトークンの相互交換を実現します。また、スマートコントラクトにおける資金検証と残高管理公平性と堅牢性の設計などの核心的な問題についても深く探求します。

Move の応用シーンを引き続き解き明かし、分散型金融の基盤コンポーネントを一緒に構築していきましょう!

HOH コミュニティ


Sui チェーンとは?#

Suiは、高性能なブロックチェーンプラットフォームで、分散型アプリケーションに迅速、安全かつスケーラブルなインフラを提供することを目的としています。これはAptos Labsチームによって開発され、新しいコンセンサスプロトコルであるNarwhal & Tuskに基づいています。Sui の設計目標は、ブロックチェーンの性能ボトルネックを解決し、非常に高い取引スループットと低遅延を提供し、複雑なアプリケーションシナリオのニーズに適応することです。

Sui チェーンの主な特徴:

  1. 高スループットと低遅延:Sui のコンセンサスメカニズムは、大量の取引を並行して処理でき、ネットワーク全体のグローバルコンセンサスを待つ必要がありません。この並行化設計により、毎秒何千もの取引を処理でき、ブロックチェーンのスループットが大幅に向上し、取引確認の遅延が減少します。

  2. オブジェクト指向のリソース管理:Sui は、ブロックチェーン内のリソースをオブジェクトとして管理します。これらのリソース(トークンや NFT など)は独立した識別子を持ち、直接追跡および操作できます。この方法により、Sui は複数のノード間で効率的にリソースを並行処理でき、グローバルステートを処理する必要がなくなり、性能がさらに向上します。

  3. 柔軟な取引モデル:Sui は、複数のリソースオブジェクト間で並行して取引を実行できる柔軟で効率的な取引モデルを提供します。これにより、異なるユーザーの取引が独立して効率的に行われ、従来のブロックチェーンの性能ボトルネックを回避できます。

  4. 効率的なアカウントと権限管理:Sui は、多様なアカウント管理メカニズムを提供し、分散型アプリケーションにおける複雑な権限要求に対応できます。個人アカウント、スマートコントラクトアカウント、マルチシグアカウントなど、柔軟に構成および管理できます。


Move プログラミング言語とは?#

Moveは、ブロックチェーン開発のために設計されたプログラミング言語で、最初はMetaLibra(後のDiem)チームによって開発され、その後Suiブロックチェーンに採用されました。Move の設計の重点は、リソースの管理、所有権の制御、および型安全性にあり、特に分散型アプリケーションにおける資産やデジタルリソースの処理に適しています。

Move 言語の主な特徴:

  1. リソース型システム:Move 言語は、すべてのリソース(トークン、NFT、スマートコントラクト内のデータなど)を「リソース型」として扱います。これらのリソースはシステム内でコピーまたは破棄できず、移転または借用のみが可能です。これにより、各リソースの唯一性と安全性が確保され、従来のスマートコントラクトにおけるリソースの喪失や重複移転の問題が根本的に回避されます。

  2. 所有権と借用メカニズム:Move は、厳格な所有権と借用メカニズムを通じてリソースを管理します。各リソースには唯一の所有者があり、リソースの借用は明示的に宣言する必要があります。このメカニズムは、「共有リソース」の際の安全性の懸念を回避します。リソースの借用は、開発者がリソースの所有権を変更せずにリソースを共有および操作できることを保証します。

  3. モジュール化プログラミング:Move は、モジュール化されたプログラミング構造をサポートし、各モジュールは異なるリソース型や関数を含むことができます。モジュール化設計により、コードがより明確で再利用可能になり、開発効率が向上し、コードのエラーの可能性が低下します。

  4. 型安全性と検証可能性:Move は強い型の言語であり、これは開発者がコンパイル時に各変数とリソースの型を明示的に定義する必要があることを意味します。Move の型システムは、契約内の大部分のエラーがコンパイル段階で発見されることを保証し、実行時エラーを回避し、スマートコントラクトの安全性を向上させます。

Move 言語のサンプルコード:
以下は、Coinというリソースを作成および移転する方法を示すシンプルな Move コントラクトの例です:

address 0x1 {
    module CoinModule {
        resource struct Coin has store {
            value: u64,
        }

        public fun create_coin(value: u64): Coin {
            Coin { value }
        }

        public fun transfer_coin(coin: Coin, recipient: address): Coin {
            let new_coin = Coin { value: coin.value };
            // ここで実際の送金操作を実行できます
            return new_coin;
        }
    }
}

この例では、Coinはリソース型で、トークンの値を示すvalueフィールドを含んでいます。create_coin関数は新しいCoinリソースを作成し、transfer_coin関数はCoinリソースを指定されたアカウントに移転します。


Move 共学活動:Move 開発の迅速な習得#

より多くの開発者が Move プログラミング言語を迅速に理解し習得できるように、Move 共学活動がHOH コミュニティHackQuestOpenBuildKeyMapによって共同で発起されました。この活動は、新人に良好な学習プラットフォームを提供し、皆さんが Move 言語に慣れ、Web3 開発にどのように応用できるかを段階的に理解する手助けをすることを目的としています。

Move 分野の専門のメンターと協力することで、参加者は Move 言語の基礎知識を迅速に習得し、より複雑なアプリケーション開発へと進むことができます。ブロックチェーン初心者から一定の開発経験を持つエンジニアまで、誰でも恩恵を受けることができます。

リソースリンク:

  • sui 公式ドキュメント🚪:Sui チェーンに関する詳細なドキュメントを取得し、開発ガイドや API リファレンスなどを含みます。
  • move 学習 Bilibili 動画🚪:Bilibili のビデオチュートリアルを通じて、メンターに従って Move プログラミング言語の基礎と進んだ内容を学びます。
  • letsmove リポジトリ🚪:これは Move 学習リソースの GitHub リポジトリで、さまざまなサンプルコードやチュートリアルが含まれており、開発者が Move 言語を習得するのに役立ちます。

一、プロジェクトの作成#

まず、新しい Move プロジェクトを作成し、Task2で開発したトークンコントラクトをインポートする必要があります。

1.1 新しい Move プロジェクトを作成#

以下のコマンドを実行して、my_swapという名前の Move プロジェクトを作成します:

sui move new my_swap
cd .\my_swap\

ここに画像の説明を挿入

1.2 依存関係をインポート#

私たちのトークンコントラクトがすでにmy_coinディレクトリに実装されていると仮定します。次の方法でそれを新しいプロジェクトに依存関係としてインポートできます:

my_coin = { local = "../../task2/my_coin" }

ここに画像の説明を挿入

この基盤の上に、プロジェクトを空でコンパイルし、依存関係が正しくインポートされ、プロジェクトが正常にコンパイルできることを確認します:sui move build
ここに画像の説明を挿入

二、コントラクト設計#

コントラクトコードの部分は、実際には前回のtask4で説明したコードロジックと同じです。task4では1 種類のトークンの入出金とゲームの勝敗のプレイ方法を扱ったので、task5ではPoolトークンプールにもう 1 種類のトークンを追加し、トークンプール内で自動的に 2 種類のトークンの変換を行うだけです。

以下はトークン交換コントラクトの完全な実装コードで、核心的なロジックを段階的に分解していきます:

module my_swap::my_swap;

use my_coin::huahuahua1223_coin::HUAHUAHUA1223_COIN;
use my_coin::huahuahua1223_faucet_coin::HUAHUAHUA1223_FAUCET_COIN;
use sui::balance::{Self, Balance};
use sui::coin::{Self, Coin, from_balance, into_balance};
use sui::transfer::{share_object, transfer, public_transfer};

const EInputNotEnough: u64 = 1000;
const EPoolNotEnough: u64 = 1001;

public struct AdminCap has key {
    id: UID
}

public struct Pool has key {
    id: UID,
    huahuahua1223_faucet_coin: Balance<HUAHUAHUA1223_FAUCET_COIN>,
    huahuahua1223_coin: Balance<HUAHUAHUA1223_COIN>,
}

fun init(ctx: &mut TxContext) {
    let pool = Pool {
        id: object::new(ctx),
        huahuahua1223_faucet_coin: balance::zero<HUAHUAHUA1223_FAUCET_COIN>(),
        huahuahua1223_coin: balance::zero<HUAHUAHUA1223_COIN>(),
    };

    let admin = AdminCap { id: object::new(ctx) };

    // 公開swapプール
    share_object(pool);
    // 管理者権限をコントラクトデプロイ者に付与
    transfer(admin, ctx.sender());
}

2.1 トークンプールと管理者権限#

Pool構造体を通じて 2 種類のトークンの残高を維持し、同時にAdminCap構造体を設定して、管理者がトークンを引き出したり管理したりする権限を持つことを保証します。init関数はトークンプールを初期化し、管理者権限をコントラクトデプロイ者に付与します。

2.2 トークンの保存#

ユーザーはトークンプールに 2 種類のトークンのいずれかを預けることができます。以下は HUAHUAHUA1223_COIN を保存するロジックです:

// my_coinトークンを保存
public entry fun deposit_my_coin(
    pool: &mut Pool,
    user_coin: Coin<HUAHUAHUA1223_COIN>,
    amount: u64,
    ctx: &mut TxContext,
) {
    // ウォレットのトークンが入力金額より多いか確認
    let coin_value = user_coin.value();
    assert!(coin_value >= amount, EInputNotEnough);

    // CoinをBalanceに変換
    let mut input_balance = into_balance(user_coin);
    if (coin_value == amount) {
        // 入力のamountがすべてのトークン
        balance::join(&mut pool.huahuahua1223_coin, input_balance);
    } else {
        balance::join(
            &mut pool.huahuahua1223_coin,
            balance::split(&mut input_balance, amount),
        );
        // 残りのトークンを返却
        let surplus_coin = from_balance(input_balance, ctx);
        public_transfer(surplus_coin, ctx.sender());
    };
}

ここでの重要なポイントは以下の通りです:

  • 入力トークンの数量が十分であることを確認。
  • 残りのトークンを処理し、余剰部分をユーザーに返却。

同様のロジックはHUAHUAHUA1223_FAUCET_COINの保存にも適用されます。

2.3 トークンの引き出し#

管理者はプール内の任意のトークンを引き出すことができます。これには管理者権限AdminCapが必要です:

// 管理者がmy_coinトークンを引き出す
public entry fun withdraw_coin(
    _: &AdminCap,
    pool: &mut Pool,
    amount: u64,
    ctx: &mut TxContext,
) {
    assert!(pool.huahuahua1223_coin.value() >= amount, EPoolNotEnough );

    // from_balanceを使ってbalanceをcoin型に変換
    let withdrawn_balance = balance::split(&mut pool.huahuahua1223_coin, amount);
    let withdrawn_coin = from_balance(withdrawn_balance, ctx);
    public_transfer(withdrawn_coin, ctx.sender());
}

// 管理者がfaucet_coinトークンを引き出す
public entry fun withdraw_faucet_coin(
    _: &AdminCap,
    pool: &mut Pool,
    amount: u64,
    ctx: &mut TxContext,
) {
    assert!(pool.huahuahua1223_faucet_coin.value() >= amount, EPoolNotEnough );

    // from_balanceを使ってbalanceをcoin型に変換
    let withdrawn_balance = balance::split(&mut pool.huahuahua1223_faucet_coin, amount);
    let withdrawn_coin = from_balance(withdrawn_balance, ctx);
    public_transfer(withdrawn_coin, ctx.sender());
}

この部分のロジックは、プール内の残高が十分であることを厳密に確認し、引き出し失敗の事態を防ぎます。

2.4 トークン交換#

トークンプールの核心機能は、2 種類のトークンの相互交換を実現することです。以下にそれぞれの交換ロジックを示します:

  • faucet_coin から my_coin への交換
// 2つのfaucet_coinを1つのmy_coinに変換
public entry fun swap_faucet_coin_to_my_coin(
    pool: &mut Pool,
    user_coin: Coin<HUAHUAHUA1223_FAUCET_COIN>,
    amount: u64,
    ctx: &mut TxContext,
) {
    // swapプールがこれだけのhuahuahua1223_coinを交換できるか確認
    let output_value = amount * 1000 / 2000;
    assert!(pool.huahuahua1223_coin.value() >= output_value, EPoolNotEnough);

    // faucet_coinをswapプールに預けて交換を待つ
    deposit_faucet_coin(pool, user_coin, amount, ctx);

    // huahuahua1223_coinの半分の数量を交換
    let output_balance = balance::split(&mut pool.huahuahua1223_coin, output_value);
    let output_coin = from_balance(output_balance, ctx);
    public_transfer(output_coin, ctx.sender());
}
  • my_coin から faucet_coin への交換
// 1つのmy_coinを2つのfaucet_coinに変換
public entry fun swap_my_coin_to_faucet_coin(
    pool: &mut Pool,
    user_coin: Coin<HUAHUAHUA1223_COIN>,
    amount: u64,
    ctx: &mut TxContext,
) {
    // swapプールがこれだけのhuahuahua1223_faucet_coinを交換できるか確認
    let output_value = amount * 2000 / 1000;
    assert!(pool.huahuahua1223_faucet_coin.value() >= output_value, EPoolNotEnough);

    // my_coinをswapプールに預けて交換を待つ
    deposit_my_coin(pool, user_coin, amount, ctx);

    // 2倍のhuahuahua1223_faucet_coinを交換
    let output_balance = balance::split(&mut pool.huahuahua1223_faucet_coin, output_value);
    let output = from_balance(output_balance, ctx);
    public_transfer(output, ctx.sender());
}

上記のロジックにより、ユーザーは事前定義された比率(例えば2:1または1:2)に基づいて 2 種類のトークンを自由に交換できます。

2.5 メインネットデプロイ#

  1. メインネットに接続していない場合は、このチュートリアルの第 3 部🚪を参照し、その後コントラクトプロジェクトのルートディレクトリ(例:my_swap)で次のコマンドを実行してコントラクトをデプロイします:
sui client publish --skip-dependency-verification
  1. デプロイ後、トランザクションハッシュが得られます。この値を記録し、suivision ブロックチェーンブラウザ🚪でコントラクトの詳細を確認します。
    ここに画像の説明を挿入
  2. コントラクトの詳細にあるPackage IDを見つけ、フロントエンドまたはSui CLIテストツールでコントラクト関数を呼び出します。
    ここに画像の説明を挿入

三、テストと検証#

コントラクトのデプロイが完了した後、主要機能の呼び出しをテストし、my_swapコントラクトの正確性と安定性を確認します。以下のテストには、トークンの預け入れ引き出しと交換の完全なプロセスが含まれ、主要な操作の結果と検証が記録されています。
ここに画像の説明を挿入

環境準備#

テストを開始する前に、アカウントに十分なtask2トークンがあることを確認してください。テストを容易にするために、Sui CLI を使用してアカウントに 100 個のcoinと 100 個のfaucet_coinを再鋳造しました。鋳造コマンドに不慣れな場合は、以前のTask2 チュートリアル🚪を参照してください。
ここに画像の説明を挿入

以下はアカウントの初期状態です:

  • coinトークンの数量:100
  • faucet_coinトークンの数量:100

ここに画像の説明を挿入

3.1 トークンの預け入れ#

まず、deposit関数を呼び出して、一部のトークンをプールに預けます。
操作 1:20 個の faucet_coin を預け入れる
ここに画像の説明を挿入

操作 2:20 個の coin を預け入れる
ここに画像の説明を挿入

結果検証:
アカウントの残りのcoin数量:80
アカウントの残りのfaucet_coin数量:80
ここに画像の説明を挿入

3.2 トークンの引き出し#

次に、withdraw関数を呼び出して、管理者権限を通じて資金プールからトークンを引き出します。

操作 1:6 個の faucet_coin を引き出す
管理者は以下のコマンドを使用して 6 個のfaucet_coinを引き出します(注意:トークンの精度は 8 であるため、600000000 は 6 個のトークンを示します):
ここに画像の説明を挿入

操作 2:6 個の coin を引き出す
ここに画像の説明を挿入

結果検証:
管理者アカウントに 6 個のcoinが追加されました。
管理者アカウントに 6 個のfaucet_coinが追加されました。
ここに画像の説明を挿入

3.3 トークン交換#

最後に、swap関数を呼び出して、2 種類のトークンの相互交換機能を検証し、交換比率が正しいことを確認します。

操作 1:6 個の faucet_coin を使用して 3 個の coin を取得、交換比率は2:1
ここに画像の説明を挿入
結果検証:
ユーザーアカウントに 3 個のcoinが追加され、合計 89 個になりました。
ユーザーアカウントから 6 個のfaucet_coinが減少し、合計 80 個になりました。
ここに画像の説明を挿入

操作 2:5 個の faucet_coin を使用して 10 個の coin を取得、交換比率は1:2
ここに画像の説明を挿入
結果検証:
ユーザーアカウントから 5 個のcoinが減少し、合計 84 個になりました。
ユーザーアカウントに 10 個のfaucet_coinが追加され、合計 90 個になりました。
ここに画像の説明を挿入

上記のテストを通じて、my_swapコントラクトの各機能が検証されました:

  1. トークンを預け入れる際、残高が正しく減少し、余剰部分の返却メカニズムが有効です。
  2. トークンを引き出す際、管理者権限の検証が正確で、引き出しロジックが正確です。
  3. トークンの相互交換時、交換比率が正しく、資金プールとアカウントの残高が正常に更新されます。

これで、Task5:トークン交換コントラクトが無事に完了しました 🎉!

次の挑戦:次のステップでは、動的価格設定や流動性プールの設計など、より複雑なロジックに挑戦し、分散型金融の無限の可能性をさらに探求していきましょう!


まとめ#

本記事を通じて、あなたは Move 言語を使用して Sui チェーン上にシンプルなトークン交換コントラクトを構築する方法を習得し、トークンの入出金、引き出し、交換の基本的なロジック設計に慣れることができたはずです。この文章が DeFi 開発の入門段階で実用的なガイダンスを提供し、Move プログラミング言語と Sui ブロックチェーンに対する理解を深める助けとなることを願っています。

DeFi アプリケーションの開発や Move 言語に興味がある方は、今後の文章やプロジェクトの共有にぜひご注目ください!疑問やアイデアがあれば、コメント欄で私と交流してください🌹


もっと素晴らしいコンテンツを、シリーズ記事目次でお楽しみください!
私たちは Move の探求の道で共に成長し、またお会いしましょう! 🎉

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