This repository is the source of truth for Eureka-related deployments.
It is used by operators to deploy and perform maintenance operations. In addition, it can be used by anyone to find the most up-to-date contract addresses for different deployments and even verify that they match what is on-chain.
To use most of the functionality in this repo, you will need to install the following software:
Most recipes in this repo depend on values defined in .eureka-env.
To set yours up, copy the .eureka-env.example file and fill in the values, according to the environment you are going to run against.
The functionality of this repo is implemented through Just recipes (which are somewhat similar to Make targets). To see available recipes, run:
just --listOperator procedures live in runbooks/. Key ones:
upgrade-v2-to-v3.md— the canonical v2→v3 core upgrade + SP1 v6.1 migration (steps 1–13). Single source of truth for that operation.post-upgrade-role-testing.md— validate & test the v3AccessManagerroles after a v2→v3 upgrade (read its Mainnet adaptation section before running anything on mainnet).upgrade-light-client.md,upgrade-ics-20.md,upgrade-ics-26.md,upgrade-escrow.md,upgrade-ibcerc20.md— routine single-contract upgrades.pause.md,recover-expired-light-client.md,env-setup.md.- Operations log:
runbooks/operations/— one folder per executed operation; each typically has aRECORD.md(addresses, tx hashes, findings). See2026-06-18-upgrade-v2-to-v3/SIGNER-CHECKLIST.mdfor the v2→v3 signer checklist.
scripts/discover-v2-roles.py— pre-cutover: enumerate the live v2 role grants (via Etherscan logs) and reconcile against the deployment JSON, so you build the exact grant set (incl. theRATE_LIMITERre-grant set) the upgrade must carry. NeedsETH_RPC+ETHERSCAN_API_KEY.scripts/validate-v3-roles.py— post-cutover: independently validate every v3AccessManager(target,selector)→role, exact role membership, andauthority()wiring on-chain. NeedsETH_RPC.
Any on-chain verification that is not implemented as recipes yet should be documented below:
To verify that the Ethereum Light on the hub is running a specific version of the CosmWasm smart contract from the solidity-ibc-eureka repo, follow the steps below:
- Acquire the binary you want to verify against by for instance downloading the binary from the release page
- Get the binary checksum by running
gunzip -c path/to/cw_ics08_wasm_eth.wasm.gz | sha256sum - Fetch the checksum of the Ethereum light client (example below for Cosmos Hub mainnet, where the Ethereum light client ID is
08-wasm-1369) and convert it from base64 to hex:gaiad q ibc client state 08-wasm-1369 --output json | jq -r ".client_state.checksum" | base64 --decode | xxd -p -c 32
- Verify that the output from step 2 matches the output from step 3
To rehearse the v2-to-v3 upgrade (including the SP1 light-client migrations) against uncommitted local changes, start an Anvil fork in one terminal:
export SEPOLIA_RPC=<SEPOLIA_RPC_URL>
just shadow-start-sepoliaThen run the rehearsal in another terminal:
just shadow-v2-to-v3-sepolia-with-sp1The SP1 clients to migrate are read from the deployment JSON (.light_clients[].clientId), so there is nothing to type, and the rehearsal writes only to ignored deployments/shadow-* copies. Use MAINNET_RPC with just shadow-start-mainnet and just shadow-v2-to-v3-mainnet-with-sp1 for Ethereum mainnet. To additionally exercise the real TimelockController + atomic Safe MultiSend path, use just shadow-v2-to-v3-sepolia-timelock. See runbooks/upgrade-v2-to-v3.md for the full flow.
For a new v3 deployment where accessManager, ics26Router, and ics20Transfer addresses are still zero in the deployment JSON, deploy the core contracts with:
just deploy-v3-coreThis deploys the AccessManager, ICS26Router, ICS20Transfer, ICS27GMP, ICS27Account, Escrow, and IBCERC20 implementations, registers the transfer and GMP apps on the router, configures the v3 target function roles, grants the configured relayer/pauser/unpauser/delegate-sender/customizer roles, and writes the deployed addresses back to deployments/<environment>/<chain_id>.json.
The script temporarily uses the broadcast account as the AccessManager admin during deployment, then hands admin control to the configured .accessManagerRoles.admin. The configured admin can be an EOA, Safe, or timelock.
Migrating/upgrading a light client is done in two steps:
- Deploying the new light client contract
- Migrating the existing light client to use the new contract
To deploy a new light client contract that is intended to be migrated, you want to essentially make a "copy" (with any modifications you might want, such as new vkeys) of the existing light client with a new contract.
Deploying the new light client contract can be done by anyone, but it is important for whoever is running the migration to verify both the contract and constructor parameters of the new light client.
- Update any fields you want changed in the relevant light client entry in the deployment JSON file.
- Update the deployment JSON entry with the latest client and consensus state from the existing light client with:
just deploy-update-light-client-state # You will be prompted for the client ID of the light client you want updated - Deploy the light client with:
just deploy-light-client # You will be prompted for the client ID of the light client to deploy
The last step will deploy the light client, but not add it to the IBC Client router. It is just a deployed contract with permissions set up for it. The implementation address will be updated in the deployment JSON entry for the light client, making it ready for step 2: migrating the existing light client.
⚠️ Only a wallet with the Light Client Migrator role for the given light client can migrate. Here, we're assuming a timelock admin has those permissions.
- Generate the timelock schedule transaction for the light client with:
just timelock-migrate-light-client schedule
- Follow the instructions to create the timelock transactions
After the timelock delay has passed, do the above steps again but replace schedule with execute
IBCERC20 metadata customization was removed in solidity-ibc-eureka v3. Prefer custom ERC20s through the custom ERC20 flow instead of post-deployment IBCERC20 metadata changes.
Important
This is for routine UUPS upgrades after the v2-to-v3 migration. It performs an upgradeToAndCall with empty calldata, so it does not call initializeV2. Do not use it to perform the v2-to-v3 core upgrades — use schedule-v3-*/execute-v3-*-upgrade-params (see runbooks/upgrade-v2-to-v3.md), which call initializeV2(accessManager). As a guard, timelock-upgrade-proxy refuses to upgrade ICS26Router/ICS20Transfer when the deployment records an accessManager but the proxy is not yet AccessManaged by it.
Modify one (and only one at the time) of the implementation values in the deployment json for one of the ERC1967Proxy contracts (ICS26Router, ICS20Transfer, or ICS27GMP).
Run the script to generate the information needed to submit a proposal to the Safe Wallet:
just timelock-upgrade-proxyThe beacon implementations have their own param recipes: schedule-escrow-upgrade-params, schedule-ibcerc20-upgrade-params, and schedule-ics27account-upgrade-params (plus the matching execute-*).