Documentation Index
Fetch the complete documentation index at: https://docs.cosmos.network/llms.txt
Use this file to discover all available pages before exploring further.
Overview
This page covers the configuration and operation of the IBC v2 Relayer. For more information on the IBC v2 Relayer, see the IBC v2 Relayer overview or the IBC v2 Relayer repository.
About
The relayer delivers IBC packets between connected chains. The relayer is request-driven: it does not watch for new packets automatically. A client submits a source transaction hash; the relayer reads IBC events from that transaction, fetches attestation proofs from the Proof API, and submits the relay transaction to the destination chain.
The relayer has three components:
- gRPC API server — accepts relay requests and status queries; also serves
GET /health on the same port
- Postgres database — persists packet state; migrations must be applied before the relayer starts
- Relay dispatcher — polls the database and submits RecvPacket / Ack / Timeout transactions
Configuration
The relayer is configured via a YAML file. Below is the config used in the Cosmos ↔ EVM Interoperability Tutorial, derived from ibc/relayer-config.yml.tmpl. It shows the relayer configuration between a Cosmos and Besu chain:
postgres:
hostname: postgres
port: "5432"
database: relayer
signing:
keys_path: "/home/nonroot/config/local/keys.json"
relayer_api:
address: "0.0.0.0:3000" # gRPC + HTTP health on same port
metrics:
prometheus_address: "0.0.0.0:9100"
ibcv2_proof_api:
grpc_address: "proof-api:9090"
grpc_tls_enabled: false
chains:
cosmos:
chain_name: cosmos
chain_id: "cosmos-1"
type: cosmos
environment: testnet
cosmos:
rpc: "http://cosmos:26657"
grpc: "cosmos:9090"
address_prefix: "cosmos"
ibcv2_tx_fee_denom: "uatom"
ibcv2_tx_fee_amount: 20000 # fixed fee per relay tx; use gas_price instead for dynamic
supported_bridges:
- ibcv2
ibcv2:
counterparty_chains:
"attestations-0": "32382" # client ID on cosmos-1 → besu chain ID
besu:
chain_name: besu
chain_id: "32382"
type: evm
environment: testnet
evm:
rpc: "http://besu:8545"
contracts:
ics_26_router_address: "<ICS26_ROUTER_ADDR>"
ics_20_transfer_address: "0x0000000000000000000000000000000000000000"
supported_bridges:
- ibcv2
ibcv2:
finality_offset: 0
counterparty_chains:
"client-0": "cosmos-1" # client ID on besu → cosmos chain ID
counterparty_chains: It is important to note this field. It maps each IBC client ID on a chain to the chain ID it tracks. The relayer only relays packets for clients listed here, and any unlisted client ID is ignored.
For advanced configuration options including batch sizing, concurrency, gas alert thresholds, and EVM gas multipliers, see the Configuration Reference in the relayer README.
Local signing keys
Set signing.keys_path to a JSON file keyed by chain ID. The format follows config/local/ibcv2keys.json.example in the ibc-relayer repository:
{
"32382": {
"name": "Besu",
"address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
"private_key": "0xac0974bec..."
},
"cosmos-1": {
"name": "Cosmos",
"address": "cosmos1...",
"private_key": "3b4f8a..."
}
}
- EVM: hex-encoded ECDSA private key — use any standard wallet or key generation tool
- Cosmos: hex-encoded secp256k1 private key — create with your chain binary, then export:
<chain-binary> keys add relayer --keyring-backend test
<chain-binary> keys export relayer --keyring-backend test --unarmored-hex --unsafe
The exported hex is what goes in keys.json. The address on each chain must be funded with enough balance to pay transaction fees.
For production key management, see Remote Signing in the relayer README.
Getting started
To start the relayer, clone the ibc-relayer repository and follow the instructions below for local development. Refer to the relayer README for full setup details.
Prerequisites
- Running Proof API
- Postgres with migrations applied (see Database migrations)
- RPC endpoints for both chains
- A funded signing key on each chain
Starting the relayer
For local development, the full startup sequence from the ibc-relayer repo is:
- Start Postgres
docker compose up -d --wait
- Build the binary and apply database migrations
make build
./bin/relayer migrate --config ./config/local/config.yml
-
Create a local config file (see the Configuration section).
-
Create a local keys file (see the Local Signing section).
-
Start the relayer
The relayer will start:
- gRPC API server on the address configured in
relayer_api.address
- Prometheus metrics server on the configured address
- Relay dispatcher polling for new transfers
To check the health of the relayer:
curl http://localhost:9000/health
CLI flags and subcommands
| Flag | Default | Description |
|---|
--config | ./config/local/config.yml | Path to relayer config file |
--ibcv2-relaying | true | Enable or disable the relay dispatcher |
--db-migrate | false | Apply pending database migrations before starting the relayer |
| Subcommand | Description |
|---|
migrate | Apply pending database migrations and exit (does not start the relayer) |
Database migrations
Migrations are compiled into the relayer binary and applied by the relayer itself. There are two modes:
One-shot (recommended for production — apply migrations and exit, then start the relayer separately):
./bin/relayer migrate --config /path/to/config.yml
Combined startup (convenient for local development — apply migrations then continue into normal startup):
./bin/relayer --db-migrate --config /path/to/config.yml
Each migration runs in its own transaction. If a migration fails, the relayer aborts startup rather than serve against an unverified schema.
The standalone ghcr.io/cosmos/ibc-relayer-migrate Docker image is no longer published. Deployments that previously used it must switch to invoking migrate on the main ibc-relayer image:# before
docker run --rm ghcr.io/cosmos/ibc-relayer-migrate:<version> up
# after
docker run --rm ghcr.io/cosmos/ibc-relayer:<version> migrate --config /path/to/config.yml
For full details on database migrations, see the Database Migrations section of the relayer README.
Triggering a relay
These commands require both chains to be connected (IBC clients created) and the relayer running.
Example command to submit a transaction for relaying:
grpcurl -plaintext \
-d '{"tx_hash":"<SOURCE_TX_HASH>","chain_id":"<SOURCE_CHAIN_ID>"}' \
localhost:3000 skip.relayer.RelayerApiService/Relay
Example command to check relay status:
grpcurl -plaintext \
-d '{"tx_hash":"<SOURCE_TX_HASH>","chain_id":"<SOURCE_CHAIN_ID>"}' \
localhost:3000 skip.relayer.RelayerApiService/Status
The response contains a packetStatuses array:
{
"packetStatuses": [
{
"state": "TRANSFER_STATE_COMPLETE",
"sequenceNumber": "1",
"sourceClientId": "attestations-0",
"sendTx": {
"txHash": "<SOURCE_TX_HASH>",
"chainId": "cosmos-1"
},
"recvTx": {
"txHash": "0x81d004...",
"chainId": "32382"
}
}
]
}
state will be one of TRANSFER_STATE_UNKNOWN, TRANSFER_STATE_PENDING, TRANSFER_STATE_COMPLETE, or TRANSFER_STATE_FAILED. ackTx and timeoutTx are also present once those legs complete.
Ports
| Port | Protocol | Config key | Purpose |
|---|
| 3000 | gRPC + HTTP | relayer_api.address | Relay/Status API and /health |
| 9100 | HTTP (Prometheus) | metrics.prometheus_address | Metrics scrape endpoint |
Both ports are configurable in the YAML config. The gRPC API and HTTP health endpoint share a single port via multiplexing.
Observability
The relayer exposes Prometheus metrics at the address set in metrics.prometheus_address. Scrape it with any standard Prometheus-compatible collector:
curl http://localhost:9100/metrics
For the full list of exposed metrics, see the Observability section of the relayer README.