IBC on Namada

Using IBC with Namada

This document describes using the inter-blockchain communication (IBC) protocol with Namada. This documentation covers being able to create connections through IBC as well as setting up local instances of Namada for testing purposes.

⚠️

Warning This feature is currently in development. Expect the unexpected. As of v0.22.0, there are some known issues with using ARM devices with this relayer.

This document will cover three essential steps for using IBC with Namada:

  1. Setup Hermes
  2. Setup nodes for Namada instances
  3. Transferring assets over IBC

The below is intended for those that wish to conduct IBC message transfers between two Namada chains. There is of course the capability to do this between any two IBC compatible chains (such as a Cosmos chain). In this case, it is necessary to have a node of both the destination and the source chain running in order to make any package transfers. Below, we discuss first how to enable this connection between two pre-existing chains by Hermes, and second, setting up two Namada local instances or joining two pre-existing Namada instances for this purpose.

Setup Hermes

Hermes is an IBC relayer to relay IBC packets between chains (instances). We have our fork of Hermes supporting Namada instances (opens in a new tab). Before packet relay, we need the following steps to configure and start Hermes.

  1. Make Hermes config file
  2. Create IBC client/connection/channel between instances
  3. Run Hermes

Make Hermes config file

One essential piece of the puzzle is to create a config.toml file that describes what connections will be set up that the relayer will be responsible for.

export HERMES_CONFIG="<choose path for hermes config>/config.toml"
touch $HERMES_CONFIG

If you don't specify the file path, ~/.hermes/config.toml is read as default.

You can find an example of the config file below. Essentially, you change only the chain IDs, the RPC addresses, and the key names in the config file for Namada. If you don't have nodes, please set up nodes manually or through our scripts.

Example: config.toml
[global]
log_level = 'info'
 
[mode]
 
[mode.clients]
enabled = true
refresh = true
misbehaviour = true
 
[mode.connections]
enabled = false
 
[mode.channels]
enabled = false
 
[mode.packets]
enabled = true
clear_interval = 10
clear_on_start = false
tx_confirmation = true
 
[telemetry]
enabled = false
host = '127.0.0.1'
port = 3001
 
[[chains]]
id = 'namada-test.0a4c6786dbda39f786'  # set your chain ID
type = 'namada'
rpc_addr = 'http://127.0.0.1:27657'  # set the IP and the port of the chain
grpc_addr = 'http://127.0.0.1:9090'  # not used for now
event_source = { mode = 'push', url = 'ws://127.0.0.1:27657/websocket', batch_delay = '500ms' }  # set the IP and the port of the chain
account_prefix = ''  # not used
key_name = 'relayer'  # The key is an account name you made
store_prefix = 'ibc'
gas_price = { price = 0.001, denom = 'nam' }  # not used for now
 
[[chains]]
id = 'namada-test.647287156defa8728c'
type = 'namada'
rpc_addr = 'http://127.0.0.1:28657'
grpc_addr = 'http://127.0.0.1:9090'
event_source = { mode = 'push', url = 'ws://127.0.0.1:28657/websocket', batch_delay = '500ms' }
account_prefix = ''
key_name = 'relayer'
store_prefix = 'ibc'
gas_price = { price = 0.001, denom = 'nam' }

The path to the config file, which is saved in the variable $HERMES_CONFIG will be useful later.

đź§©

Interpreting the toml

Each chain configuration is specified under the [[chains]] object. These are the pieces of this puzzle you want to keep your đź‘€ on:

  • chains.id is the name of the chain
  • chains.rpc_address specifies the port that the channel is communicating through, and will be the argument for the ledger_address of Namada when interacting with the ledger (will become clearer later)
    • Make sure to change the IP address to the IP address of your local machine that is running this node!
  • chains.key_name specifies the key of the signer who signs a transaction from the relayer. The key should be generated before starting the relayer.

Create IBC client/connection/channel between instances

Hermes CLI has commands to create them. Before the creation, a node of each instance should be running.

Install Hermes

Before conducting any IBC operations, we download Heliax's fork Hermes binary or build it from source.

From binaries

We can download the latest binary release from our releases page (opens in a new tab) by choosing the appropriate architecture.

E.g.

