IBC Relayers

Relaying on Namada

This document describes how to operate a relayer for the Inter-Blockchain Communication (IBC) protocol with Namada. This documentation covers being able to create connections through IBC as well as setting up local chains of Namada for testing purposes.

This document covers essential steps for using IBC with Namada:

  1. Configure Hermes
  2. Install Hermes
  3. Setting up the relayer
  4. Start the relayer
  5. Set up local Namada chains

The below is intended for those that wish to relay 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 running on both the destination and the source chain 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 chains for this purpose.

Configure Hermes

Hermes is an IBC relayer to relay IBC packets between chains. Namada uses a fork of Hermes supporting Namada chains (opens in a new tab).

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 = 'shielded-expedition.88f17d1d14'  # set your chain ID
type = 'Namada'
rpc_addr = 'http://127.0.0.1:26657'  # 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'
trusting_period = '4752s'
gas_price = { price = 0.0001, denom = 'tnam1qxvg64psvhwumv3mwrrjfcz0h3t3274hwggyzcee' }  # the price isn't used for now, the denom should be a raw token address retrieve denom by namadaw address find --alias "naan"
rpc_timeout = '30s'
memo_prefix = ''
 
[chains.packet_filter]
policy = 'allow'
list = [
  ['transfer', '<channel-id>'], #channel-id leading to the counterparty channel you want to configure IBC
]
 
[[chains]]
id = 'axelar-testnet-lisbon-3'
type = 'CosmosSdk'
rpc_addr = 'http://127.0.0.1:28657' # RPC of the counterparty chain
grpc_addr = 'http://127.0.0.1:28090' # gRPC of the counterparty chain
event_source = { mode = 'push', url = 'ws://127.0.0.1:28657/websocket', batch_delay = '500ms' }
rpc_timeout = '10s'
account_prefix = 'axelar'
key_name = 'relayer'
store_prefix = 'ibc'
default_gas = 5000000
max_gas = 15000000
gas_price = { price = 0.001, denom = 'uaxl' }
gas_multiplier = 1.1
max_msg_num = 30
max_tx_size = 800000
clock_drift = '5s'
max_block_time = '30s'
trusting_period = '5days' # should be less than unbonding period of the counterparty channel
ccv_consumer_chain = false
sequential_batch_tx = false
memo_prefix = ''
 
[chains.trust_threshold]
numerator = "1"
denominator = "3"
 
[chains.packet_filter]
 policy = 'allow'
 list = [
   ['transfer', '<channel-id>'], # channel id of the Namada side
 ]
 
[chains.packet_filter.min_fees]
 
[chains.address_type]
derivation = "cosmos"
 
# Add all channels you want to process

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.grpc_addr currently is not used in Namada but needs to be configured for other Cosmos chains
  • 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.
  • chains.event_source specifies the URL of the chain's websocket. This must be the same as the rpc_address for Hermes to work properly.
  • chains.gas_price.denom specifies the token that the relayer pays for IBC transactions. chains.gas_price.price isn't used for now in Namada.
  • trusting_period specifies the maximum period before which the client can not expire. This should be not more than unbonding time in the particular chain.

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

Export environment variables

The relaying user will need to save certain environment variables. These are:

export CHAIN_A_ID="<replace-with-chain-a-id>"
export CHAIN_B_ID="<replace-with-chain-b-id>"
export HERMES_CONFIG="<replace-with-hermes-config-path>"

Install Hermes

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

From binaries

One 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.7.4-namada-beta7"
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

For some systems, /usr/local/bin is a protected directory. In this case, you may need to run the above command with sudo. I.e

sudo tar -xvzf /tmp/hermes.tar.gz -C /usr/local/bin

This is also true for the command cp ./target/release/hermes /usr/local/bin/ below (see the comment).

From source

export TAG="v1.7.4-namada-beta7"
 
git clone https://github.com/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

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

Setting up the relayer

Create the relayer account

On each chain, there must be a relayer account. The alias should be the same as chains.key_name in the config. On a Namada chain, this can be done by running

namadaw gen --alias relayer

This will generate a key for the relayer account. The key will be stored in the wallet.toml that is found in the base directory of the node, inside the chain-id folder. For example, if the chain-id is shielded-expedition.88f17d1d14, the wallet.toml will be found in $HOME/.local/share/namada/shielded-expedition.88f17d1d14/wallet.toml (on a ubuntu machine where base-dir has not been set up properly).

The relayer account should have some balance to pay the fee of transactions. Before creating an IBC channel or relaying an IBC packet, you need to transfer the fee token to the relayer account.

