Overview
For chains that are part of the publicsuperchain-registry, the standard kona-client absolute prestate published in standard-prestates.toml already embeds your chain configuration. No custom build is needed.
This tutorial is for the rarer case: a partner chain whose RollupConfig is not yet in the public registry but which still needs to run permissionless fault proofs (cannon-kona game type). In that case you must build a custom kona-client that embeds your chain’s configuration, generate the absolute prestate hash from that build, and host the resulting binary at a URL op-challenger can fetch.
Most chains are in the Superchain Registry and should use the standard prestate. Only follow this tutorial if your chain is not yet in the registry. Once the chain is added to the public registry, future releases will cover it via the standard prestate and you can stop maintaining a custom build.
Prerequisites
Before starting, ensure you have:- Docker running
justinstalled- Your chain’s
rollup.json, L2 genesis, and deployment artifacts (typically produced byop-deployer)
How kona-client picks up custom chain configurations
kona-client reads its embedded chain registry from the kona-registry crate. At build time, the crate’s build.rs can merge additional chains on top of the canonical Superchain Registry snapshot. The merge is gated by two environment variables:
KONA_CUSTOM_CONFIGS_DIR:
chainList.json— light-weightChainentries for your custom chainsconfigs.json— fullChainConfig+RollupConfigentries grouped under aSuperchainbucket
kona-registry README.
The compiled kona-client binary embeds the merged registry via include_str!(), so the resulting absolute prestate hash differs from the standard one. Any honest challenger participating in your chain’s dispute games will need to run this same binary.
Generating the custom prestate
Check out a kona-node release tag
Use the same
kona-node/v<VERSION> tag that your chain’s nodes are running. The native KONA_CUSTOM_CONFIGS_DIR support documented below requires kona-node/v1.5.2 or later; on older tags, additional justfile patches are needed.Stage your chain configuration
Create a directory for your custom configs:Add two files inside it — Source the values from your chain’s existing artifacts:
chainList.json (lightweight chain entry) and configs.json (full rollup config). Replace every <PLACEHOLDER> with your chain’s value. Notes:<CHAIN_GROUP>:mainnetif your L1 is Ethereum mainnet,sepoliaif your L1 is Sepolia. The bucket groups chains by L1 network, not by governance — your custom-chain status is expressed viagovernedByOptimism: falseandsuperchainLevel: 0.faultProofs.status:permissionlessfor chains running thecannon-konagame type publicly,permissionedfor chains that only allow whitelisted challengers.
- chainList.json
- configs.json
genesis.*,block_time,seq_window_size,max_sequencer_drift,batch_inbox_address, hardfork timestamps → your chain’srollup.jsonAddresses.*→ yourop-deployerstate (opChainDeployments[<i>])Roles.*→ yourop-deployerstate’s per-chainrolesblock
cast call) before committing.Generate the absolute prestate
From the root of the monorepo, point The hash printed is your chain’s custom kona absolute prestate. The build also writes a hash-named gzipped binary at
KONA_CUSTOM_CONFIGS_DIR at the directory you created in Step 2, then run the canonical build:rust/kona/prestate-artifacts-cannon/0x<hash>.bin.gz — this is the file op-challenger needs to fetch at dispute time.Verify your chain is embedded in the prestate
A custom-config build that silently fails to merge your chain produces the standard prestate hash — and an Run the
op-challenger pointed at it will never agree with your games. Always confirm your chain actually made it in:grep once per chain in your chainList.json and confirm at least one match for every chain — a build that embeds chain A but drops chain B still produces a valid-looking hash. Zero matches means KONA_CUSTOM_CONFIGS=true was not set in the build shell, or KONA_CUSTOM_CONFIGS_DIR was a relative path.Deploying and configuring with the custom prestate
Host the prestate binary
Upload
0x<hash>.bin.gz to wherever you serve preimage files for op-challenger — typically a GCS bucket or HTTP endpoint. Files must be named by their absolute prestate hash so the challenger can resolve them on demand.Register the custom prestate as game type 8
On the current (v2.4+) dispute-game contracts the absolute prestate is not a constructor argument — it lives in the Reuse Then make game type 8 the respected type from the Guardian role — See Migrating to permissionless fault proofs for the full role/transaction walkthrough. (On older, pre-v2.4 contracts where
DisputeGameFactory’s per-game-type gameArgs, appended to each game via clones-with-immutable-args. So you do not deploy a new implementation for a new prestate. Reuse the existing permissionless FaultDisputeGame implementation (a fresh op-deployer chain deploys one but leaves it unregistered) and register it for game type 8 with gameArgs that carry your prestate.gameArgs for a permissionless game is the packed encoding (124 bytes):vm / anchorStateRegistry / weth / l2ChainId from an existing registered game type (e.g. read gameArgs(1) and swap in your prestate), then register from the DisputeGameFactory owner:respectedGameType lives on the AnchorStateRegistry, not the OptimismPortal (the portal proxies to it):absolutePrestate was a constructor immutable, each prestate did require a fresh implementation deployment instead.)Configure op-challenger
Add the kona-specific env vars to your existing challenger config:The challenger appends
/0x<hash>.bin.gz to *_PRESTATES_URL to resolve the right binary per dispute. Your existing OP_CHALLENGER_ROLLUP_CONFIG, OP_CHALLENGER_L2_GENESIS, and OP_CHALLENGER_GAME_FACTORY_ADDRESS continue to apply unchanged.Next Steps
- Upgrade 19 notice — the
cannon-konagame type promotion and reference build commands for the standard prestate. - Generating absolute prestate and preimage files — the equivalent tutorial for
op-program(cannon, game type 1), kept for chains still running that game type.