メインコンテンツへスキップ
このセクションでは、CosmWasmスマートコントラクト開発のための環境セットアップ方法を説明します。

前提条件

開始前に、rustupと最新バージョンのrustcおよびcargoがインストールされていることを確認してください。現在、Rust v1.58.1以降でテストしています。 また、wasm32-unknown-unknownターゲットとcargo-generate Rustクレートもインストールする必要があります。 以下のコマンドでバージョンを確認できます:

目標

  • カウンターを指定値まで増加およびリセットするスマートコントラクトの作成と操作
  • CosmWasmスマートコントラクトの基礎を理解し、Injectiveにデプロイしてツールで操作する方法を習得

CosmWasmコントラクトの基礎

スマートコントラクトはシングルトンオブジェクトのインスタンスと考えることができます。その内部状態はブロックチェーン上に永続化されます。ユーザーはJSONメッセージを送信することで状態変更をトリガーでき、JSONメッセージ形式のリクエストを送信して状態をクエリすることもできます。これらのJSONメッセージはMsgSendMsgExecuteContractなどのInjectiveブロックチェーンメッセージとは異なります。 スマートコントラクト開発者として、コントラクトのインターフェースを構成する3つの関数を定義する必要があります:
  • instantiate():コントラクトのインスタンス化時に呼び出されるコンストラクタ関数であり、初期状態を設定します。
  • execute():ユーザーがスマートコントラクトのメソッドを呼び出す際に実行されます
  • query():ユーザーがスマートコントラクトからデータを取得する際に呼び出されます
サンプルカウンターコントラクトでは、1つのinstantiate、1つのquery、2つのexecuteメソッドを実装します。

テンプレートから始める

作業ディレクトリで以下のコマンドを実行すると、推奨されるフォルダ構成とビルド設定を備えたテンプレートから開発を開始できます:
これにより、スマートコントラクトの基本的なボイラープレートと構造が提供されます。src/contract.rsファイルには、標準的なCosmWasmエントリポイントであるinstantiate()execute()query()が適切に公開されています。

State

CosmWasmのStateについて詳しくはドキュメントを参照してください。
Stateはスマートコントラクトのデータが保存・アクセスされるデータベースの状態を管理します。 スターティングテンプレートは以下の基本的な状態を持ちます。シングルトン構造体Stateは以下を含みます:
  • countexecute()メッセージが増加またはリセットを行う32ビット整数
  • ownerMsgInstantiateContractの送信者addressで、特定のexecuteメッセージの実行可否を判断します
Injectiveスマートコントラクトは、InjectiveネイティブのLevelDB(バイトベースのKey-Valueストア)を通じて永続的な状態を保持できます。永続化したいデータには一意のキーを割り当てる必要があり、これによりデータのインデックス作成と取得が可能になります。 データはrawバイトとしてのみ永続化できるため、構造やデータ型はシリアライズおよびデシリアライズ関数のペアとして表現する必要があります。例えば、オブジェクトはバイトとして保存するため、オブジェクトをバイトにエンコードしてブロックチェーンに保存する関数と、バイトをコントラクトロジックが理解できるデータ型にデコードする関数の両方を提供する必要があります。バイト表現の選択は自由ですが、クリーンな双方向マッピングを提供する必要があります。 CosmWasmはcosmwasm-storageなどのユーティリティクレートを提供しており、構造体やRustの数値型などの一般的に使用される型に対して自動的にシリアライズとデシリアライズを行う「singleton」や「bucket」などのデータコンテナの便利な高レベル抽象化を提供します。さらに、cw-storage-plusクレートを使用することで、より効率的なストレージメカニズムを利用できます。 State構造体がcountownerの両方を保持していることに注目してください。derive属性は以下の便利なトレイトを自動実装します:
  • Serialize:シリアライズを提供
  • Deserialize:デシリアライズを提供
  • Clone:構造体のコピーを可能にする
  • Debug:構造体の文字列出力を可能にする
  • PartialEq:等価比較を提供
  • JsonSchema:JSONスキーマを自動生成
