Skip to main content

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:
  1. Start Postgres
docker compose up -d --wait
  1. Build the binary and apply database migrations
make build
./bin/relayer migrate --config ./config/local/config.yml
  1. Create a local config file (see the Configuration section).
  2. Create a local keys file (see the Local Signing section).
  3. Start the relayer
make relayer-local
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

FlagDefaultDescription
--config./config/local/config.ymlPath to relayer config file
--ibcv2-relayingtrueEnable or disable the relay dispatcher
--db-migratefalseApply pending database migrations before starting the relayer
SubcommandDescription
migrateApply 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

PortProtocolConfig keyPurpose
3000gRPC + HTTPrelayer_api.addressRelay/Status API and /health
9100HTTP (Prometheus)metrics.prometheus_addressMetrics 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.