export TAG="v1.6.0-namada-beta2"
export ARCH="x86_64-unknown-linux-gnu" # or "aarch64-apple-darwin"
curl -Lo /tmp/hermes.tar.gz https://github.com/heliaxdev/hermes/releases/download/${TAG}/hermes-${TAG}-${ARCH}.tar.gz
tar -xvzf /tmp/hermes.tar.gz -C /usr/local/bin
From source
export TAG="v1.6.0-namada-beta2"
 
git clone [email protected]:heliaxdev/hermes.git
git checkout $TAG
cd hermes
cargo build --release --bin hermes
export HERMES=$(pwd) # if needed

Check the binary:

./target/release/hermes --version

It is recommended to now add hermes to $PATH such that it is callable without any pre-fixes. For ubuntu users, this can be achieved by

cp ./target/release/hermes /usr/local/bin/

Create IBC channel

The "create channel" command (below) creates not only the IBC channel but also the necessary IBC client connection.

hermes --config $HERMES_CONFIG \
  create channel \
  --a-chain $CHAIN_A_ID \
  --b-chain $CHAIN_B_ID \
  --a-port transfer \
  --b-port transfer \
  --new-client-connection --yes

Note that the above CHAIN_IDs will depend on your own setup, so do check this for yourself!

When the creation has been completed, you can see the channel IDs. For example, the following text shows that a channel with ID 7 has been created on Chain A namada-test.0a4c6786dbda39f786, and a channel with ID 12 has been created on Chain B namada-test.647287156defa8728c. You will need the channel IDs for a transfer over IBC. It means that you have to specify channel-7 as a channel ID (The prefix channel- is always required) for a transfer from Chain A to Chain B. Also, you have to specify channel-12 as a channel ID for a transfer from Chain B to Chain A.

SUCCESS Channel {
    ordering: Unordered,
    a_side: ChannelSide {
        chain: BaseChainHandle {
            chain_id: ChainId {
                id: "namada-test.0a4c6786dbda39f786",
                version: 0,
            },
            runtime_sender: Sender { .. },
        },
        client_id: ClientId(
            "07-tendermint-0",
        ),
        connection_id: ConnectionId(
            "connection-3",
        ),
        port_id: PortId(
            "transfer",
        ),
        channel_id: Some(
            ChannelId(
                "channel-7",
            ),
        ),
        version: None,
    },
    b_side: ChannelSide {
        chain: BaseChainHandle {
            chain_id: ChainId {
                id: "namada-test.647287156defa8728c",
                version: 0,
            },
            runtime_sender: Sender { .. },
        },
        client_id: ClientId(
            "07-tendermint-1",
        ),
        connection_id: ConnectionId(
            "connection-2",
        ),
        port_id: PortId(
            "transfer",
        ),
        channel_id: Some(
            ChannelId(
                "channel-12",
            ),
        ),
        version: None,
    },
    connection_delay: 0ns,
}

Run Hermes

Once you run Hermes, it monitors instances via the nodes and relays packets according to monitored events.

hermes --config $HERMES_CONFIG start

You can see more details of Hermes at the official document (opens in a new tab).

Setup nodes for Namada instances

We need a node for each instance to be monitored by Hermes. In this document, we will set up two local nodes for two instances. But, of course, the node doesn't have to be on the same machine as Hermes.

We will explain for two cases:

  • Set up nodes to join existing Namada instances
  • Set up local Namada instances for testing purposes

Before running the following scripts, you have to build Namada and wasm.

git clone [email protected]:anoma/namada.git
cd namada
git checkout v0.22.0
make build-release
make build-wasm-scripts
export NAMADA_DIR=$(pwd) # if needed

You can use scripts in our Hermes branch (opens in a new tab) to setup these nodes automatically.

Set up nodes to join existing Namada instances

The script join-namada will set up two nodes for two instances, copy necessary files for Hermes, and make an account for Hermes on each ledger. Also, it will make a Hermes' config file config_for_namada.toml in the hermes directory.

The script requires the Namada directory path and chain IDs.

git clone [email protected]:heliaxdev/hermes.git
git checkout $TAG # The branch is the same as our Hermes
cd hermes
./scripts/join-namada $NAMADA_DIR $CHAIN_ID_A $CHAIN_ID_B

You need to wait to sync each node with the corresponding instance. And, you have to transfer NAM token to the relayer account (the script will make an alias relayer) from the faucet or others on each instance because the fee for IBC transactions should be charged. For example, the following command transfers NAM from the faucet for namada-a instance which is created by the script. You can refer to here about --base-dir and --node.