AddrはInjectiveの人間が読めるアドレスを参照し、injがプレフィックスとして付きます。例:inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt

InstantiateMsg

CosmWasmのInstantiateMsgに関するドキュメントを参照してください。
InstantiateMsgは、ユーザーがMsgInstantiateContractを通じてブロックチェーン上でコントラクトをインスタンス化する際にコントラクトに提供されます。これにより、コントラクトの設定と初期状態が提供されます。 Injectiveブロックチェーンでは、コントラクトコードのアップロードとコントラクトのインスタンス化は別々のイベントとして扱われます(Ethereumとは異なります)。これにより、少数の検証済みコントラクトアーキタイプが同じベースコードを共有しながら異なるパラメータで設定された複数のインスタンスとして存在できます(標準的なERC20を想像し、そのコードを使用する複数のトークンがあるイメージです)。

このコントラクトでは、コントラクト作成者が初期状態をJSONメッセージとして提供することが期待されます。以下のメッセージ定義では、初期カウントを表すcountパラメータを1つ保持しています。

メッセージ定義

コントラクトロジック

contract.rsで、最初のエントリポイントinstantiate()を定義します。ここでコントラクトがインスタンス化され、InstantiateMsgが渡されます。メッセージからcountを取得し、初期状態を設定します:
  • countにメッセージのcountを割り当て
  • ownerMsgInstantiateContractの送信者を割り当て

ExecuteMsg

CosmWasmのExecuteMsgについて詳しくはドキュメントを参照してください。
ExecuteMsgMsgExecuteContractを通じてexecute()関数に渡されるJSONメッセージです。InstantiateMsgとは異なり、ExecuteMsgはスマートコントラクトがユーザーに公開できるさまざまな種類の関数に対応するため、複数の種類のメッセージとして存在できます。execute()関数は、これらの異なる種類のメッセージを適切なメッセージハンドラロジックにルーティングします。 2つのExecuteMsgがあります:IncrementReset
  • Incrementは入力パラメータがなく、countの値を1増加させます。
  • Resetは32ビット整数をパラメータとして受け取り、countの値を入力パラメータにリセットします。

Increment すべてのユーザーが現在のカウントを1増加させることができます。

Reset

オーナーのみがカウントを特定の数値にリセットできます。実装の詳細はロジックを参照してください。

メッセージ定義

ExecuteMsgには、コントラクトが理解できるさまざまな種類のメッセージを多重化するためにenumを使用できます。serde属性は属性キーをスネークケースおよび小文字に書き換えるため、シリアライズおよびデシリアライズ時にIncrementResetの代わりにincrementresetになります。

ロジック

これはexecute()メソッドで、Rustのパターンマッチングを使用して受信したExecuteMsgを適切な処理ロジックにルーティングします。受信したメッセージに応じてtry_increment()またはtry_reset()の呼び出しにディスパッチします。
まず、キーstateにあるアイテムを更新するためにストレージへの可変参照を取得します。次に、新しい状態でOk結果を返すことでstateのcountを更新します。最後に、Responseと共にOk結果を返すことで、成功を確認してコントラクトの実行を終了します。
resetのロジックはincrementと非常に似ていますが、最初にメッセージの送信者がreset関数の呼び出しを許可されているかどうかを確認します(この場合、コントラクトのオーナーである必要があります)。

QueryMsg

CosmWasmのQueryMsgに関するドキュメントを参照してください。
GetCountクエリメッセージはパラメータがなく、count値を返します。 実装の詳細はロジックを参照してください。

テンプレートコントラクトは1種類のQueryMsgのみをサポートしています: GetCount リクエスト:
レスポンス:

メッセージ定義

コントラクトでデータクエリをサポートするには、QueryMsgのフォーマット(リクエストを表す)とクエリの出力構造(この場合はCountResponse)の両方を定義する必要があります。query()は構造化されたJSONを通じてユーザーに情報を返送するため、レスポンスの形式を公開する必要があります。詳細はJSONスキーマの生成を参照してください。 src/msg.rsに以下を追加します:

