Skip to main content
Adding a new chain involves two independent tasks: getting the chain’s execution client to export data (the write side), and getting leafage-evm to execute calls for the chain correctly (the read side). The two sides can progress separately.
If the client the new chain uses is already in the list of adapted clients (for example, yet another OP Stack chain), the write side usually only needs a new deployment; no code changes are required.

Write side: integrate pipeline into the execution client

Choose an adaptation path

The three adaptation guides are in the pipeline repository: standard, legacy, Reth.

What to change

Using a standard Geth fork as an example:
1

Extend the tracing hooks

Add OnCommit and OnBlockDBStart in core/tracing/hooks.go.
2

Export the state diff

Add StateDiff() in core/state/statedb.go to convert the commit set into pipeline’s types.
3

Distribute the hooks

Call the new hooks on the block processing path in core/blockchain.go, and compute the reorg and publish the Kafka notification when the canonical head is determined.
4

Register the live tracer

Create eth/tracers/live/pipeline.go and register the pipeline tracer in LiveDirectory.
5

Add the RPC

Implement trace_debankBlock and register the trace namespace in eth/backend.go.
6

Validate

Once go build ./... passes, run a real chain and compare the output of trace_debankBlock with the objects on S3.
The reference implementation is the diff of the write node against upstream, about 2000 lines in total.

Adapting with Claude Code

The pipeline repository ships with adaptation skills that detect the client type automatically and guide you stage by stage:
It scans for signals such as Cargo.toml, go.mod, tracing.Hooks, and vm.EVMLogger to determine the client type, checks whether an integration already exists, and then routes to the corresponding specialized skill: /adapt-pipeline-geth, /adapt-pipeline-legacy, or /adapt-pipeline-reth. The flow for each stage is: probe the code structure → consult the guide → generate the changes → run go build or cargo check to validate.

Read side: add an executor to leafage-evm

If the new chain’s EVM behavior is identical to a chain that is already supported, just start with the corresponding --evm-type and the correct --chain-cfg (chain ID). A new executor is only needed when the behavior differs. What to change: A typical configuration branch:
The disable_* settings are standard for state queries: eth_call does not need to check balances, the base fee, or the block gas limit.
Start with the closest chain in leafage-evm-chains. OP Stack chains can follow base or mantle, standalone EVM-compatible chains can follow citrea or iotex, and chains that need custom precompiles can follow bsc or cosmos.

Historical ranges without data

Some chains have historical ranges where block diffs cannot be obtained (typically OP pre-bedrock). Use --historical-rpc to specify an external RPC and --historical-height to specify the fork height; queries below the threshold are forwarded out.

Validation

1

Compare state

For the same batch of addresses and storage slots, compare the eth_getBalance, eth_getStorageAt, and eth_getCode return values from leafage-evm and the chain’s official full node.
2

Compare call results

Use leafage-bench to send the same corpus to both leafage-evm and a full node, and compare the eth_call return values and latency.
3

Watch reorgs

Watch the changeType: 2 notifications for a while and confirm that leafage-evm’s chain head follows correctly. Chains with deeper reorgs need a correspondingly larger --catchup-safe-depth.

Deployment

Deploying a new chain is identical to existing chains; only the chainID differs: Kafka topics, S3 prefixes, and etcd keys all start with the chain ID, so they are naturally isolated. nodex-proxy does not need a restart; it discovers the new chain’s nodes through etcd. See the deployment guide for the specific steps.