Process Overview
- Create an upgrade branch and freeze schema-affecting changes
- Export a pre-upgrade state and archive node configs
- Bump
cosmos/evmto v0.4.0 and align Cosmos SDK/IBC/CometBFT constraints - Rewire keepers and AppModule (imports, constructors,
RegisterServices) - Add client context field and
SetClientCtxmethod - Add pending transaction listener support
- Migrate ERC20 precompiles if you have existing token pairs (see [this section]./(erc20-precompiles-migration))
- Audit and migrate EVM & FeeMarket params (EIP-1559 knobs, denom/decimals)
- Implement store/params migrations in your UpgradeHandler
Prep
- Create a branch:
git switch -c upgrade/evm-v0.4 - Ensure a clean build + tests green pre-upgrade
- Snapshot your current params/genesis for comparison later
Dependency bumps
Pin EVM and tidy
Bump thecosmos/evm dependency in go.mod:
Transitive bumps
Check for minor dependency bumps (e.g.,google.golang.org/protobuf, github.com/gofrs/flock, github.com/consensys/gnark-crypto):
App constructor return type & CLI command wiring
Update your app’snewApp to return an evmserver.Application rather than servertypes.Application, and CLI commands that still expect an SDK app creator require a wrapper.
Change the return type
Provide a wrapper for commands that expect the SDK type
Create a thin wrapper and use it forpruning.Cmd and snapshot.Cmd:
Add clientCtx and SetClientCtx
Add the clientCtx to your app object:Pending-tx listener support
Imports
Import the EVM ante package and geth common:App state: listeners slice
Add a new field for listeners:Registration method
Add a public method to register a listener by txHash:Precompiles: optionals + codec injection
New imports
Define Optionals + defaults + functional options
Create a small options container with sane defaults pulled from the app’s bech32 config:4.3 Update the precompile factory to accept options
4.4 Modify individual precompile constructors
ICS-20 precompile now needsbankKeeper first:
AddressCodec:
ERC20 Precompiles Migration
Include this migration with your upgrade if your chain has:- IBC tokens converted to ERC20
- Token factory tokens with ERC20 representations
- Any existing
DynamicPrecompilesorNativePrecompilesin storage
Implementation
For complete migration instructions, see: ERC20 Precompiles Migration Guide Add this to your upgrade handler:Verification
Post-upgrade, verify your migration succeeded:Build & quick tests
-
Compile:
-
Smoke tests (local single-node):
- Start your node; ensure RPC starts cleanly
- Deploy a trivial contract; verify events and logs
- Send a couple 1559 txs and confirm base-fee behavior looks sane
- (Optional) register a pending-tx listener and log hashes as they enter the mempool
Rollout checklist
- Package the new binary (and Cosmovisor upgrade folder if you use it)
- Confirm all validators build the same commit (no
replacelines) - Share an
app.tomldiff only if you changed defaults; otherwise regenerate the file from the new binary and re-apply customizations - Post-upgrade: monitor mempool/pending tx logs, base-fee progression, and contract events for the first 20-50 blocks
Pitfalls & remedies
-
Forgot wrapper for CLI commands →
pruning/snapshotpanic or wrong type:- Ensure you pass
sdkAppCreatorWrapper(notac.newApp) into those commands
- Ensure you pass
-
ICS-20 precompile build error:
- You likely didn’t pass
bankKeeperfirst; update the call site
- You likely didn’t pass
-
Governance precompile address parsing fails:
- Provide the correct
AddressCodecvia defaults orWithAddressCodec(...)
- Provide the correct
-
Listeners never fire:
- Register with
RegisterPendingTxListenerduring app construction or module init
- Register with
Minimal code snippets
App listenersAdditional Breaking Changes (v0.3.1 → v0.4.1)
Credits: Thanks to the Mantrachain team for identifying these additional migration requirements.
CallEVM Signature Change
TheCallEVM function now requires a gasCap parameter of type *big.Int. You can pass nil for default behavior.
Function Signature (from x/vm/keeper/call_evm.go:20):
x/erc20/keeper/evm.go:87):
x/erc20/keeper/evm.go:87- decimals callx/erc20/keeper/evm.go:143- balanceOf callx/ibc/callbacks/keeper/keeper.go:193- approve call with custom gas cap
Test Keyring Import Path
The test keyring package has been reorganized into its own subdirectory. Import Change:tests/integration/precompiles/erc20/test_setup.go:10):
testutil/keyring/keyring.go:58):
New(nAccs int) Keyring- Create keyring with n accountsGetPrivKey(index int)- Get private keyGetAddr(index int)- Get Ethereum addressGetAccAddr(index int)- Get Cosmos SDK addressGetAllAccAddrs()- Get all SDK addresses
Verify before tagging
go.modhas noreplacelines forgithub.com/cosmos/evm- Node boots with expected RPC namespaces
- Contracts deploy/call; events stream; fee market behaves
- (If applicable) ICS-20 transfers work and precompiles execute