Rolling Across Blockchains: Exploring IBC Transfers Between Two Rollups

Deepak
Vitwit
Published in
7 min readMar 26, 2024

This article is a part of a series Unlocking the power of rollups using rollkit and Avail DA

please refer the above article which is a prerequisite for this article

Whats is IBC

The Inter-Blockchain Communication Protocol (IBC) serves as a foundational protocol facilitating authentication and data transport between distinct blockchains. With IBC, developers gain access to a permissionless framework for securely relaying data packets across blockchains. This protocol effectively tackles a common challenge in the realm of public blockchains: enabling seamless communication between different chains.

In this article we will be doing a IBC transfer between two rollup chains

In the article mentioned above, We have made a Cosmos app chain into a rollup and submitted the data to Avail. In this article we will be running two rollup chains and making a IBC transfer through go-relayer.

Note: we are using gm chains (the chains generated by scaffolding tool here) as a rollup chains

Once you have done with the setup and make sure that gm chain is up and running as a rollup chain, follow these steps to make an IBC transfer between them.

The following software versions has been used in making this video

  • rust — v1.74.0
  • go-1.21.5

Run the following scripts to run two different rollup chains

Note: these scripts are used while writing this article, you can modify the scripts accordingly.

script-1: init-testnet1.sh

#!/bin/sh
# set variables for the chain
VALIDATOR_NAME=t1validator-1
CHAIN_ID=testnet-1
KEY_NAME=t1-key-1
KEY_2_NAME=t1-key-2
CHAINFLAG="--chain-id ${CHAIN_ID}"
TOKEN_AMOUNT="10000000000000000000000000stake"
STAKING_AMOUNT="1000000000stake"
MNEMONIC_1="----paste your mnemonic here----"
MNEMONIC_2="----paste your mnemonic here----"
# network. The default port is 26657.
DA_BLOCK_HEIGHT=$(curl http://localhost:8000/v1/latest_block | jq -r '.latest_block')
gmd tendermint unsafe-reset-all
gmd init $VALIDATOR_NAME --chain-id $CHAIN_ID
echo $MNEMONIC_1 | gmd keys add $KEY_NAME --recover --keyring-backend=test
echo $MNEMONIC_2 | gmd keys add $KEY_2_NAME --recover --keyring-backend=test
# add these as genesis accounts
gmd genesis add-genesis-account $KEY_NAME $TOKEN_AMOUNT --keyring-backend test
gmd genesis add-genesis-account $KEY_2_NAME $TOKEN_AMOUNT --keyring-backend test
sed -i 's/"max_expected_time_per_block": "30000000000"/"max_expected_time_per_block": "75000000000"/' ~/.gm/config/genesis.json
# set the staking amounts in the genesis transaction
gmd genesis gentx $KEY_NAME $STAKING_AMOUNT --chain-id $CHAIN_ID --keyring-backend test
# collect genesis transactions
gmd genesis collect-gentxs
# copy centralized sequencer address into genesis.json
# Note: validator and sequencer are used interchangeably here
ADDRESS=$(jq -r '.address' ~/.gm/config/priv_validator_key.json)
PUB_KEY=$(jq -r '.pub_key' ~/.gm/config/priv_validator_key.json)
jq --argjson pubKey "$PUB_KEY" '.consensus["validators"]=[{"address": "'$ADDRESS'", "pub_key": $pubKey, "power": "1000", "name": "Rollkit Sequencer"}]' ~/.gm/config/genesis.json > temp.json && mv temp.json ~/.gm/config/genesis.json
echo "DA_BLOCK_HEIGHT=$DA_BLOCK_HEIGHT" >> restart-local.sh
echo "gmd start --rollkit.aggregator true --rollkit.da_address=":26650" --rollkit.da_start_height \$DA_BLOCK_HEIGHT --rpc.laddr tcp://127.0.0.1:36657 --p2p.laddr \"0.0.0.0:36656\" --minimum-gas-prices="0.025stake"" >> restart-local.sh
# start the chain
gmd start --rollkit.aggregator true --rollkit.da_address=":26650" --rollkit.da_start_height $DA_BLOCK_HEIGHT --rpc.laddr tcp://127.0.0.1:36657 --p2p.laddr "0.0.0.0:36656" --minimum-gas-prices="0.0stake"

script-2: init-testnet2.sh

#!/bin/sh
# set variables for the chain
VALIDATOR_NAME=t2validator-1
CHAIN_ID=testnet-2
KEY_NAME=t2-key-1
KEY_2_NAME=t2-key-2
CHAINFLAG="--chain-id ${CHAIN_ID}"
TOKEN_AMOUNT="10000000000000000000000000stake"
STAKING_AMOUNT="1000000000stake"
MNEMONIC_1="----paste your mnemonic here----"
MNEMONIC_2="----paste your mnemonic here----"
DA_BLOCK_HEIGHT=$(curl http://localhost:8000/v1/latest_block | jq -r '.latest_block')
# echo variables for the chain
echo -e "\n Your DA_BLOCK_HEIGHT is $DA_BLOCK_HEIGHT \n"
gmd tendermint unsafe-reset-all --home /home/vitwit/.gm1
# initialize the validator with the chain ID you set
gmd init $VALIDATOR_NAME --chain-id $CHAIN_ID --home /home/vitwit/.gm1
# # add keys for key 1 and key 2 to keyring-backend test
echo $MNEMONIC_1 | gmd keys add $KEY_NAME --recover --keyring-backend=test --home /home/vitwit/.gm1
echo $MNEMONIC_2 | gmd keys add $KEY_2_NAME --recover --keyring-backend=test --home /home/vitwit/.gm1
# # add these as genesis accounts
gmd genesis add-genesis-account $KEY_NAME $TOKEN_AMOUNT --keyring-backend test --home /home/vitwit/.gm1
gmd genesis add-genesis-account $KEY_2_NAME $TOKEN_AMOUNT --keyring-backend test --home /home/vitwit/.gm1
echo "----------update config--------------"
GRPC="9092"
sed -i 's#localhost:9090#localhost:'${GRPC}'#g' ~/.gm1/config/app.toml
sed -i 's/laddr = \"tcp:\/\/127.0.0.1:26657\"/laddr = \"tcp:\/\/0.0.0.0:16657\"/' ~/.gm1/config/config.toml
sed -i 's/laddr = \"tcp:\/\/127.0.0.1:26656\"/laddr = \"tcp:\/\/0.0.0.0:16656\"/' ~/.gm1/config/config.toml
sed -i 's/"max_expected_time_per_block": "30000000000"/"max_expected_time_per_block": "75000000000"/' ~/.gm1/config/genesis.json
# # set the staking amounts in the genesis transaction
gmd genesis gentx $KEY_NAME $STAKING_AMOUNT --chain-id $CHAIN_ID --keyring-backend test --home /home/vitwit/.gm1
# collect genesis transactions
gmd genesis collect-gentxs --home /home/vitwit/.gm1
ADDRESS=$(jq -r '.address' ~/.gm1/config/priv_validator_key.json)
PUB_KEY=$(jq -r '.pub_key' ~/.gm1/config/priv_validator_key.json)
jq --argjson pubKey "$PUB_KEY" '.consensus["validators"]=[{"address": "'$ADDRESS'", "pub_key": $pubKey, "power": "1000", "name": "Rollkit Sequencer"}]' ~/.gm1/config/genesis.json > temp.json && mv temp.json ~/.gm1/config/genesis.json
echo "DA_BLOCK_HEIGHT=$DA_BLOCK_HEIGHT" >> restart2-local.sh
echo "gmd start --rollkit.aggregator true --rollkit.da_address=":26650" --rollkit.da_start_height \$DA_BLOCK_HEIGHT --rpc.laddr tcp://127.0.0.1:36657 --p2p.laddr \"0.0.0.0:36656\" --minimum-gas-prices="0.025stake"" >> restart-local.sh
# start the chain
gmd start --home /home/vitwit/.gm1 --rollkit.aggregator true --rollkit.da_address=":26650" --rollkit.da_start_height $DA_BLOCK_HEIGHT --rpc.laddr tcp://127.0.0.1:16657 --p2p.laddr "0.0.0.0:16656" --minimum-gas-prices="0.0stake"

Run the chain-1 by the following command

bash init-testnet1.sh

you can view the following logs once the chain is up and running

Run the chain-2 by the following command

bash init-testnet2.sh

you can view the following logs once the chain is up and running

We are supposed to establish a relayer conncetion between the two rollup chains. To do so, we will be using go-relayer. The setup and documentation for go-relayer is available here

Once the installation is done, you can use the below script as an example setup.

create a file for the relayer-script

touch relayer-script.sh

copy and paste the following script

#!/bin/bash
RELAYER_PATH="/home/vitwit/.relayer"
CONFIG_FILE="$RELAYER_PATH/config/config.yaml"
CHAIN_ID_1="testnet-1"
KEY_1="t1-key-1"
RPC_1="http://localhost:36657"
PREFIX_1="gm"
GAS_PRICES_1="1000stake"
MNEMONIC_1="----paste your mnemonic here----"
CHAIN_ID_2="testnet-2"
KEY_2="t2-key-1"
RPC_2="http://localhost:16657"
PREFIX_2="gm"
GAS_PRICES_2="1000stake"
MNEMONIC_2="----paste your mnemonic here----"
# Remove existing config.yaml
rm -f "$CONFIG_FILE"
# Run rly config init to generate a new config.yaml
rly config init
# Define the new chains information
NEW_CHAINS=$(cat <<EOF
chains:
$CHAIN_ID_1:
type: cosmos
value:
key-directory: $RELAYER_PATH/keys/$CHAIN_ID_1
key: $KEY_1
chain-id: $CHAIN_ID_1
rpc-addr: $RPC_1
account-prefix: $PREFIX_1
keyring-backend: test
gas-adjustment: 2
gas-prices: $GAS_PRICES_1
min-gas-amount: 0
max-gas-amount: 1000000000
debug: false
timeout: 20s
block-timeout: ""
output-format: json
sign-mode: direct
extra-codecs: []
coin-type: 118
signing-algorithm: ""
broadcast-mode: batch
min-loop-duration: 0s
extension-options: []
feegrants: null
$CHAIN_ID_2:
type: cosmos
value:
key-directory: $RELAYER_PATH/keys/$CHAIN_ID_2
key: $KEY_2
chain-id: $CHAIN_ID_2
rpc-addr: $RPC_2
account-prefix: $PREFIX_2
keyring-backend: test
gas-adjustment: 2
gas-prices: $GAS_PRICES_2
min-gas-amount: 0
max-gas-amount: 100000000
debug: false
timeout: 20s
block-timeout: ""
output-format: json
sign-mode: direct
extra-codecs: []
coin-type: 118
signing-algorithm: ""
broadcast-mode: batch
min-loop-duration: 0s
extension-options: []
feegrants: null
paths:
EOF
)
# Update the chains section in the configuration file
sed '/^chains:/,/^[a-zA-Z]*:/d' "$CONFIG_FILE" > "$CONFIG_FILE.tmp"
echo "$NEW_CHAINS" >> "$CONFIG_FILE.tmp"
mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
echo "Configuration file updated successfully."
rly keys restore $CHAIN_ID_1 $KEY_1 "$MNEMONIC_1"
rly keys restore $CHAIN_ID_2 $KEY_2 "$MNEMONIC_2"
rly paths new testnet-1 testnet-2 transfer-path
rly tx link transfer-path --src-port transfer --dst-port transfer
rly start

Do not forgot to change the chain-id, mnemonic, key-name etc.. as per your chain configurations accordingly

You can find following logs once the relayer connection has been established

Relayer

Now, we are good to go for making a transfer between two IBC rollups

Let us query the balance of the key to make sure we had enough stake with the below command

gmd q bank balances gm1huqkhe8nyvqumq62flfan2uzl57gg7w98m78kd  --node tcp://localhost:16657

You can view the following log which shows the account balance

With the following command, IBC transfer can be done from testnet1(sender) to testnet2 (receiver)

gmd tx ibc-transfer transfer transfer channel-0 gm1huqkhe8nyvqumq62flfan2uzl57gg7w98m78kd 100000stake --from t1-key-1 --keyring-backend test --node tcp://localhost:36657 --chain-id testnet-1 -y

You can view the following log once after executing the following command

code-0 indicates that the transfer has been successful

We can query the tx using the following command

gmd q tx <tx-hash>

Let us check the balance on receiver rollup chain

We can check the received amount of 10000 denom which got credited into the receiver rollup chain

With this, we have successfully made an IBC transfer between two rollups 🎉

--

--