ロジック

query()のロジックはexecute()と類似していますが、query()はエンドユーザーがトランザクションを作成せずに呼び出されるため、env引数は省略されます。

ユニットテスト

ユニットテストはチェーンにコードをデプロイする前の最初の保証として実行すべきです。実行が速く、RUST_BACKTRACE=1フラグを使用することで失敗時に有用なバックトレースを提供できます:
ユニットテストの実装src/contract.rsにあります。

コントラクトのビルド

コントラクトを理解しテストしたので、以下のコマンドを実行してコントラクトをビルドできます。これにより、次のステップでコントラクトを最適化する前に予備的なエラーを確認します。
次に、チェーンへのアップロードに向けてコードを準備するためにコントラクトを最適化する必要があります。
本番用Wasmバイトコードの準備の詳細を参照してください。
CosmWasmにはrust-optimizerという小さく一貫したビルド出力を生成できる最適化コンパイラがあります。最も簡単な方法はPublishされたDockerイメージを使用することです。最新のx86バージョンはこちら、最新のARMバージョンはこちらを確認してください。Dockerが実行中の状態で、以下のコマンドを実行してコントラクトコードを/codeにマウントし出力を最適化します($(pwd)の代わりに絶対パスを使用することもできます):
ARM64マシンの場合は、ARM64用にビルドされたDockerイメージを使用してください:
CosmWasmはARM64版コンパイラの使用を推奨していません。Intel/AMD版とは異なるWasmアーティファクトが生成されるためです。リリース/本番環境では、Intel/AMDオプティマイザでビルドされたコントラクトのみの使用が推奨されます。詳細はこちらを参照してください。
コマンド実行時にUnable to update registry `crates-io`エラーが表示される場合があります。コントラクトディレクトリ内のCargo.tomlファイルに以下の行を追加して再実行してください:
詳細は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コンテナが無期限に実行されます。
注意:directory_to_which_you_cloned_cw-templateは絶対パスである必要があります。絶対パスはCosmWasm/cw-counterディレクトリ内でpwdコマンドを実行することで簡単に取得できます。 新しいターミナルを開き、Dockerコンテナに入ってチェーンを初期化します:
後で必要になるjq依存パッケージを追加します:
次に、ローカルチェーンの初期化に進み、testuserというテストユーザーを追加します(プロンプトが表示されたらパスワードとして12345678を使用)。テストユーザーは、テストネットでメッセージの署名に使用する新しいプライベートキーの生成にのみ使用します:
出力
先に進むためにアドレスをメモするか、環境変数としてエクスポートしてください:
Injectiveテストfaucetを使用して、生成したテストアドレスにテストネット資金をリクエストできます。
これでtestuserがInjective Testnetに正常に作成されました。faucetからテストネット資金をリクエストした後、残高も保有しているはずです。 確認するには、Injective Testnet Explorerでアドレスを検索して残高を確認してください。 または、Bank残高のクエリまたはcurlで確認することもできます:

Wasmコントラクトのアップロード

前のステップでコンパイルした.wasmファイルをInjective Testnetにアップロードします。メインネットの手順は異なり、ガバナンスプロポーザルが必要です。
出力:
Injective Testnet Explorerでアドレスを確認し、コード保存から返されたtxhashのトランザクションを探してください。トランザクションタイプはMsgStoreCodeのはずです。 Injective Testnet上のすべての保存コードはCodeで確認できます。
保存したコードを見つけるには複数の方法があります:
  • Injective Explorerのコード一覧でTxHashを探します。最新のものである可能性が高いです。
  • injectivedを使用してトランザクション情報をクエリします。
トランザクションをクエリするにはtxhashを使用してコントラクトがデプロイされたことを確認します。
出力を詳しく見ると、アップロードされたコントラクトのcode_id290であることがわかります:
code_idを環境変数としてエクスポートしましょう。コントラクトのインスタンス化に必要です。このステップはスキップして後で手動で追加することもできますが、IDを記録しておいてください。