Add the relayer key to Hermes

To sign each transaction, the relayer's key should be added to Hermes with keys add command in advance. It requires the wallet.toml which should have the key of chains.key_name. Once the key has been added, Hermes doesn't need the wallet anymore.

hermes --config $HERMES_CONFIG keys add --chain $CHAIN_ID --key-file $WALLET_PATH
hermes --config $HERMES_CONFIG keys add --chain $CHAIN_ID --mnemonic-file $SEED_PATH

Hermes will store the key in ~/.hermes/keys/${CHAIN_ID} as default. You can specify the directory by setting chains.key_store_folder in the config file.

If you want to use an encrypted key with a password, you have to set an environment variable NAMADA_WALLET_PASSWORD_FILE for the password file or NAMADA_WALLET_PASSWORD to avoid entering the password for each transaction submission.

It is now possible to set up the client.

Verify configuration files

After editing config.toml and adding wallet keys, it’s time to test the configurations and ensure the system is healthy. Run the following:

hermes health-check
hermes config validate

If everything was set up correctly, you should see output like:

SUCCESS performed health check for all chains in the config
SUCCESS "configuration is valid"

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 955 has been created on Chain A shielded-expedition.88f17d1d14, and a channel with ID 460 has been created on Chain B axelar-testnet-lisbon-3. You will need the channel IDs for a transfer over IBC. It means that you have to specify channel-955 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-460 as a channel ID for a transfer from Chain B to Chain A.

Remember the ClientId for each of the chains, we will need them on the next step: 07-tendermint-2996 for shielded-expedition.88f17d1d14 and 07-tendermint-884 for axelar-testnet-lisbon-3

export CLIENT_A_ID="<replace-with-client-a-id>"
export CLIENT_B_ID="<replace-with-client-b-id>"
SUCCESS Channel {
    ordering: Unordered,
    a_side: ChannelSide {
        chain: BaseChainHandle {
            chain_id: ChainId {
                id: "shielded-expedition.88f17d1d14",
                version: 0,
            },
            runtime_sender: Sender { .. },
        },
        client_id: ClientId(
            "07-tendermint-2996",
        ),
        connection_id: ConnectionId(
            "connection-1479",
        ),
        port_id: PortId(
            "transfer",
        ),
        channel_id: Some(
            ChannelId(
                "channel-955",
            ),
        ),
        version: None,
    },
    b_side: ChannelSide {
        chain: BaseChainHandle {
            chain_id: ChainId {
                id: "axelar-testnet-lisbon-3",
                version: 3,
            },
            runtime_sender: Sender { .. },
        },
        client_id: ClientId(
            "07-tendermint-884",
        ),
        connection_id: ConnectionId(
            "connection-679",
        ),
        port_id: PortId(
            "transfer",
        ),
        channel_id: Some(
            ChannelId(
                "channel-460",
            ),
        ),
        version: None,
    },
    connection_delay: 0ns,
}

Change Hermes configuration

Now when the channels are created we need to update the Hermes configuration

...
[chains.packet_filter]
policy = 'allow'
list = [
  ['transfer', '<channel-id>'], #channel-id leading to the counterparty channel you want to use for IBC
]
...

Update IBC clients

In order to have IBC channels running they need active IBC clients they rely on. When clients are not in use they tend to expire and to prevent this they are required to be updated manually.

The "update channel" command (below) update the actual state of the client in the particular chain.

hermes update client --host-chain $CHAIN_A_ID --client $CLIENT_A_ID
hermes update client --host-chain $CHAIN_B_ID --client $CLIENT_B_ID

It is recommended to perform this manual update or use specific scripts to automate it. Otherwise, you risk your clients will be expired. The restoration is possible only from the Governance of the specific chain.

Start the relayer

Once you run Hermes, it monitors chains 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).

After the sync, you can create the channel and start Hermes as explained 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

Transferring assets over IBC

It is now possible to transfer assets between the two chains.

Set up local Namada chains using the Hermes script

The script setup-namada will set up two chains 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.

First, you will need to export some environment variables:

export NAMADA_DIR="<path-to-namada-source-directory>"
export TAG="v1.7.4-namada-beta7"
git clone https://github.com/heliaxdev/hermes.git
git checkout $TAG # The branch is the same as our Hermes
cd hermes
./scripts/setup-namada $NAMADA_DIR

In this case, the user doesn't have to wait for sync. If the relayer account on each instance has enough balance, the user can create a channel and start Hermes immediately as explained above. The user finds these chain IDs of the chains 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