このセクションでは、CosmWasmスマートコントラクト開発のための環境セットアップ方法を説明します。
前提条件
開始前に、rustup と最新バージョンのrustcおよびcargoがインストールされていることを確認してください。現在、Rust v1.58.1以降でテストしています。
また、wasm32-unknown-unknownターゲットとcargo-generate Rustクレートもインストールする必要があります。
以下のコマンドでバージョンを確認できます:
rustc --version
cargo --version
rustup target list --installed
# wasm32が上記に表示されない場合、以下を実行
rustup target add wasm32-unknown-unknown
# cargo-generateをインストールするには、以下を実行
cargo install cargo-generate
カウンターを指定値まで増加およびリセットするスマートコントラクトの作成と操作
CosmWasmスマートコントラクトの基礎を理解し、Injectiveにデプロイしてツールで操作する方法を習得
CosmWasmコントラクトの基礎
スマートコントラクトはシングルトンオブジェクト のインスタンスと考えることができます。その内部状態はブロックチェーン上に永続化されます。ユーザーはJSONメッセージを送信することで状態変更をトリガーでき、JSONメッセージ形式のリクエストを送信して状態をクエリすることもできます。これらのJSONメッセージはMsgSendやMsgExecuteContractなどのInjectiveブロックチェーンメッセージとは異なります。
スマートコントラクト開発者として、コントラクトのインターフェースを構成する3つの関数を定義する必要があります:
instantiate():コントラクトのインスタンス化時に呼び出されるコンストラクタで、初期状態を提供します
execute():ユーザーがスマートコントラクトのメソッドを呼び出す際に実行されます
query():ユーザーがスマートコントラクトからデータを取得する際に呼び出されます
サンプルカウンターコントラクト では、1つのinstantiate、1つのquery、2つのexecuteメソッドを実装します。
テンプレートから始める
作業ディレクトリで、以下のコマンドを実行して推奨のフォルダ構成とビルドオプションでスマートコントラクトをすぐに開始できます:
cargo generate --git https://github.com/CosmWasm/cw-template.git --branch 1.0 --name my-first-contract
cd my-first-contract
これにより、スマートコントラクトの基本的なボイラープレートと構造が提供されます。src/contract.rs ファイルには、標準的なCosmWasmエントリポイントであるinstantiate() 、execute() 、query() が適切に公開されています。
State
CosmWasmのStateについて詳しくはドキュメント を参照してください。
Stateはスマートコントラクトのデータが保存・アクセスされるデータベースの状態を管理します。
スターティングテンプレート は以下の基本的な状態を持ちます。シングルトン構造体Stateは以下を含みます:
count:execute()メッセージが増加またはリセットを行う32ビット整数
owner:MsgInstantiateContractの送信者addressで、特定のexecuteメッセージの実行可否を判断します
// src/state.rs
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use cosmwasm_std::Addr;
use cw_storage_plus::Item;
#[ derive (Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct State {
pub count: i32,
pub owner: Addr,
}
pub const STATE: Item < State > = Item:: new ( "state" );
Injectiveスマートコントラクトは、InjectiveネイティブのLevelDB(バイトベースのKey-Valueストア)を通じて永続的な状態を保持できます。永続化したいデータには一意のキーを割り当てる必要があり、これによりデータのインデックス作成と取得が可能になります。
データはrawバイトとしてのみ永続化できるため、構造やデータ型はシリアライズおよびデシリアライズ関数のペアとして表現する必要があります。例えば、オブジェクトはバイトとして保存するため、オブジェクトをバイトにエンコードしてブロックチェーンに保存する関数と、バイトをコントラクトロジックが理解できるデータ型にデコードする関数の両方を提供する必要があります。バイト表現の選択は自由ですが、クリーンな双方向マッピングを提供する必要があります。
CosmWasmはcosmwasm-storage などのユーティリティクレートを提供しており、構造体やRustの数値型などの一般的に使用される型に対して自動的にシリアライズとデシリアライズを行う「singleton」や「bucket」などのデータコンテナの便利な高レベル抽象化を提供します。さらに、cw-storage-plus クレートを使用することで、より効率的なストレージメカニズムを利用できます。
State構造体がcountとownerの両方を保持していることに注目してください。derive属性は以下の便利なトレイトを自動実装します:
Serialize:シリアライズを提供
Deserialize:デシリアライズを提供
Clone:構造体のコピーを可能にする
Debug:構造体の文字列出力を可能にする
PartialEq:等価比較を提供
JsonSchema:JSONスキーマを自動生成
AddrはInjectiveの人間が読めるアドレスを参照し、injがプレフィックスとして付きます。例:inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt
InstantiateMsg
InstantiateMsgは、ユーザーがMsgInstantiateContractを通じてブロックチェーン上でコントラクトをインスタンス化する際にコントラクトに提供されます。これにより、コントラクトの設定と初期状態が提供されます。
Injectiveブロックチェーンでは、コントラクトコードのアップロードとコントラクトのインスタンス化は別々のイベントとして扱われます(Ethereumとは異なります)。これにより、少数の検証済みコントラクトアーキタイプが同じベースコードを共有しながら異なるパラメータで設定された複数のインスタンスとして存在できます(標準的なERC20を想像し、そのコードを使用する複数のトークンがあるイメージです)。
このコントラクトでは、コントラクト作成者が初期状態をJSONメッセージとして提供することが期待されます。以下のメッセージ定義では、初期カウントを表すcountパラメータを1つ保持しています。
メッセージ定義
// src/msg.rs
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[ derive (Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {
pub count: i32,
}
コントラクトロジック
contract.rsで、最初のエントリポイントinstantiate()を定義します。ここでコントラクトがインスタンス化され、InstantiateMsgが渡されます。メッセージからcountを取得し、初期状態を設定します:
countにメッセージのcountを割り当て
ownerにMsgInstantiateContractの送信者を割り当て
// src/contract.rs
#[ cfg_attr (n ot (feature = "library" ), entry_point)]
pub fn instantiate (
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: InstantiateMsg,
) -> Result < Response, ContractError > {
let state = State {
count: msg . count ,
owner: info . sender . clone (),
};
set_contract_version ( deps . storage , CONTRACT_NAME, CONTRACT_VERSION) ? ;
STATE . save ( deps . storage , & state) ? ;
Ok ( Response::new ()
. add_attribute ( "method" , "instantiate" )
. add_attribute ( "owner" , info . sender )
. add_attribute ( "count" , msg . count . to_string ()))
}
ExecuteMsg
CosmWasmのExecuteMsgについて詳しくはドキュメント を参照してください。
ExecuteMsgはMsgExecuteContractを通じてexecute()関数に渡されるJSONメッセージです。InstantiateMsgとは異なり、ExecuteMsgはスマートコントラクトがユーザーに公開できるさまざまな種類の関数に対応するため、複数の種類のメッセージとして存在できます。execute()関数 は、これらの異なる種類のメッセージを適切なメッセージハンドラロジックにルーティングします。
2つのExecuteMsg があります:IncrementとReset。
Incrementは入力パラメータがなく、countの値を1増加させます。
Resetは32ビット整数をパラメータとして受け取り、countの値を入力パラメータにリセットします。
Increment
すべてのユーザーが現在のカウントを1増加させることができます。
Reset
オーナーのみがカウントを特定の数値にリセットできます。実装の詳細はロジックを参照してください。
{
"reset" : {
"count" : 5
}
}
メッセージ定義
ExecuteMsgには、コントラクトが理解できるさまざまな種類のメッセージを多重化するためにenumを使用できます。serde属性は属性キーをスネークケースおよび小文字に書き換えるため、シリアライズおよびデシリアライズ時にIncrementとResetの代わりにincrementとresetになります。
// src/msg.rs
#[ derive (Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[ serde (rename_all = "snake_case" )]
pub enum ExecuteMsg {
Increment {},
Reset { count: i32 },
}
ロジック
// src/contract.rs
#[ cfg_attr (n ot (feature = "library" ), entry_point)]
pub fn execute (
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result < Response, ContractError > {
match msg {
ExecuteMsg::Increment {} => try_increment (deps),
ExecuteMsg::Reset { count } => try_reset (deps, info, count),
}
}
これはexecute()メソッドで、Rustのパターンマッチングを使用して受信したExecuteMsgを適切な処理ロジックにルーティングします。受信したメッセージに応じてtry_increment()またはtry_reset()の呼び出しにディスパッチします。
pub fn try_increment (deps: DepsMut) -> Result < Response, ContractError > {
STATE . update ( deps . storage , | mut state | -> Result < _, ContractError > {
state . count += 1 ;
Ok (state)
}) ? ;
Ok ( Response::new (). add_attribute ( "method" , "try_increment" ))
}
まず、キーstateにあるアイテムを更新するためにストレージへの可変参照を取得します。次に、新しい状態でOk結果を返すことでstateのcountを更新します。最後に、Responseと共にOk結果を返すことで、成功を確認してコントラクトの実行を終了します。
// src/contract.rs
pub fn try_reset (deps: DepsMut, info: MessageInfo, count: i32) -> Result < Response, ContractError > {
STATE . update ( deps . storage , | mut state | -> Result < _, ContractError > {
if info . sender != state . owner {
return Err (ContractError::Unauthorized {});
}
state . count = count;
Ok (state)
}) ? ;
Ok ( Response::new (). add_attribute ( "method" , "reset" ))
}
resetのロジックはincrementと非常に似ていますが、最初にメッセージの送信者がreset関数の呼び出しを許可されているかどうかを確認します(この場合、コントラクトのオーナーである必要があります)。
QueryMsg
GetCountクエリメッセージ はパラメータがなく、count値を返します。
実装の詳細はロジックを参照してください。
テンプレートコントラクトは1種類のQueryMsgのみをサポートしています:
GetCount
リクエスト:
レスポンス:
メッセージ定義
コントラクトでデータクエリをサポートするには、QueryMsgのフォーマット(リクエストを表す)とクエリの出力構造(この場合はCountResponse)の両方を定義する必要があります。query()は構造化されたJSONを通じてユーザーに情報を返送するため、レスポンスの形式を公開する必要があります。詳細はJSONスキーマの生成を参照してください。
src/msg.rsに以下を追加します:
// src/msg.rs
#[ derive (Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[ serde (rename_all = "snake_case" )]
pub enum QueryMsg {
// GetCountは現在のカウントをJSONエンコードされた数値として返す
GetCount {},
}
// 各クエリレスポンス用のカスタム構造体を定義
#[ derive (Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct CountResponse {
pub count: i32,
}
ロジック
query()のロジックはexecute()と類似していますが、query()はエンドユーザーがトランザクションを作成せずに呼び出されるため、env引数は省略されます。
// src/contract.rs
#[ cfg_attr (n ot (feature = "library" ), entry_point)]
pub fn query (deps: Deps, _env: Env, msg: QueryMsg) -> StdResult < Binary > {
match msg {
QueryMsg::GetCount {} => to_binary ( & query_count (deps) ? ),
}
}
fn query_count (deps: Deps) -> StdResult < CountResponse > {
let state = STATE . load ( deps . storage ) ? ;
Ok (CountResponse { count: state . count })
}
ユニットテスト
ユニットテストはチェーンにコードをデプロイする前の最初の保証として実行すべきです。実行が速く、RUST_BACKTRACE=1フラグを使用することで失敗時に有用なバックトレースを提供できます:
cargo unit - test // RUST_BACKTRACE=1で実行するとバックトレースが表示されます
ユニットテストの実装 はsrc/contract.rsにあります。
コントラクトのビルド
コントラクトを理解しテストしたので、以下のコマンドを実行してコントラクトをビルドできます。これにより、次のステップでコントラクトを最適化する前に予備的なエラーを確認します。
次に、チェーンへのアップロードに向けてコードを準備するためにコントラクトを最適化する必要があります。
CosmWasmにはrust-optimizer という小さく一貫したビルド出力を生成できる最適化コンパイラがあります。最も簡単な方法はPublishされたDockerイメージを使用することです。最新のx86バージョンはこちら 、最新のARMバージョンはこちら を確認してください。Dockerが実行中の状態で、以下のコマンドを実行してコントラクトコードを/codeにマウントし出力を最適化します($(pwd)の代わりに絶対パスを使用することもできます):
docker run --rm -v "$( pwd )":/code \
--mount type=volume,source="$( basename "$( pwd )")_cache",target=/code/target \
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
cosmwasm/rust-optimizer:0.12.12
ARM64マシンの場合は、ARM64用にビルドされたDockerイメージを使用してください:
docker run --rm -v "$( pwd )":/code \
--mount type=volume,source="$( basename "$( pwd )")_cache",target=/code/target \
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
cosmwasm/rust-optimizer-arm64:0.12.12
CosmWasmはARM64版コンパイラの使用を推奨していません。Intel/AMD版とは異なるWasmアーティファクトが生成されるためです。リリース/本番環境では、Intel/AMDオプティマイザでビルドされたコントラクトのみの使用が推奨されます。詳細はこちら を参照してください。
コマンド実行時にUnable to update registry `crates-io`エラーが表示される場合があります。コントラクトディレクトリ内のCargo.tomlファイルに以下の行を追加して再実行してください: [ net ]
git-fetch-with-cli = true
詳細はThe Cargo Book を参照してください。
これにより、PROJECT_NAME.wasmとWasmファイルのSha256ハッシュを含むchecksums.txtが格納されたartifactsディレクトリが生成されます。Wasmファイルは決定論的にコンパイルされます(同じDockerで同じGitコミットを実行すると、同一のSha256ハッシュを持つ同一のファイルが得られます)。
injectivedのインストール
injectivedはInjectiveに接続してInjectiveブロックチェーンとの対話を可能にするコマンドラインインターフェースおよびデーモンです。
CLIを使用してスマートコントラクトとローカルで対話する場合は、injectivedをインストールする必要があります。injectiveインストールガイド のインストール手順に従ってください。
または、このチュートリアルを簡単にするためにDockerイメージが用意されています。
バイナリからinjectivedをインストールした場合は、Dockerコマンドを無視してください。
パブリックエンドポイントセクション で、MainnetおよびTestnetと対話するための正しい—node情報を確認できます。
以下のコマンドを実行すると、Dockerコンテナが無期限に実行されます。
docker run --name= "injective-core-staging" \
-v=<directory_to_which_you_cloned_cw-template>/artifacts:/var/artifacts \
--entrypoint=sh public.ecr.aws/l9h3g6c6/injective-core:staging \
-c "tail -F anything"
注意:directory_to_which_you_cloned_cw-templateは絶対パスである必要があります。絶対パスはCosmWasm/cw-counterディレクトリ内でpwdコマンドを実行することで簡単に取得できます。
新しいターミナルを開き、Dockerコンテナに入ってチェーンを初期化します:
docker exec -it injective-core-staging sh
後で必要になるjq依存パッケージを追加します:
# "injective-core-staging"コンテナ内で
apk add jq
次に、ローカルチェーンの初期化に進み、testuserというテストユーザーを追加します(プロンプトが表示されたらパスワードとして12345678を使用)。テストユーザーは、テストネットでメッセージの署名に使用する新しいプライベートキーの生成にのみ使用します:
# "injective-core-staging"コンテナ内で
injectived keys add testuser
出力
- name: testuser
type: local
address: inj1exjcp8pkvzqzsnwkzte87fmzhfftr99kd36jat
pubkey: '{"@type":"/injective.crypto.v1beta1.ethsecp256k1.PubKey","key":"Aqi010PsKkFe9KwA45ajvrr53vfPy+5vgc3aHWWGdW6X"}'
mnemonic: ""
**Important** write this mnemonic phrase in a safe place.
It is the only way to recover your account if you ever forget your password.
wash wise evil buffalo fiction quantum planet dial grape slam title salt dry and some more words that should be here
先に進むためにアドレスをメモするか、環境変数としてエクスポートしてください:
# "injective-core-staging"コンテナ内で
export INJ_ADDRESS = < your inj address >
これでtestuserがInjective Testnetに正常に作成されました。faucetからテストネット資金をリクエストした後、残高も保有しているはずです。
確認するには、Injective Testnet Explorer でアドレスを検索して残高を確認してください。
または、Bank残高のクエリ またはcurlで確認することもできます:
curl -X GET "https://sentry.testnet.lcd.injective.network/cosmos/bank/v1beta1/balances/<your_INJ_address>" -H "accept: application/json"
Wasmコントラクトのアップロード
前のステップでコンパイルした.wasmファイルをInjective Testnetにアップロードします。メインネットの手順は異なり、ガバナンスプロポーザルが必要です。
# "injective-core-staging"コンテナ内で、またはinjectivedをローカルで実行している場合はコントラクトディレクトリから
yes 12345678 | injectived tx wasm store artifacts/my_first_contract.wasm \
--from=$(echo $INJ_ADDRESS ) \
--chain-id = "injective-888" \
--yes --fees=1000000000000000inj --gas=2000000 \
--node=https://testnet.sentry.tm.injective.network:443
出力:
code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 912458AA8E0D50A479C8CF0DD26196C49A65FCFBEEB67DF8A2EA22317B130E2C
Injective Testnet Explorer でアドレスを確認し、コード保存から返されたtxhashのトランザクションを探してください。トランザクションタイプはMsgStoreCodeのはずです。
Injective Testnet上のすべての保存コードはCode で確認できます。
保存したコードを見つけるには複数の方法があります:
Injective Explorerのコード一覧 でTxHashを探します。最新のものである可能性が高いです。
injectivedを使用してトランザクション情報をクエリします。
トランザクションをクエリするにはtxhashを使用してコントラクトがデプロイされたことを確認します。
injectived query tx 912458AA8E0D50A479C8CF0DD26196C49A65FCFBEEB67DF8A2EA22317B130E2C --node=https://testnet.sentry.tm.injective.network:443
出力を詳しく見ると、アップロードされたコントラクトのcode_idが290であることがわかります:
- events:
- attributes:
- key: access_config
value: '{"permission":"Everybody","address":""}'
- key: checksum
value: '"+OdoniOsDJ1T9EqP2YxobCCwFAqNdtYA4sVGv7undY0="'
- key: code_id
value: '"290"'
- key: creator
value: '"inj1h3gepa4tszh66ee67he53jzmprsqc2l9npq3ty"'
type : cosmwasm.wasm.v1.EventCodeStored
- attributes:
- key: action
value: /cosmwasm.wasm.v1.MsgStoreCode
- key: module
value: wasm
- key: sender
value: inj1h3gepa4tszh66ee67he53jzmprsqc2l9npq3ty
type : message
- attributes:
- key: code_id
value: "290"
type : store_code
code_idを環境変数としてエクスポートしましょう。コントラクトのインスタンス化に必要です。このステップはスキップして後で手動で追加することもできますが、IDを記録しておいてください。
export CODE_ID = < code_id of your stored contract >
JSONスキーマの生成
Wasmのinstantiate、execute、queryはJSONを受け取りますが、これだけでは使用に十分な情報ではありません。期待されるメッセージのスキーマをクライアントに公開する必要があります。
JSONスキーマの自動生成を利用するには、スキーマが必要な各データ構造を登録する必要があります。
// examples/schema.rs
use std::env::current_dir;
use std::fs::create_dir_all;
use cosmwasm_schema::{export_schema, remove_schemas, schema_for};
use my_first_contract::msg::{CountResponse, HandleMsg, InitMsg, QueryMsg};
use my_first_contract::state::State;
fn main () {
let mut out_dir = current_dir (). unwrap ();
out_dir . push ( "schema" );
create_dir_all ( & out_dir). unwrap ();
remove_schemas ( & out_dir). unwrap ();
export_schema ( & schema_for ! (InstantiateMsg), & out_dir);
export_schema ( & schema_for ! (ExecuteMsg), & out_dir);
export_schema ( & schema_for ! (QueryMsg), & out_dir);
export_schema ( & schema_for ! (State), & out_dir);
export_schema ( & schema_for ! (CountResponse), & out_dir);
}
スキーマは以下のコマンドで生成できます:
これにより、コントラクトが受け取る3つのメッセージタイプ、クエリレスポンスメッセージ、内部Stateに対応する5つのファイルが./schemaに出力されます。
これらのファイルは標準的なJSON Schemaフォーマットで、さまざまなクライアントサイドツールで使用できます。コーデックの自動生成や、定義されたスキーマに対する受信JSONの検証に利用できます。
スキーマを生成し(こちら で確認できます)、次のステップに必要なので内容を理解しておいてください。
コントラクトのインスタンス化
コードがInjective上にアップロードされたので、コントラクトをインスタンス化して対話できるようにします。
CosmWasmでは、コントラクトコードのアップロードとコントラクトのインスタンス化は別々のイベントとして扱われます。
コントラクトをインスタンス化するには、前のステップで取得したcode_idとJSONエンコードされた初期化引数 、およびlabel(リストでこのコントラクトを識別するための人間が読める名前)を指定して以下のCLIコマンドを実行します。
INIT = '{"count":99}'
yes 12345678 | injectived tx wasm instantiate $CODE_ID $INIT \
--label= "CounterTestInstance" \
--from=$(echo $INJ_ADDRESS ) \
--chain-id = "injective-888" \
--yes --fees=1000000000000000inj \
--gas=2000000 \
--no-admin \
--node=https://testnet.sentry.tm.injective.network:443
出力:
code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 01804F525FE336A5502E3C84C7AE00269C7E0B3DC9AA1AB0DDE3BA62CF93BE1D
コントラクトアドレスとメタデータは以下の方法で確認できます: injectived query wasm contract inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7 --node=https://testnet.sentry.tm.injective.network:443
コントラクトのクエリ
先に説明した通り、唯一のQueryMsgはget_countです。
GET_COUNT_QUERY = '{"get_count":{}}'
injectived query wasm contract-state smart inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7 " $GET_COUNT_QUERY " \
--node=https://testnet.sentry.tm.injective.network:443 \
--output json
出力:
コントラクトをインスタンス化した時に設定した通り、countは99です。
同じコントラクトをクエリすると、他のユーザーがカウントを増加またはリセットして操作している可能性があるため、異なるレスポンスが返される場合があります。
コントラクトの実行
カウンターを増加させてコントラクトと対話してみましょう。
INCREMENT = '{"increment":{}}'
yes 12345678 | injectived tx wasm execute inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7 " $INCREMENT " --from=$( echo $INJ_ADDRESS ) \
--chain-id= "injective-888" \
--yes --fees=1000000000000000inj --gas=2000000 \
--node=https://testnet.sentry.tm.injective.network:443 \
--output json
カウントをクエリすると、以下のようになります:
yes 12345678 | は自動的にパスフレーズをinjectived tx wasm execute の入力にパイプ(渡す)するため、手動で入力する必要はありません。
カウンターをリセットするには:
RESET = '{"reset":{"count":999}}'
yes 12345678 | injectived tx wasm execute inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7 " $RESET " \
--from=$(echo $INJ_ADDRESS ) \
--chain-id = "injective-888" \
--yes --fees=1000000000000000inj --gas=2000000 \
--node=https://testnet.sentry.tm.injective.network:443 \
--output json
コントラクトを再度クエリすると、カウントが指定した値にリセットされていることがわかります:
Cosmosメッセージ
カスタムスマートコントラクトロジックの定義に加えて、CosmWasmではコントラクトが基盤となるCosmos SDK機能と対話することもできます。一般的なユースケースの1つは、Cosmos SDKのBankモジュールを使用してコントラクトから指定アドレスにトークンを送信することです。
例:Bank Send
BankMsg::Sendメッセージを使用すると、コントラクトが別のアドレスにトークンを転送できます。報酬の配布やユーザーへの返金など、さまざまなシナリオで役立ちます。
注意: 資金の送信と別のコントラクト上の関数の実行を同時に行いたい場合は、BankMsg::Sendを使用しないでください。代わりに、WasmMsg::Executeを使用して、それぞれのfundsフィールドを設定してください。
メッセージの構築
コントラクトのexecute関数内でBankMsg::Sendメッセージを構築できます。このメッセージでは受信者アドレスと送信額を指定する必要があります。構築方法の例を以下に示します:
use cosmwasm_std :: { BankMsg , Coin , Response , MessageInfo };
pub fn try_send (
info : MessageInfo ,
recipient_address : String ,
amount : Vec < Coin >,
) -> Result < Response , ContractError > {
let send_message = BankMsg :: Send {
to_address : recipient_address ,
amount ,
};
let response = Response :: new () . add_message ( send_message );
Ok ( response )
}
スマートコントラクトでの使用
コントラクトでは、ExecuteMsg enumにBank送金機能を処理する新しいバリアントを追加できます:
#[derive( Serialize , Deserialize , Clone , Debug , PartialEq , JsonSchema )]
#[serde(rename_all = "snake_case" )]
pub enum ExecuteMsg {
// ... 他のメッセージ ...
SendTokens { recipient : String , amount : Vec < Coin > },
}
次に、execute関数にこのメッセージを処理するケースを追加します:
#[cfg_attr(not(feature = "library" ), entry_point)]
pub fn execute (
deps : DepsMut ,
env : Env ,
info : MessageInfo ,
msg : ExecuteMsg ,
) -> Result < Response , ContractError > {
match msg {
// ... 他のメッセージ処理 ...
ExecuteMsg :: SendTokens { recipient , amount } => try_send ( info , recipient , amount ),
}
}
テスト
他のスマートコントラクト関数と同様に、Bank送金機能が期待通りに動作することを確認するためのユニットテストを追加する必要があります。さまざまなトークン量の送信やエラーの適切な処理など、異なるシナリオのテストを含めてください。
ローカルInjectiveチェーンを含む統合テストの実行にはtest-tube を使用できます。
おめでとうございます!初めてのInjectiveスマートコントラクトを作成して操作し、InjectiveでのCosmWasm開発の始め方を習得しました。コントラクト用のWeb UIを作成するガイドについては「フロントエンドの作成」に進んでください。