${NAMADA_DIR}/target/release/namadac transfer \
  --base-dir ${HERMES}/data/namada-a/.namada \
  --source faucet \
  --target relayer \
  --token nam \
  --amount 1000 \
  --signing-keys relayer \
  --node 127.0.0.1:26657

After the sync, you can create the channel and start Hermes as we explain above.

# create a channel
hermes --config $HERMES_CONFIG \
  create channel \
  --a-chain $CHAIN_A_ID \
  --b-chain $CHAIN_B_ID \
  --a-port transfer \
  --b-port transfer \
  --new-client-connection --yes
 
# Run Hermes
hermes --config $HERMES_CONFIG start

Each node data and configuration files are in ${HERMES}/data/namada-*/.namada.

In order to close any ledgers setup by the script, one can run

killall namadan

Set up local Namada instances

The script setup-namada will set up two instances with one validator node, copy necessary files for Hermes, and make an account for Hermes on each ledger. Also, it will make a Hermes' config file config_for_namada.toml in the hermes directory.

git clone [email protected]:heliaxdev/hermes.git
git checkout $TAG # The branch is the same as our Hermes
cd hermes
./scripts/setup-namada $NAMADA_DIR $CHAIN_ID_A $CHAIN_ID_B

In this case, we don't have to wait for sync. If the relayer account on each instance has enough balance, you can create a channel and start Hermes immediately as we explain above. You find these chain IDs of the instances in the config file config_for_namada.toml. One can run grep "id" ${HERMES_CONFIG}.

# create a channel
hermes --config $HERMES_CONFIG \
  create channel \
  --a-chain $CHAIN_A_ID \
  --b-chain $CHAIN_B_ID \
  --a-port transfer \
  --b-port transfer \
  --new-client-connection --yes
 
# Run Hermes
hermes --config $HERMES_CONFIG start

Each node data and configuration files are in hermes/data/namada-*/.namada.

In order to close any ledgers setup by the script, one can run

killall namadan

Transferring assets over IBC

This will make transfers across chains by Namada CLI. This assumes that a channel has been created and Hermes is running with the proper config.

In order to do this by Namada's ibc-transfer command, we will need to know the base-dir and node of each instance (and other transfer parameters). base-dir is the base directory of each node. If you have used the script, the directory is ${HERMES}/data/namada-*/.namada. node is rpc_addr in the relevant Hermes' config file. You can run

grep "rpc_addr" ${HERMES_CONFIG}

to find the address.

đź’ˇ

For the local node ONLY

To find your ledger address for Chain A, you can run the following command

export BASE_DIR_A = "${HERMES}/data/namada-a/.namada"
export LEDGER_ADDRESS_A = "$(grep "rpc_address" ${BASE_DIR_A}/${CHAIN_A_ID}/setup/validator-0/.namada/${CHAIN_A_ID}/config.toml)"

The channel ID for this chain will depend on the order in which one created the channel. Since we have only opened one channel, the channel-id is channel-0, but as more are created, these increase by index incremented by 1. Please refer to here.

Assuming that the open channel is channel-0, you can save it in an environment variable by running

export CHANNEL_ID = "channel-0"

The inter-blockchain transfers from Chain A can be achieved by

namadac --base-dir ${BASE_DIR_A}
    ibc-transfer \
        --amount ${AMOUNT} \
        --source ${SOURCE_ALIAS} \
        --receiver ${RECEIVER_RAW_ADDRESS} \
        --token ${TOKEN_ALIAS} \
        --channel-id ${CHANNEL_ID} \
        --node ${LEDGER_ADDRESS_A}

Where the above variables in ${VARIABLE} must be substituted with appropriate values. The raw address of the receiver can be found by namadaw --base-dir ${BASE_DIR_B} address find --alias ${RECEIVER}.

E.g.

namadac --base-dir ${BASE_DIR_A}
    ibc-transfer \
    --amount 100 \
    --source albert \
    --receiver atest1d9khqw36g56nqwpkgezrvvejg3p5xv2z8y6nydehxprygvp5g4znj3phxfpyv3pcgcunws2x0wwa76 \
    --token nam \
    --channel-id channel-0 \
    --node 127.0.0.1:27657