- Instructions to setup an environment to test IBC Smart Contracts
In this environment setup guide, we will be using the following tools:
This guide doesn't use docker to set up the blockchain nodes, instead, gaiad manager takes care of managing multiple wasmd instances, and the hermes config for us.
Follow the instructions here to install golang.
Follow the instructions here to install rust.
Navigate to a suitable directory and clone the wasmd repo, in this guide we will be using wasmd v0.40.0-rc.1
since at this time, it is the latest version using Cosmos SDK v0.47 and ibc-go v7.
git clone https://github.com/CosmWasm/wasmd.git -b v0.40.0-rc.1
To build wasmd, run the following command:
cd wasmd/
make install
This will create the wasmd
binary in your $HOME/go/bin
directory. To test if the binary is working, run the following command:
wasmd version
You should see the following output:
0.40.0-rc.1
Follow the instructions found in the hermes docs to install hermes via cargo.
To test if the binary is working, run the following command:
hermes version
You should see the following output:
hermes 1.4.1
If you want to install the exact same version used in this guide. You can append --version 1.4.1
to the cargo install command.
Follow the instructions found in the gaiad manager repo.
In this environment, we will have two instances of wasmd running on our local machine and create a connection between them using the hermes relayer.
Go to $HOME/.gm/gm.toml
and enter the following config:
[global]
gaiad_binary="path/to/your/wasmd"
add_to_hermes=true
[global.hermes]
binary="path/to/your/hermes"
[ibc-0]
[ibc-1]
This config will be used to run two chains with the chain-ids ibc-0
and ibc-1
. If you installed hermes through cargo, you can find the binary at $HOME/.cargo/bin/hermes
.
For more customized setups, a more in depth guide about the config can be found here.
To initialize the chains, run the following command:
gm start
If you think that there is any reason you might have a previous gm configuration, then run gm nuke
before running gm start
. Nuke command is used to stop any running nodes, delete any previous configurations (if they exist).
To see if the nodes are running, run the following command:
gm status
You should see the following output if the nodes are running successfully:
NODE PID RPC APP GRPC HOME_DIR
ibc-0 194371 27000 27001 27002 /path/to/.gm/ibc-0
ibc-1 194554 27010 27011 27012 /path/to/.gm/ibc-1
To help with the rest of the guide, we will set the following environment variables:
IBC_0="--home /path/to/your/.gm/ibc-0 --keyring-backend test"
IBC_1="--home /path/to/your/.gm/ibc-1 --keyring-backend test"
NODE_0="--node tcp://localhost:27000"
NODE_1="--node tcp://localhost:27010"
The ports used by the nodes are the RPC ports. We can use these variables to run commands on the nodes. For example, let's view the accounts created by gaiad manager on both the nodes:
wasmd keys list $IBC_0
wasmd keys list $IBC_1
You should see the following output:
- name: validator
type: local
address: wasm1340rxhpezg8pkw58xry006ysppr2xy4zzpma07
pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AjW3R2SQJbJndP+VpemvgJj5IMTdBcKf/d7YvtMMZDKt"}'
mnemonic: ""
- name: wallet
type: local
address: wasm1yddvd050tqaxhyms9udcaa3x26xl0wxj56azt5
pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AkwJloSlaHxA4Ybi3/ixZn0DpbnK5s2BRPjJN/MH1fZz"}'
mnemonic: ""
If at any point you want to stop the nodes and start them again later, you can use the following commands:
gm stop
gm start
After running gm stop
, if you run gm status
, you should see the following output:
NODE PID RPC APP GRPC HOME_DIR
ibc-0 - - - - /path/to/.gm/ibc-0
ibc-1 - - - - /path/to/.gm/ibc-1
To create a connection between the chains, we will use the hermes relayer. To do this, we will first need to create a config file and keys for hermes relayer. Gaiad manager also takes are of this for us:
gm hermes config
gm hermes keys
after this we can create a connection between the chains:
hermes create connection --a-chain ibc-0 --b-chain ibc-1
Now that light clients and connections endpoints are created in both chains. We can now open new channels on top of this connection.
The purpose of this guide is to create a channel between two smart contracts. However, we will first open a standard token transfer channel to test if the connection is working properly.
hermes create channel --a-chain ibc-0 --a-connection connection-0 --a-port transfer --b-port transfer
To see if the channel is created successfully, run:
hermes query channels --show-counterparty --chain ibc-0
and you should see the following output:
ibc-0: transfer/channel-0 --- ibc-1: transfer/channel-0
At this point, you can start relaying packets between the chains by running the following command on a separate terminal:
hermes start
Once you do this, hermes will first relay the pending packets that have not been relayed and then start passively relaying by listening for and acting on packet events. To stop relaying and stopping the chains:
- Stop Hermes by pressing
Ctrl+C
- Stop the chains by running
gm stop
In this example, we will set up a simple smart contract on ibc-0
chain that is able to query all of the smart contracts on ibc-1
chain through IBC. Since channels can only be opened between two smart contracts, we will deploy a query receiver contract on ibc-1
. Then, we will open a channel between this contract and the querier contract of ibc-0
. For this tutorial, we will use the querier and query receiver contracts from this repository.
And to have some contract to query on ibc-1
, we will deploy the template counter contract from here.
These queries are unlike the queries that are made between smart contracts that reside in the same blockchain. A callback transaction will have to be made from the query receiver to the querier. In this model, there is no difference between an ibc query and an ibc transaction. The only difference is that the query receiver will have to send a callback transaction to the querier.
First, we will build the counter contract. A compiled version of this contract is in ./contract_binaries/
directory if you want to skip this step. In an appropriate directory, run the following command:
cargo generate --git https://github.com/CosmWasm/cw-template.git --name counter-contract
Then follow the building instruction in Developing.md
. Build with the rust optimizer docker image to reduce the size of the contract and make the build more reproducible. At the time of writing, the recommended build command is:
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.11
The contract can be found in ./artifacts/
.
Compiled versions of these contracts are in the ./contract_binaries/
directory if you want to skip this step. Now, we will build the query receiver contract. In an appropriate directory, run the following command:
git clone https://github.com/JakeHartnell/cw-ibc-queries.git
cd cw-ibc-queries/
Note that this repository is built as a mono workspace. So building each contract individually is not recommended and is difficult. Even if you tried running the optimizer command from above in each of the contracts found in ./contracts/
, this would fail. You should build all contracts and packages in this repo at once. So we will need to use the workspace optimizer docker image instead. You can learn more about contracts as workspace members here. Run:
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/workspace-optimizer:0.12.13
The contracts can be found in ./artifacts/
.
Now that we have the contracts, we will create the typescript bindings for them. This way, once we deploy them, we can interact with them using typescript. To do this, we will use the ts-codegen tool. First, install the tool:
npm install -g @cosmwasm/ts-codegen
Enter the directory of the contract you want to create bindings for and run:
cargo schema
mkdir ts
cosmwasm-ts-codegen generate \
--plugin client \
--schema ls ./schema \
--out ./ts \
--name INSERT_CONTRACT_NAME \
--no-bundle
This will create the bindings in a ts/
directory. Do this for all three contracts.