IBC Relayer Guide
This guide covers how to set up and operate an IBC relayer for Monolythium using either Hermes (Rust) or the Go Relayer (rly).
Overview
IBC relayers are off-chain processes that forward packets between connected blockchains. They monitor both chains for pending IBC messages and submit relay transactions to deliver them. Relayers are permissionless -- anyone can operate one.
Running a relayer does not earn direct protocol rewards. However, relayers are essential for cross-chain functionality, and the community may fund relayer operators via governance proposals in the future.
Prerequisites
Before setting up a relayer, ensure you have:
- Funded accounts on both Monolythium and the counterparty chain (the relayer pays gas fees on both sides)
- Access to RPC endpoints for both chains (either your own full node or a public RPC)
- Hermes (Rust, recommended) or Go Relayer (
rly) installed - Sufficient disk space for chain state queries and caching
| Requirement | Hermes | Go Relayer (rly) |
|---|---|---|
| Language | Rust | Go 1.21+ |
| Install | cargo install | go install |
| Config format | TOML | YAML |
| Recommended for | Production | Quick setup |
Hermes Setup
Hermes is the recommended relayer for production deployments.
Installation
cargo install ibc-relayer-cli --bin hermes --locked
Verify the installation:
hermes version
Configuration
Create a configuration file at ~/.hermes/config.toml. Below is a minimal configuration for relaying between Monolythium testnet and a counterparty chain:
[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 = 100
clear_on_start = true
tx_confirmation = false
[[chains]]
id = "mono_6940-1"
type = "CosmosSdk"
rpc_addr = "https://rpc.testnet.mononodes.xyz"
grpc_addr = "https://grpc.testnet.mononodes.xyz"
event_source = { mode = "push", url = "wss://rpc.testnet.mononodes.xyz/websocket", batch_delay = "200ms" }
account_prefix = "mono"
key_name = "monolythium-relayer"
address_type = { derivation = "ethermint", proto_type = { pk_type = "/ethermint.crypto.v1.ethsecp256k1.PubKey" } }
store_prefix = "ibc"
default_gas = 400000
max_gas = 1000000
gas_price = { price = 20000000000, denom = "alyth" }
gas_multiplier = 1.2
max_msg_num = 30
max_tx_size = 180000
clock_drift = "5s"
max_block_time = "30s"
trusting_period = "7days"
trust_threshold = { numerator = "1", denominator = "3" }
[[chains]]
id = "<counterparty-chain-id>"
type = "CosmosSdk"
rpc_addr = "<counterparty-rpc>"
grpc_addr = "<counterparty-grpc>"
event_source = { mode = "push", url = "<counterparty-websocket>", batch_delay = "200ms" }
account_prefix = "<counterparty-prefix>"
key_name = "counterparty-relayer"
store_prefix = "ibc"
default_gas = 300000
max_gas = 800000
gas_price = { price = 0.025, denom = "<counterparty-denom>" }
gas_multiplier = 1.2
trusting_period = "7days"
trust_threshold = { numerator = "1", denominator = "3" }
The address_type must use the ethermint derivation for Monolythium. Standard Cosmos derivation will generate incorrect addresses.
Add Keys
Import your relayer key for each chain:
# Monolythium key
hermes keys add --chain mono_6940-1 --mnemonic-file /path/to/mono-mnemonic.txt
# Counterparty chain key
hermes keys add --chain <counterparty-chain-id> --mnemonic-file /path/to/counterparty-mnemonic.txt
Verify key balances:
hermes keys balance --chain mono_6940-1
hermes keys balance --chain <counterparty-chain-id>
Create Client, Connection, and Channel
If no IBC path exists yet between the two chains, create one:
# Create a light client on each chain
hermes create client --host-chain mono_6940-1 --reference-chain <counterparty-chain-id>
hermes create client --host-chain <counterparty-chain-id> --reference-chain mono_6940-1
# Create a connection
hermes create connection --a-chain mono_6940-1 --b-chain <counterparty-chain-id>
# Create a transfer channel (ICS-20)
hermes create channel --a-chain mono_6940-1 --a-connection connection-0 --a-port transfer --b-port transfer
Start the Relayer
hermes start
For production, run Hermes as a systemd service:
sudo tee /etc/systemd/system/hermes.service > /dev/null <<EOF
[Unit]
Description=Hermes IBC Relayer
After=network.target
[Service]
User=hermes
ExecStart=/usr/local/bin/hermes start
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now hermes
Go Relayer (rly) Setup
The Go Relayer (rly) is an alternative with a simpler setup process.
Installation
go install github.com/cosmos/relayer/v2@latest
Initialize and Configure
rly config init
Add chain configurations:
rly chains add --file mono_6940-1.json monolythium
rly chains add --file counterparty.json counterparty
Example chain config (mono_6940-1.json):
{
"type": "cosmos",
"value": {
"key-directory": "/home/relayer/.relayer/keys",
"key": "monolythium-relayer",
"chain-id": "mono_6940-1",
"rpc-addr": "https://rpc.testnet.mononodes.xyz",
"account-prefix": "mono",
"keyring-backend": "test",
"gas-adjustment": 1.2,
"gas-prices": "20000000000alyth",
"min-gas-amount": 0,
"max-gas-amount": 1000000,
"debug": false,
"timeout": "20s",
"block-timeout": "",
"output-format": "json",
"sign-mode": "direct",
"extra-codecs": ["ethermint"]
}
}
Add Keys and Link
# Restore keys from mnemonic
rly keys restore monolythium monolythium-relayer "your mnemonic words here"
rly keys restore counterparty counterparty-relayer "your mnemonic words here"
# Add a path between the two chains
rly paths new mono_6940-1 <counterparty-chain-id> mono-counterparty
# Create clients, connection, and channel
rly tx link mono-counterparty
Start the Relayer
rly start mono-counterparty
Monitoring
Check Relay Status
# Hermes
hermes query packet pending --chain mono_6940-1 --port transfer --channel channel-0
# Go Relayer
rly query unrelayed-packets mono-counterparty
rly query unrelayed-acks mono-counterparty
Balance Monitoring
The relayer pays gas on both chains for every packet it relays. Monitor your balances regularly to avoid running out of funds:
# Hermes
hermes keys balance --chain mono_6940-1
hermes keys balance --chain <counterparty-chain-id>
# Go Relayer
rly query balance monolythium
rly query balance counterparty
If your relayer account runs out of funds, packets will stop being relayed. Set up balance alerts to ensure you top up before the balance reaches zero.
Logging
Both relayers produce structured logs that can be monitored:
# Hermes systemd logs
journalctl -u hermes -f
# Go Relayer (if running as systemd service)
journalctl -u rly -f
IBC Channels
Active Channels
| Network | Channel | Counterparty | Port | Status |
|---|---|---|---|---|
| Sprintnet | channel-0 | Provider channel-578 | transfer | Active |
| Testnet | TBD | TBD | transfer | Pending |
| Mainnet | TBD | TBD | transfer | Pending (activates at block 500K) |
New IBC channels will be added to this table as they are established. Check the monolythium/networks repository for the latest channel information.
Frequently Asked Questions
Do relayers earn rewards?
There are no direct protocol rewards for relayers at this time. Relaying is a public good for the network. The community may choose to fund relayer operators through governance proposals.
How much does it cost to run a relayer?
The relayer pays gas fees on both chains for every packet it relays. Costs depend on packet volume and gas prices on each chain. For low-traffic channels, costs are minimal. Monitor your balances and budget accordingly.
Can I relay for mainnet?
IBC on mainnet activates at block 500,000. Before that block height, there are no IBC packets to relay. Once activated, anyone can set up a relayer for mainnet channels.
What happens if my relayer goes offline?
Packets queue up and wait for any relayer to forward them. Since relaying is permissionless, other relayers on the path can pick up pending packets. There is no penalty for downtime, but unrelayed packets will be delayed.
Further Reading
- IBC Integration -- Protocol-level IBC architecture and precompile details
- Networks -- Network parameters and endpoints