From 46590ca54d57ec59f416754df1b12ffb8404ef84 Mon Sep 17 00:00:00 2001 From: chatton Date: Fri, 28 Nov 2025 11:52:59 +0000 Subject: [PATCH 1/2] wip --- scripts/e2e/Makefile | 95 ++++++++++++++++++++ scripts/e2e/chain-entry.sh | 46 ++++++++++ scripts/e2e/docker-compose.yml | 125 +++++++++++++++++++++++++++ scripts/e2e/hermes-entry.sh | 107 +++++++++++++++++++++++ scripts/e2e/migrate-stayoncomet.sh | 111 ++++++++++++++++++++++++ scripts/e2e/relayer.mnemonic | 1 + scripts/e2e/update-clients-simple.sh | 50 +++++++++++ 7 files changed, 535 insertions(+) create mode 100644 scripts/e2e/Makefile create mode 100644 scripts/e2e/chain-entry.sh create mode 100644 scripts/e2e/docker-compose.yml create mode 100644 scripts/e2e/hermes-entry.sh create mode 100755 scripts/e2e/migrate-stayoncomet.sh create mode 100644 scripts/e2e/relayer.mnemonic create mode 100755 scripts/e2e/update-clients-simple.sh diff --git a/scripts/e2e/Makefile b/scripts/e2e/Makefile new file mode 100644 index 00000000..5653004f --- /dev/null +++ b/scripts/e2e/Makefile @@ -0,0 +1,95 @@ +SHELL := /bin/bash + +COMPOSE := docker compose -f docker-compose.yml + +# Default ports exposed in compose +RPC_A ?= 26657 +GRPC_A ?= 9090 +RPC_B ?= 26657 +GRPC_B ?= 9090 +RPC_C ?= 26657 +GRPC_C ?= 9090 + +# Migration window and height (set MIG when running backfill) +WINDOW ?= 30 +MIG ?= + +.PHONY: help +help: + @echo "E2E orchestration targets:" + @echo " make up - start chains (wait for height >= 1)" + @echo " make down - stop containers" + @echo " make ps - list containers" + @echo " make logs-a/b/c - tail chain logs" + @echo " make hermes-start - start Hermes only (after chains ready)" + @echo " make ibc-setup - fund relayer and create A<->B, A<->C channels" + @echo " make migrate - submit StayOnComet migration on A (WINDOW=$(WINDOW))" + @echo " make backfill MIG= [WINDOW=$(WINDOW)] - run client backfill" + @echo " make clean - down and remove volumes" + +.PHONY: up +up: + $(COMPOSE) up -d gm-a-val-0 gm-a-val-1 gm-a-val-2 gm-b-val-0 gm-c-val-0 hermes + @echo "[wait] waiting for chains to reach height >= 1" + @bash -c 'set -e; \ + parse_height() { \ + url="$$1"; \ + if command -v jq >/dev/null 2>&1; then \ + curl -s "$$url" | jq -r .result.sync_info.latest_block_height 2>/dev/null || true; \ + else \ + curl -s "$$url" | sed -n "s/.*\"latest_block_height\":\"\([0-9]\+\)\".*/\1/p"; \ + fi; \ + }; \ + endpoints=("http://localhost:26657/status" "http://localhost:27657/status" "http://localhost:28657/status"); \ + for ep in "$${endpoints[@]}"; do \ + echo " waiting on $$ep"; \ + ok=0; \ + for i in $$(seq 1 120); do \ + h=$$(parse_height $$ep); \ + if [ -n "$$h" ] && [ "$$h" -ge 1 ] 2>/dev/null; then \ + echo " ok height=$$h"; ok=1; break; \ + fi; \ + sleep 1; \ + done; \ + if [ $$ok -ne 1 ]; then echo " timeout waiting for $$ep" >&2; exit 1; fi; \ + done' + @echo "[up] Hermes started (gated by chain healthchecks)" + +.PHONY: down +down: + $(COMPOSE) down + +.PHONY: ps +ps: + $(COMPOSE) ps + +.PHONY: logs-a logs-b logs-c +logs-a: + docker logs -f gm-a-val-0 +logs-b: + docker logs -f gm-b-val-0 +logs-c: + docker logs -f gm-c-val-0 + +.PHONY: init + +.PHONY: hermes-start +hermes-start: + $(COMPOSE) up -d hermes + +.PHONY: ibc-setup +ibc-setup: + bash ./ibc-setup.sh + +.PHONY: migrate +migrate: + WINDOW=$(WINDOW) bash ./migrate-stayoncomet.sh $(WINDOW) + +.PHONY: backfill +backfill: + @if [ -z "$(MIG)" ]; then echo "Set MIG= (e.g., MIG=120)" >&2; exit 2; fi + python3 ./update_ibc_clients_backfill.py gm-a gm-b gm-c --migration-height $(MIG) --window $(WINDOW) + +.PHONY: clean +clean: + $(COMPOSE) down -v diff --git a/scripts/e2e/chain-entry.sh b/scripts/e2e/chain-entry.sh new file mode 100644 index 00000000..b7bd6027 --- /dev/null +++ b/scripts/e2e/chain-entry.sh @@ -0,0 +1,46 @@ +#!/bin/sh +set -e + +CHAIN_ID="${CHAIN_ID:-gm-a}" +RPC_PORT="${RPC_PORT:-26657}" +GRPC_PORT="${GRPC_PORT:-9090}" +DENOM="stake" +HOME_DIR="/home/gm/.gm" +MNEMONIC_FILE="/scripts/relayer.mnemonic" + +echo "[chain] init $CHAIN_ID (rpc=$RPC_PORT grpc=$GRPC_PORT)" + +# initialize chain +gmd init "$HOSTNAME" --chain-id "$CHAIN_ID" --home "$HOME_DIR" + +# create faucet key +gmd keys add faucet --keyring-backend test --home "$HOME_DIR" >/dev/null 2>&1 +FAUCET_ADDR=$(gmd keys show faucet -a --keyring-backend test --home "$HOME_DIR") + +# add faucet as genesis account +gmd genesis add-genesis-account "$FAUCET_ADDR" 100000000000"$DENOM" --home "$HOME_DIR" + +# recover relayer key from shared mnemonic +gmd keys add relayer --recover --keyring-backend test --home "$HOME_DIR" < "$MNEMONIC_FILE" >/dev/null 2>&1 +RELAYER_ADDR=$(gmd keys show relayer -a --keyring-backend test --home "$HOME_DIR") + +# add relayer as genesis account +gmd genesis add-genesis-account "$RELAYER_ADDR" 100000000000"$DENOM" --home "$HOME_DIR" + +# create genesis transaction +gmd genesis gentx faucet 10000000000"$DENOM" --moniker "$HOSTNAME" --chain-id "$CHAIN_ID" --keyring-backend test --home "$HOME_DIR" +gmd genesis collect-gentxs --home "$HOME_DIR" + +# configure app +sed -i "s/^minimum-gas-prices.*/minimum-gas-prices = \"0.0$DENOM\"/" "$HOME_DIR/config/app.toml" +sed -i "s/^indexer.*/indexer = \"kv\"/" "$HOME_DIR/config/config.toml" +sed -i "s|127.0.0.1:26657|0.0.0.0:26657|" "$HOME_DIR/config/config.toml" +sed -i "s|127.0.0.1:9090|0.0.0.0:9090|" "$HOME_DIR/config/app.toml" + +# reduce voting period for testing (30 seconds instead of 48 hours) +sed -i "s/\"voting_period\": \"172800s\"/\"voting_period\": \"30s\"/" "$HOME_DIR/config/genesis.json" +sed -i "s/\"expedited_voting_period\": \"86400s\"/\"expedited_voting_period\": \"15s\"/" "$HOME_DIR/config/genesis.json" +sed -i "s/\"max_deposit_period\": \"172800s\"/\"max_deposit_period\": \"30s\"/" "$HOME_DIR/config/genesis.json" + +echo "[chain] starting $CHAIN_ID" +exec gmd start --home "$HOME_DIR" --rpc.laddr tcp://0.0.0.0:"$RPC_PORT" --grpc.address 0.0.0.0:"$GRPC_PORT" diff --git a/scripts/e2e/docker-compose.yml b/scripts/e2e/docker-compose.yml new file mode 100644 index 00000000..b3e584f1 --- /dev/null +++ b/scripts/e2e/docker-compose.yml @@ -0,0 +1,125 @@ +version: "3.8" + +services: + gm-a-val-0: + image: cosmos-gm:test + container_name: gm-a-val-0 + entrypoint: ["/bin/sh", "/scripts/chain-entry.sh"] + volumes: + - gm_a_val0:/home/gm/.gm + - ./:/scripts:ro + networks: [gmnet] + user: "0:0" + ports: + - "26657:26657" # RPC + - "9090:9090" # gRPC + environment: + - CHAIN_ID=gm-a + - RPC_PORT=26657 + - GRPC_PORT=9090 + healthcheck: + test: ["CMD-SHELL", "gmd status 2>/dev/null | tr -d '\n' | grep -q '\"latest_block_height\":\"[1-9]' "] + interval: 2s + timeout: 2s + retries: 60 + + gm-a-val-1: + image: cosmos-gm:test + container_name: gm-a-val-1 + entrypoint: ["/bin/sh", "/scripts/chain-entry.sh"] + volumes: + - gm_a_val1:/home/gm/.gm + - ./:/scripts:ro + networks: [gmnet] + user: "0:0" + environment: + - CHAIN_ID=gm-a + - RPC_PORT=26657 + - GRPC_PORT=9090 + + gm-a-val-2: + image: cosmos-gm:test + container_name: gm-a-val-2 + entrypoint: ["/bin/sh", "/scripts/chain-entry.sh"] + volumes: + - gm_a_val2:/home/gm/.gm + - ./:/scripts:ro + networks: [gmnet] + user: "0:0" + environment: + - CHAIN_ID=gm-a + - RPC_PORT=26657 + - GRPC_PORT=9090 + + gm-b-val-0: + image: cosmos-gm:test + container_name: gm-b-val-0 + entrypoint: ["/bin/sh", "/scripts/chain-entry.sh"] + volumes: + - gm_b_val0:/home/gm/.gm + - ./:/scripts:ro + networks: [gmnet] + user: "0:0" + ports: + - "27657:26657" + - "9190:9090" + environment: + - CHAIN_ID=gm-b + - RPC_PORT=26657 + - GRPC_PORT=9090 + healthcheck: + test: ["CMD-SHELL", "gmd status 2>/dev/null | tr -d '\n' | grep -q '\"latest_block_height\":\"[1-9]' "] + interval: 2s + timeout: 2s + retries: 60 + + gm-c-val-0: + image: cosmos-gm:test + container_name: gm-c-val-0 + entrypoint: ["/bin/sh", "/scripts/chain-entry.sh"] + volumes: + - gm_c_val0:/home/gm/.gm + - ./:/scripts:ro + networks: [gmnet] + user: "0:0" + ports: + - "28657:26657" + - "9290:9090" + environment: + - CHAIN_ID=gm-c + - RPC_PORT=26657 + - GRPC_PORT=9090 + healthcheck: + test: ["CMD-SHELL", "gmd status 2>/dev/null | tr -d '\n' | grep -q '\"latest_block_height\":\"[1-9]' "] + interval: 2s + timeout: 2s + retries: 60 + + hermes: + image: ghcr.io/informalsystems/hermes:1.13.1 + container_name: hermes + entrypoint: ["/bin/sh", "/scripts/hermes-entry.sh"] + volumes: + - hermes_home:/home/hermes/.hermes + - ./:/scripts:ro + networks: [gmnet] + depends_on: + gm-a-val-0: + condition: service_healthy + gm-b-val-0: + condition: service_healthy + gm-c-val-0: + condition: service_healthy + restart: unless-stopped + user: "0:0" + +networks: + gmnet: {} + +volumes: + gm_a_val0: {} + gm_a_val1: {} + gm_a_val2: {} + gm_b_val0: {} + gm_c_val0: {} + hermes_home: {} diff --git a/scripts/e2e/hermes-entry.sh b/scripts/e2e/hermes-entry.sh new file mode 100644 index 00000000..8f9186c7 --- /dev/null +++ b/scripts/e2e/hermes-entry.sh @@ -0,0 +1,107 @@ +#!/bin/sh +set -e + +CONFIG=/home/hermes/.hermes/config.toml +MNEMONIC=/scripts/relayer.mnemonic + +# Ensure config dir exists and is writable +mkdir -p /home/hermes/.hermes || true + +# Point Hermes to the generated config for all subsequent CLI calls +export HERMES_HOME=/home/hermes/.hermes +export HERMES_CONFIG="$CONFIG" + +cat > "$CONFIG" </dev/null | grep -q "$name"; then + echo " [$ch] key $name already present" + continue + fi + echo " [$ch] importing $name from mnemonic" + hermes --config "$CONFIG" keys add --chain "$ch" --mnemonic-file "$MNEMONIC" --key-name "$name" +done + +# Create connections + channels (idempotent) +echo "[hermes] creating IBC connections/channels" +# A <-> B +hermes --config "$CONFIG" create connection --a-chain gm-a --b-chain gm-b || true +hermes --config "$CONFIG" create channel \ + --a-chain gm-a --b-chain gm-b \ + --a-port transfer --b-port transfer \ + --order unordered --channel-version ics20-1 \ + --new-client-connection || true +# A <-> C +hermes --config "$CONFIG" create connection --a-chain gm-a --b-chain gm-c || true +hermes --config "$CONFIG" create channel \ + --a-chain gm-a --b-chain gm-c \ + --a-port transfer --b-port transfer \ + --order unordered --channel-version ics20-1 \ + --new-client-connection || true + +echo "[hermes] starting relayer" +exec hermes --config "$CONFIG" start diff --git a/scripts/e2e/migrate-stayoncomet.sh b/scripts/e2e/migrate-stayoncomet.sh new file mode 100755 index 00000000..3b53221a --- /dev/null +++ b/scripts/e2e/migrate-stayoncomet.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash +set -euo pipefail + +# migrate to single validator (validator-0) while staying on CometBFT +# hardcoded for gm-a-val-0 container + +NODE="gm-a-val-0" +CHAIN_ID="gm-a" +KEY="faucet" +HOME_DIR="/home/gm/.gm" +VALIDATORS=("gm-a-val-0" "gm-a-val-1" "gm-a-val-2") + +echo "[migrate-stayoncomet] getting current height..." +CURRENT_HEIGHT=$(docker exec "$NODE" sh -lc "gmd status --home $HOME_DIR" | grep -o '"latest_block_height":"[0-9]*"' | grep -o '[0-9]*') +MIGRATE_AT=$((CURRENT_HEIGHT + 30)) + +echo "[migrate-stayoncomet] current height: $CURRENT_HEIGHT, migration at: $MIGRATE_AT" + +echo "[migrate-stayoncomet] getting validator-0 pubkey..." +VALIDATOR_PUBKEY=$(docker exec "$NODE" sh -lc "gmd query staking validators --home $HOME_DIR --output json" | grep -A 2 '"consensus_pubkey"' | grep '"value"' | head -1 | sed 's/.*"value": "\(.*\)".*/\1/') + +echo "[migrate-stayoncomet] validator pubkey: $VALIDATOR_PUBKEY" + +echo "[migrate-stayoncomet] using hardcoded gov module address..." +GOV_ADDRESS="gm10d07y265gmmuvt4z0w9aw880jnsr700j5nsal6" + +echo "[migrate-stayoncomet] gov address: $GOV_ADDRESS" + +echo "[migrate-stayoncomet] creating proposal json..." +cat > /tmp/proposal.json < /tmp/submit_output.json 2>&1 + +SUBMIT_OUTPUT=$(cat /tmp/submit_output.json) +echo "[migrate-stayoncomet] submit output: $SUBMIT_OUTPUT" + +TXHASH=$(echo "$SUBMIT_OUTPUT" | grep -o '"txhash":"[^"]*"' | cut -d'"' -f4) +echo "[migrate-stayoncomet] tx hash: $TXHASH" + +echo "[migrate-stayoncomet] waiting for tx to be committed..." +sleep 5 + +echo "[migrate-stayoncomet] querying proposal ID from transaction..." +PROPOSAL_ID=$(docker exec "$NODE" sh -lc "gmd query tx $TXHASH --home $HOME_DIR --output json 2>/dev/null" | grep -o '"key":"proposal_id","value":"[0-9]*"' | grep -o '[0-9]*' | head -1) + +if [ -z "$PROPOSAL_ID" ]; then + echo "[migrate-stayoncomet] failed to extract proposal ID, querying all proposals..." + sleep 3 + PROPOSAL_ID=$(docker exec "$NODE" sh -lc "gmd query gov proposals --home $HOME_DIR --output json" | grep -o '\"id\":\"[0-9]*\"' | tail -1 | grep -o '[0-9]*') +fi + +echo "[migrate-stayoncomet] proposal ID: $PROPOSAL_ID" + +echo "[migrate-stayoncomet] waiting for proposal to be queryable..." +sleep 3 + +echo "[migrate-stayoncomet] voting yes on proposal from all validators..." +for val in "${VALIDATORS[@]}"; do + echo "[migrate-stayoncomet] voting from $val..." + if docker exec "$val" sh -lc "gmd tx gov vote $PROPOSAL_ID yes \ + --from $KEY \ + --keyring-backend test \ + --chain-id $CHAIN_ID \ + --home $HOME_DIR \ + --yes" 2>&1 | grep -q "code: 0"; then + echo "[migrate-stayoncomet] ✓ vote from $val succeeded" + else + echo "[migrate-stayoncomet] ✗ vote from $val failed" + fi + sleep 2 +done + +echo "[migrate-stayoncomet] waiting for votes to be processed..." +sleep 3 + +echo "[migrate-stayoncomet] proposal submitted and voted on" +echo "[migrate-stayoncomet] proposal ID: $PROPOSAL_ID" +echo "[migrate-stayoncomet] migration will execute at height $MIGRATE_AT" diff --git a/scripts/e2e/relayer.mnemonic b/scripts/e2e/relayer.mnemonic new file mode 100644 index 00000000..f1032c1a --- /dev/null +++ b/scripts/e2e/relayer.mnemonic @@ -0,0 +1 @@ +abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about diff --git a/scripts/e2e/update-clients-simple.sh b/scripts/e2e/update-clients-simple.sh new file mode 100755 index 00000000..d6b1c549 --- /dev/null +++ b/scripts/e2e/update-clients-simple.sh @@ -0,0 +1,50 @@ +#!/bin/bash +set -e + +CONFIG=/home/hermes/.hermes/config.toml + +# Simple IBC client update script - just updates to H+1 and lets Hermes handle bisection +# Usage: ./update-clients-simple.sh + +log() { + echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*" +} + +if [ -z "$1" ]; then + echo "Usage: $0 " >&2 + echo " Updates all IBC clients to migration_height+1" >&2 + exit 2 +fi + +MIG_HEIGHT="$1" +TARGET_HEIGHT=$((MIG_HEIGHT + 1)) + +log "Updating IBC clients to height $TARGET_HEIGHT (migration at $MIG_HEIGHT)" + +# Query all clients on gm-b that track gm-a +log "Querying clients on gm-b tracking gm-a..." +GMA_CLIENT_ON_B=$(docker exec hermes hermes --json --config $CONFIG query clients --reference-chain gm-a --host-chain gm-b 2>/dev/null | jq -r '.result[0] // empty') + +if [ -n "$GMA_CLIENT_ON_B" ]; then + log "Updating gm-a client on gm-b: $GMA_CLIENT_ON_B -> height $TARGET_HEIGHT" + docker exec hermes hermes --config $CONFIG update client --host-chain gm-b --client "$GMA_CLIENT_ON_B" --height "$TARGET_HEIGHT" || { + log "Warning: Failed to update client $GMA_CLIENT_ON_B on gm-b" + } +else + log "No gm-a client found on gm-b" +fi + +# Query all clients on gm-c that track gm-a +log "Querying clients on gm-c tracking gm-a..." +GMA_CLIENT_ON_C=$(docker exec hermes hermes --json --config $CONFIG query clients --reference-chain gm-a --host-chain gm-c 2>/dev/null | jq -r '.result[0] // empty') + +if [ -n "$GMA_CLIENT_ON_C" ]; then + log "Updating gm-a client on gm-c: $GMA_CLIENT_ON_C -> height $TARGET_HEIGHT" + docker exec hermes hermes --config $CONFIG update client --host-chain gm-c --client "$GMA_CLIENT_ON_C" --height "$TARGET_HEIGHT" || { + log "Warning: Failed to update client $GMA_CLIENT_ON_C on gm-c" + } +else + log "No gm-a client found on gm-c" +fi + +log "Done! Hermes handled bisection internally." From 4bc8b617e65beb53251946d9db7b83d2fdeb9edd Mon Sep 17 00:00:00 2001 From: chatton Date: Fri, 28 Nov 2025 12:17:59 +0000 Subject: [PATCH 2/2] chore: verified working as expected --- scripts/e2e/Makefile | 33 +++++++++++++++++++++++++++++++++ scripts/e2e/hermes-entry.sh | 12 ++++-------- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/scripts/e2e/Makefile b/scripts/e2e/Makefile index 5653004f..dcf340ab 100644 --- a/scripts/e2e/Makefile +++ b/scripts/e2e/Makefile @@ -23,6 +23,8 @@ help: @echo " make logs-a/b/c - tail chain logs" @echo " make hermes-start - start Hermes only (after chains ready)" @echo " make ibc-setup - fund relayer and create A<->B, A<->C channels" + @echo " make ibc-transfer - send IBC transfer from gm-a to gm-b (can be called multiple times)" + @echo " make ibc-transfer-verify - verify IBC transfer completed" @echo " make migrate - submit StayOnComet migration on A (WINDOW=$(WINDOW))" @echo " make backfill MIG= [WINDOW=$(WINDOW)] - run client backfill" @echo " make clean - down and remove volumes" @@ -81,6 +83,37 @@ hermes-start: ibc-setup: bash ./ibc-setup.sh +.PHONY: ibc-transfer +ibc-transfer: + @echo "[ibc-transfer] Sending 1000000stake from gm-a to gm-b" + @docker exec -i gm-a-val-0 gmd tx ibc-transfer transfer transfer channel-0 \ + $$(docker exec -i gm-b-val-0 gmd keys show faucet -a --keyring-backend test --home /home/gm/.gm) \ + 1000000stake \ + --from faucet \ + --keyring-backend test \ + --chain-id gm-a \ + --home /home/gm/.gm \ + --yes \ + --output json | jq -r '.txhash // "Transaction submitted"' + +.PHONY: ibc-transfer-verify +ibc-transfer-verify: + @echo "[ibc-transfer-verify] Checking IBC balance on gm-b..." + @sleep 5 + @IBC_DENOM=$$(docker exec -i gm-b-val-0 gmd query bank balances \ + $$(docker exec -i gm-b-val-0 gmd keys show faucet -a --keyring-backend test --home /home/gm/.gm) \ + --home /home/gm/.gm \ + --output json 2>/dev/null | jq -r '.balances[] | select(.denom | startswith("ibc/")) | .denom' | head -1); \ + if [ -n "$$IBC_DENOM" ]; then \ + BALANCE=$$(docker exec -i gm-b-val-0 gmd query bank balances \ + $$(docker exec -i gm-b-val-0 gmd keys show faucet -a --keyring-backend test --home /home/gm/.gm) \ + --home /home/gm/.gm \ + --output json 2>/dev/null | jq -r ".balances[] | select(.denom == \"$$IBC_DENOM\") | .amount"); \ + echo "[ibc-transfer-verify] ✓ IBC balance: $$BALANCE $$IBC_DENOM"; \ + else \ + echo "[ibc-transfer-verify] ✗ No IBC tokens found yet"; \ + fi + .PHONY: migrate migrate: WINDOW=$(WINDOW) bash ./migrate-stayoncomet.sh $(WINDOW) diff --git a/scripts/e2e/hermes-entry.sh b/scripts/e2e/hermes-entry.sh index 8f9186c7..0d342090 100644 --- a/scripts/e2e/hermes-entry.sh +++ b/scripts/e2e/hermes-entry.sh @@ -91,17 +91,13 @@ echo "[hermes] creating IBC connections/channels" # A <-> B hermes --config "$CONFIG" create connection --a-chain gm-a --b-chain gm-b || true hermes --config "$CONFIG" create channel \ - --a-chain gm-a --b-chain gm-b \ - --a-port transfer --b-port transfer \ - --order unordered --channel-version ics20-1 \ - --new-client-connection || true + --a-chain gm-a --a-connection connection-0 \ + --a-port transfer --b-port transfer # A <-> C hermes --config "$CONFIG" create connection --a-chain gm-a --b-chain gm-c || true hermes --config "$CONFIG" create channel \ - --a-chain gm-a --b-chain gm-c \ - --a-port transfer --b-port transfer \ - --order unordered --channel-version ics20-1 \ - --new-client-connection || true + --a-chain gm-a --a-connection connection-1 \ + --a-port transfer --b-port transfer echo "[hermes] starting relayer" exec hermes --config "$CONFIG" start