JSONスキーマの生成

WasmのinstantiateexecutequeryはJSONを受け取りますが、これだけでは使用に十分な情報ではありません。期待されるメッセージのスキーマをクライアントに公開する必要があります。 JSONスキーマの自動生成を利用するには、スキーマが必要な各データ構造を登録する必要があります。
スキーマは以下のコマンドで生成できます:
これにより、コントラクトが受け取る3つのメッセージタイプ、クエリレスポンスメッセージ、内部Stateに対応する5つのファイルが./schemaに出力されます。 これらのファイルは標準的なJSON Schemaフォーマットで、さまざまなクライアントサイドツールで使用できます。コーデックの自動生成や、定義されたスキーマに対する受信JSONの検証に利用できます。 スキーマを生成し(こちらで確認できます)、次のステップに必要なので内容を理解しておいてください。

コントラクトのインスタンス化

コードがInjective上にアップロードされたので、コントラクトをインスタンス化して対話できるようにします。
CosmWasmでは、コントラクトコードのアップロードとコントラクトのインスタンス化は別々のイベントとして扱われます。
コントラクトをインスタンス化するには、前のステップで取得したcode_idとJSONエンコードされた初期化引数、およびlabel(リストでこのコントラクトを識別するための人間が読める名前)を指定して以下のCLIコマンドを実行します。
出力:
コントラクトアドレスとメタデータは以下の方法で確認できます:

コントラクトのクエリ

先に説明した通り、唯一のQueryMsgはget_countです。
出力:
コントラクトをインスタンス化した時に設定した通り、countは99です。
同じコントラクトをクエリすると、他のユーザーがカウントを増加またはリセットして操作している可能性があるため、異なるレスポンスが返される場合があります。

コントラクトの実行

カウンターを増加させてコントラクトと対話してみましょう。
カウントをクエリすると、以下のようになります:
yes 12345678 | は、自動的にパスフレーズを injectived tx wasm execute の入力にパイプする(渡す)ため、手動で入力する必要はありません。
カウンターをリセットするには:
コントラクトを再度クエリすると、カウントが指定した値にリセットされていることがわかります:

Cosmosメッセージ

カスタムスマートコントラクトロジックの定義に加えて、CosmWasmではコントラクトが基盤となるCosmos SDK機能と対話することもできます。一般的なユースケースの1つは、Cosmos SDKのBankモジュールを使用してコントラクトから指定アドレスにトークンを送信することです。

例:Bank Send

BankMsg::Sendメッセージを使用すると、コントラクトが別のアドレスにトークンを転送できます。報酬の配布やユーザーへの返金など、さまざまなシナリオで役立ちます。
注意: 資金の送信と別のコントラクト上の関数の実行を同時に行いたい場合は、BankMsg::Sendを使用しないでください。代わりに、WasmMsg::Executeを使用して、それぞれのfundsフィールドを設定してください。

メッセージの構築

コントラクトのexecute関数内でBankMsg::Sendメッセージを構築できます。このメッセージでは受信者アドレスと送信額を指定する必要があります。構築方法の例を以下に示します:

スマートコントラクトでの使用

コントラクトでは、ExecuteMsg enumにBank送金機能を処理する新しいバリアントを追加できます:
次に、execute関数にこのメッセージを処理するケースを追加します:

テスト

他のスマートコントラクト関数と同様に、Bank送金機能が期待通りに動作することを確認するためのユニットテストを追加する必要があります。さまざまなトークン量の送信やエラーの適切な処理など、異なるシナリオのテストを含めてください。 ローカルInjectiveチェーンを含む統合テストの実行にはtest-tubeを使用できます。 おめでとうございます!初めてのInjectiveスマートコントラクトを作成して操作し、InjectiveでのCosmWasm開発の始め方を習得しました。コントラクト用のWeb UIを作成するガイドについては「フロントエンドの作成」に進んでください。
最終更新日 2026年4月24日