はじめに
本記事は、Cosmos上のスマートコントラクトプラットフォーム『CosmWasm(コズムワズム)』を用いた開発の入門編第1弾です。
内容としては、Cosmos内のDeFi用スマートコントラクトのためのブロックチェーン『Neutron(ニュートロン)』のテストネットにて、CW20という規格のトークンを発行・送金する操作まで解説しています。
もし何かわからないことがあれば、Cosmos JapanのDiscordにて質問をしていただければ幸いです。親切な人が教えてくれるはずです!
用語の解説
実際の操作方法を解説する前に、本記事を読む上で知っておくべき用語を軽く共有しておきます。
既に知っている方は読み飛ばしていただいて問題ありません。
用語 | 解説 |
---|---|
CosmWasm | Cosmosエコシステム用に作られたスマートコントラクトプラットフォーム(ライブラリ)です。 CosmWasmを使用することで、Cosmos SDKを使用して構築されたブロックチェーンに対して、簡単にスマートコントラクトを作成することが可能です。 公式ドキュメント:https://docs.cosmwasm.com/docs/ |
Neutron | Cosmos SDKで構築されたクロスチェーンのスマートコントラクトプラットフォームです。Cosmosエコシステム上におけるDeFiアプリケーションの展開に特化したブロックチェーンとなっています。 |
CW20 | トークンの規格です。CW20はCosmWasm環境で動作する、Cosmos SDKベースのブロックチェーンで使用されるカスタムトークンの規格です。 |
全体の流れ
記事の流れとしては、以下の6ステップに沿って進んでいきます。
①開発環境と利用するツールの準備
必要な開発言語の環境の用意や実際にNeutronのチェーンと接続するために必要なツールのインストールを行います。
②Neutronに接続してみよう
CLIを用いて、自分のPC上でNeutronのアカウントを作成し、テストネット上でfaucetからテスト用のトークンを受け取った後に、そのテストネット上での残高をCLIから確認します。
NeutronのネイティブトークンであるNTRNを他のアカウントに送金するなど、基本的なコマンドも試してみます。
③トークンのためのコントラクトを用意する
Neutron上でCW20トークンを発行するためのCosmWasmのコントラクトを自分のPCにダウンロードし、Neutronにアップロードできる形にするためにコンパイルを行います。
④コントラクトをアップロード&初期化してみる
コンパイルしたコントラクトをNeutronのテストネットに対してアップロードし、アップロードしたコントラクトを初期化することで、トークンの発行を行います。
⑤発行したCW20トークンを送金する
デプロイしたコントラクトに対してどう関数を実行するのかを学びます。自分が作ったトークンを別のアカウントに送ってみましょう。
⑥おわりに
開発環境と利用するツールの準備
利用できるOSについて
- Ubuntu
- M1,M2チップを利用していないMacOS
Windows環境でDockerを利用して動作するかは未検証です。
チェーンとの接続ができたとしても、用意したCosmWasm用のコードに対して、最適なコンパイルを実行した際に、M 1,M2チップを利用しているMacOSだとコンパイルが完了しなかったり、完了したとしてもチェーンに対してうまくアップロードができなかったりします。これはMac上のDockerを用いてLinux環境を作成してもうまくできないようです。
少し手間がかかりますが、M1,M2チップを利用している環境でも開発を行なってみたい方は、AWS上のLightsailなどでubuntuの仮想環境を立ち上げて実行することをおすすめします。
必要な言語、ツールのインストール
以下のツールをインストールしていきます。
- golang
- jq
- Docker
- neutrond
golangのインストール
version 1.20 現在neutronのmakefileでの指定が1.20です。環境に合わせたものをインストールしてください。また、GoのPathなど、それぞれの環境に適した方法でよしなにお願いします。
jqのインストール
JSONデータを操作するためのコマンドラインツールです。
以下の記事が参考になると思われます。
https://zenn.dev/en2enzo2/articles/e45e6d0aec6c7e
Dockerのインストール
コントラクトのコンパイルを実行する際にDockerを利用しますので、こちらも各環境に合わせてDockerをインストールしておいてください。
以下の記事が参考になると思われます。
https://and-engineer.com/articles/Yb2imhEAACMAhjUx
neutrondのインストール
NeutronのノードとCLIが一緒になっているリポジトリをローカル環境にクローンし、CLIの部分を利用します。任意のディレクトリにて、以下のコマンドを順番に実行し、ローカル環境にneutrondをインストールしましょう。なお、goがうまくインストールされていないと一番最後のコマンドが実行できません。
git clone -b v1.0.4 https://github.com/neutron-org/neutron
cd neutron
make install
以下コマンドを実行してバージョンが表示されれば、インストールが完了しています。
neutrond version
1.0.4
Neutronに接続してみよう
アカウントの作成
以下コマンドを実行することでローカルのPC上にNeutron用のアカウントが生成されます。アカウントの操作を管理するためのパスワードの設定も一緒に行うことになります。
このコマンドの実行結果として、最後に表示されるニーモニックは、今後二度と再表示できないので、安全な場所に保存しておきましょう。
neutrond keys add (好きなアカウント名)
以下のようにコマンドを実行して、アカウントが表示されれば、アカウントの作成は完了しています。
neutrond keys list
Enter keyring passphrase:
- name: hogehoge
type: local
address: neutron197sfunfhoge6lgfmr69hogeukhfuniffjjefnun8
pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AoP+C6pXLt3QMEXuH57e/d/3aBojXxNLvIlFf9mgUIeZ"}'
mnemonic: ""
Faucetの実行
Faucet(フォーセット)とは、暗号資産やトークンを無料で配布するシステムです。今回は、テストネットで使用するトークンを入手するためにFaucetを使用します。
ここで入手するトークンは、後ほど行うコントラクトのデプロイなどに必要なガス代に使用します。先ほど作成したNeutronのアカウントに対し、Faucetを用いてトークンを入金しましょう。
以下より示す手順に従って、Faucetを使用してください。
まずNeutronの公式サイトに行き、一番下のDiscordのリンクをクリックして公式のDiscordに入ります。
Discordへの招待リンクは変更される可能性があるので、公式サイトからの案内を行なっています。
NeutronのDiscordに入れたら、#✅|verify-GB
というチャンネルでアカウント認証をしてください。
アカウント認証が終わったら、公式Discordの#testnet-faucet
チャンネルに入り、faucetのコマンドを実行します。
以下のようにfaucetのコマンドを実行してください。
faucetのコマンドは、一度実行した後、同じアカウントからは24時間経たないと再実行できないため、間違ったアドレスを入力しないように注意が必要です。
$request (自分のアカウントのアドレス)
Faucetの確認
自分の作成したアカウントに対して、ちゃんとテストネットのトークンが配布されているかを、ローカルのCLIから確認しましょう。
以下のコマンドを実行することで、アカウントが持っているトークンの種類とその残高が表示されるようになっています。
neutrond q bank balances (自分のアカウントのアドレス) --node https://rpc-t.neutron.nodestake.top:443 --chain-id pion-1
実行結果は以下のように出力されます。
balances:
- amount: "2000000"
denom: untrn
pagination:
next_key: null
total: "0"
オプションにて、接続するrpcノードと接続するチェーンのIDを指定することで、Neutronのテストネットに接続したいこと、その中のどのrpcノードに対して接続したいかを指定しています。もしうまく表示できない、アクセスできないという場合は他のNeutronテストネットのrpcノードのアドレスを調べて変更することをおすすめします。
NTRNの送金をやってみよう
アカウントがテストネットのNTRNを持っていることがわかったら、別のアカウントに送金してみましょう。
先ほどアカウントを作ったように再度neutrond keys add (好きな名前)を実行して、2つ目のアカウントを作成し、以下のコマンドを使って、そのアドレスに対して、自分でNTRNトークンを送ってみましょう。
neutrond tx bank send (自分の送り元のアドレス) (送り先のアドレス) 100untrn --node https://rpc-t.neutron.nodestake.top:443 --chain-id pion-1 --gas-prices 0.01untrn --gas auto --gas-adjustment 1.3
上記のコマンドでは、100untrnを送っています。Cosmosのネイティブトークンは基本的にdecimalが6になっているので、1000000untrn = 1ntrnとなっています。なので、100untrnは0.0001ntrnを送っていることになります。送金のテストなので、あとでコントラクトをデプロイするガス代を残しておくために少額を送っています。
先ほどの残高を参照した際のオプションに追加して、gas-priceなどのgas関連のオプションが追加されていることがわかります。
残高を参照する際はノードから情報を参照するだけのクエリの実行でしたが、送金はトランザクションを実行させることになります。そのため、送金の際にはガスに関する設定をしてあげる必要が出てきます。
よくあるエラーとして、out of gasというものがありますが、これが表示された場合は、gas-priceのオプションを変更してあげることで解決することが多いです。利用するガスの量を増やしてあげましょう。
トークンのためのコントラクトを用意する
発行したいCW20トークンのコントラクトを用意します。CosmWasmの開発元が用意してくれているCW20のコントラクトを利用します。以下のリポジトリをローカルにクローンして、それらをコンパイルしていきます。
コントラクトのダウンロード
以下のように実行してクローンを行なってください。
git clone -b v1.1.0 https://github.com/CosmWasm/cw-plus.git
cd cw-plus
今回は2023/08/20時点で最新のv1.1.0
を利用していますが、今後Neutronのテストネットで利用するCosmWasmのバージョンがアップデートされると、それに合わせて適宜利用するべきcw-plusのバージョンも上げる必要があるかもしれません。 こちらに関して何か分からないことがあれば、Cosmos JapanのDiscordにて質問をしていただけたらと思います。
コントラクトのコンパイル
以下のDockerのコマンドを実行して、コントラクトのコンパイルを実行します。cw-plusに含まれているcw20以外のコントラクトも一緒にコンパイルするので、少し時間がかかります。
docker run --rm -v "$(pwd)":/code
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/target
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry
cosmwasm/workspace-optimizer:0.13.0
場合によってはスーパーユーザー権限がないとコマンドが実行できない場合もありますので、その場合はsudoを最初につけてコマンドの実行をしてみてください。
ちなみに、こちらのコマンドはM1チップを利用しているMacだと完了しません。
コマンドの実行が終わったら、新しく作成されているartifactsディレクトリの中に、cw20_base.wasm
というファイルが生成されているはずです。
以下のコマンドラインでartifactsディレクトリに入り、ファイルを確認しましょう。lsコマンドを実行することでcw20_base.wasmが生成されていることが確認できます。こちらがNeutronにアップロードすることになるwasmファイルです。
cd artifacts
ls
checksums.txt cw1_subkeys.wasm cw20_base.wasm cw3_fixed_multisig.wasm cw4_group.wasm
checksums_intermediate.txt cw1_whitelist.wasm cw20_ics20.wasm cw3_flex_multisig.wasm cw4_stake.wasm
コントラクトをアップロード&初期化してみる
コントラクトのアップロード
artifactsディレクトリにて、以下のコマンドを実行することで、Neutronのテストネットにwasmファイルをアップロードします。
neutrond tx wasm store cw20_base.wasm --from (自分のアカウントの名前) --node https://rpc-t.neutron.nodestake.top:443 --chain-id pion-1 --gas-prices 0.01untrn --gas auto --gas-adjustment 1.3
コマンドを実行し終わったら、以下のようにtxhashが表示されます。このtxhashをコピーし、mintscan等のブロックエクスプローラーで検索をかけてみましょう。
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 233BD64613B3F9450E08D85112B00FC84C14573660D7F99632FED6871202C2EC
今回の例では、以下のようなページでトランザクションの実行が完了していることが確認できます。
Code Id(赤枠部分)はトークンのデプロイに必要になるので、ご自身でアップロードしたコードのCode Idをいつでも参照できるようにしておいてください。
コントラクトの初期化
初期化する際にコントラクトに渡すパラメータの設定を行います。
以下コマンドのnameに設定しているのが発行するトークンの名前、symbolがシンボル、initial_balancesは初期発行時にどのアドレスにどれだけの量を発行するのかを指定した配列を渡すことになります。
INIT=$(jq -n '{"name":"(自分の好きな名前)","symbol":"(トークンのシンボル)","decimals":6,"initial_balances":[{address:"(自分のアドレス)",amount:"10000000"}]}')
以下のコマンドを実行することで先ほどアップロードしたコントラクトのコードを使って、コントラクトの初期化を行なっています。Code Idを指定して、初期化するコントラクト自体の名前や、管理者が誰なのかもオプションとして指定してあげてください。
neutrond tx wasm instantiate (先ほどのCode Id) "$INIT" --label "(トークンの名前)" --admin (自分のアカウントのアドレス) --from (自分のアカウント名) --node https://rpc-t.neutron.nodestake.top:443 --chain-id pion-1 --gas-prices 0.1untrn --gas auto --gas-adjustment 1.3
コマンドを実行し終わったら、再度以下のようにtxhashが表示されます。
このtxhashをコピーし、ブロックエクスプローラーで検索をかけてみましょう。
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 3880BE3D7432F19926CC263AEF7F585502092EA37F17854C1E9AAB7E18E66AD7
以下のようにInstantiates
の中の”contract_address”
より、今回初期化を行なったコントラクトアドレスが参照できるようになっています。トークンの送金の際にこちらを利用しますので、いつでも参照できるようにしておきましょう。
これでトークンの発行自体は完了です。
発行したCW20トークンを送金する
ここまでの操作でトークンの発行はできました。最後に送金を試していきましょう!
CW20トークンの残高を参照する
送金をする前に、自分のアカウントが発行したトークンをどれくらい所有しているかを確認します。以下のように実行すると、Balance
の部分に発行したトークンの残高が表示されます。
BALANCE=$(jq -n '{"balance":{"address": "(トークンを発行した自分のアカウントのアドレス)"}}')
neutrond query wasm contract-state smart (初期化したトークンのコントラクトのアドレス) "$BALANCE" --node https://rpc-t.neutron.nodestake.top:443 --chain-id pion-1
data:
balance: "10000000"
コントラクトにクエリを実行したりトランザクションに渡す際に利用するパラメータはjsonの形式で管理することになります。
CW20トークンを送金する
次にトークンの送金を試してみます。
以下のコマンドを実行しましょう。
EXECUTE=$(jq -n '{"transfer":{"recipient": "(受け取るアカウントのアドレス)", "amount": "1000"}}')
neutrond tx wasm execute (初期化したトークンのコントラクトのアドレス) "$EXECUTE" --from (自分のアカウント名) --node https://rpc-t.neutron.nodestake.top:443 --chain-id pion-1 --gas-prices 0.1untrn --gas auto --gas-adjustment 1.3
正常に実行できた場合は、送金が完了しています。
再度、残高を参照することで、送金した額だけ発行したトークンが減っていることがわかるはずです。送金先のアドレスの残高も参照してみてください。
※ もし以下のようなエラーが出現した場合は、--gas auto
を--gas 20000
など適当な数値に変えて実行してみてください。 Error: rpc error: code = Unknown desc = rpc error: code = Unknown desc = failed to execute message; message index: 0: Overflow: Cannot Sub with 0 and 1000: execute wasm contract failed [CosmWasm/wasmd@v0.31.0/x/wasm/keeper/keeper.go:376] With gas wanted: '0' and gas used: '110355' : unknown request
おわりに
お疲れ様でした。以上がCosmosのスマートコントラクトにおけるアップロードと初期化から、コントラクト自体に対するクエリとトランザクションの実行になります。
実際にCW20のコントラクトには、他にも実行できるクエリや、transfer以外にもburnや、別のコントラクトに対して送金を実行するsendなどの関数も用意されています。
実際のcw20-baseのコントラクトやその依存先であるcw20のコントラクトのメッセージを眺めながら他のコマンドも実行してみると、一歩進んだ理解ができるようになるはずです!