Upgrade an IBC Solidity contract using the router as an example.
This guide demonstrates a contract upgrade using the IBC router (ICS26Router) as an example. You will replace the implementation behind each router proxy on the tutorial’s two chains while preserving each proxy’s address and state. The new logic is built from the same source the tutorial deployed, so these steps demonstrate the upgrade without changing its behavior.
ROUTER_A=$(./bin/ibc deploy show 41001 | jq -r '.core.router')ROUTER_B=$(./bin/ibc deploy show 41002 | jq -r '.core.router')IFT_A=$(./bin/ibc deploy show 41001 | jq -r '.tokens[0].address')IFT_B=$(./bin/ibc deploy show 41002 | jq -r '.tokens[0].address')DEPLOYER_KEY=$(./bin/ibc keys show deployer --private | jq -r '.privateKey')
The last line reads the deployer’s raw private key, because Foundry cannot read the CLI’s key files. Run unset DEPLOYER_KEY when you finish, so the key does not stay in your shell.
For a different target version, review the contracts repository’s upgradeability overview and release policy.
The policy defines minor Solidity releases as requiring a new initializer for storage changes.
Patch releases require neither storage changes nor a new initializer.
Major releases introduce API-breaking changes.Check the target release for required initialization and function-role changes.
See Permissions and upgrades for storage-layout and access-control considerations.This guide builds the new logic from the ibc-contracts commit the IBC CLI pins, which is the source of the logic ibc deploy core deployed.For your own upgrade, check out the release you are shipping. Compare its IBCRolesLib and DeployAccessManagerWithRoles with your deployment’s assignments. If the release newly marks a function restricted, assign its selector before you call upgradeToAndCall. The old logic does not consult the access manager for that function, so the assignment changes nothing until the upgrade, and callers the release admits never lose access.
When changing contract versions, verify storage compatibility and follow the release’s initialization or migration requirements. The upgrade transaction does not check storage compatibility.
Switch the 41001 router to NEW_IMPL_A:
Use empty call data, 0x, because this example redeploys the same contract version.
If your target release requires an initializer or migration function, encode that call and its arguments.
Pass the encoded data instead of 0x in both upgrade calls.
With nonempty data, upgradeToAndCall executes that call in the same transaction.
If the tutorial’s transfer is the only earlier transfer, the balance is 20000000000000000000: the tutorial’s 10 tokens plus this transfer’s 10. Each additional transfer raises the balance by its amount.Clear the admin key when finished:
The CLI does not currently have first-class support for contract upgrades.
This guide upgrades the routers directly on chain, leaving each manifest’s targetData.ics26RouterImplementation at its original address.
Rerunning ibc deploy core reuses the deployed contracts without refreshing their implementation addresses in the manifests.