Skip to content

ZEVM JSON-RPC Contract

This file is the exact ZEVM JSON-RPC API contract.

It defines:

  • request tuples
  • request-object fields
  • return payload shapes
  • mode gating
  • selector resolution
  • error behavior
  • trusted-mode canonical zevm_* methods and accepted aliases
TypeContract
QuantityHex0x-prefixed unsigned integer, minimal hex encoding except 0x0
Address0x-prefixed 20-byte hex
Hash320x-prefixed 32-byte hex
Bytes320x-prefixed 32-byte hex
HexData0x-prefixed byte string hex; 0x means empty
BlockTaglatest, earliest, pending, safe, finalized, or numeric quantity
TrustedBlockSelectorany BlockTag
LightBlockSelectorlatest, earliest, pending, safe, finalized, or numeric quantity; pending is rejected for light proof-backed reads with -32010
ReceiptSelectorone BlockTag or one Hash32 block hash
RuntimeSourceeth_chainId result
trusted modeconfigured chainIdconfigured value as QuantityHex
light mode + mainnetfixed mapping0x1
light mode + sepoliafixed mapping0xaa36a7
light mode + holeskyfixed mapping0x4268
  • HTTP only
  • JSON-RPC endpoint path is / only
  • request method for JSON-RPC endpoint is POST only
  • request path other than / -> HTTP 404 with no JSON-RPC body
  • non-POST request to / -> HTTP 405 with no JSON-RPC body
  • POST / request content type must be application/json (media-type parameters allowed); unsupported or missing content type -> HTTP 415 with no JSON-RPC body
  • JSON-RPC success responses -> HTTP 200
  • JSON-RPC error responses -> HTTP 200
  • notification-only request or notification-only batch -> HTTP 204 with empty body
  • request body limit is 1,048,576 bytes; larger bodies return HTTP 413 with no JSON-RPC body
  • HTTP header read buffer limit is 8,192 bytes; oversized or malformed headers close the connection without a JSON-RPC body
  • listener accepts up to 64 active TCP connections; slow clients are isolated at the connection layer and do not block other accepted clients
  • accepted connections use 15,000 ms read and write socket timeouts
  • handler dispatch is serialized within a ZEVM process so concurrent transport connections cannot race the runtime state
  • one canonical ZEVM-owned HTTP transport/parser stack is the shipping path for request parsing and envelope dispatch; divergent production parser stacks are out of contract for phase 1
  • whenever a JSON-RPC body is returned, content type is application/json
  • protocol: JSON-RPC 2.0
  • single requests: supported
  • batches: supported
  • empty batch []: invalid request and returns HTTP 200 with exactly:
{
"jsonrpc": "2.0",
"id": null,
"error": {
"code": -32600,
"message": "Invalid Request"
}
}
  • notification = request object with no id
  • ZEVM sends no JSON-RPC response for notifications
  • mixed batches return responses only for entries that had id, preserving the input order of those entries
  • "id": null is not a notification and receives a response
ConditionCode
parse error-32700
invalid request-32600
method not found-32601
invalid params-32602
internal error-32603
ConditionCode
method unsupported in active mode-32010
light mode not ready for proof-backed reads-32011
reserved: selected checkpoint too old under strict startup policy-32012
reserved: checkpoint input or persisted checkpoint is malformed/corrupt-32013
proof verification failed-32014
malformed data from upstream proof source-32015
  • malformed addresses, quantities, hex bytes, selectors, filters, tuple lengths, or invalid object field combinations -> -32602
  • well-formed requests for methods defined by this contract but unavailable in active mode -> -32010
  • well-formed requests that use deferred/out-of-contract JSON-RPC method names (section 14) -> -32601
  • trusted block/tx lookup miss -> null
  • eth_getLogs no matches -> []
  • selected light checkpoint is stale only when age > maxCheckpointAgeSeconds; age == maxCheckpointAgeSeconds is valid
  • age is ZEVM’s startup-time freshness value for the selected startup checkpoint
  • age is evaluated once during startup, after checkpoint selection and before stale-policy decision
  • age is measured in whole seconds: age = max(0, startupTimeSeconds - checkpointTimeSeconds)
  • startupTimeSeconds is sampled at age-check time
  • selected startup checkpoint hash must resolve on the selected network via the configured consensus source (consensusRpcUrl); network mismatch is startup failure before listening
  • checkpointTimeSeconds is derived deterministically from Beacon API data for the selected startup checkpoint hash and is anchored to that checkpoint, not to filesystem metadata or local file/write times
  • derivation steps are exact:
    1. call GET <consensusRpcUrl>/eth/v1/beacon/genesis, require HTTP 200, parse data.genesis_time as decimal unsigned integer genesisTimeSeconds
    2. call GET <consensusRpcUrl>/eth/v1/beacon/headers/{selectedCheckpointHash}, require HTTP 200, parse data.root as Hash32 and require equality with selectedCheckpointHash, then parse data.header.message.slot as decimal unsigned integer checkpointSlot
    3. use SECONDS_PER_SLOT = 12 for phase-1 supported light networks and compute checkpointTimeSeconds = genesisTimeSeconds + (checkpointSlot * SECONDS_PER_SLOT) with integer arithmetic
    4. use computed checkpointTimeSeconds as integer Unix seconds in age evaluation
  • any request failure, non-200, missing/malformed required field, checkpoint-root mismatch, or arithmetic overflow in this derivation is inability to resolve checkpointTimeSeconds and is startup failure before listening
  • stale selected checkpoint + strictCheckpointAge = false: emit one operator-facing startup warning before listening, then continue startup
  • non-strict stale warnings must be surfaced on startup logs via process stderr and must not be surfaced via JSON-RPC
  • phase 1 defines no dedicated CLI/config controls for startup log level, log file paths, or alternative startup log sinks
  • the non-strict stale warning must include: selected checkpoint hash, checkpointSource, checkpointTimeSeconds, startupTimeSeconds, computed age, maxCheckpointAgeSeconds, and strictCheckpointAge = false
  • stale selected checkpoint + strictCheckpointAge = true: startup failure before listening
  • inability to resolve checkpointTimeSeconds for the selected startup checkpoint is startup failure before listening
  • checkpoint startup input format split is intentional: CLI/config startup checkpoint input must be Hash32 (0x + 64 hex chars), while persisted ${resolvedCheckpointDir}/checkpoint content must be 64 hex chars without 0x
  • persisted checkpoint startup input path is ${resolvedCheckpointDir}/checkpoint, where resolvedCheckpointDir is derived from startup checkpointDir by applying <network> expansion and then resolving relative paths against startup current working directory
  • if ${resolvedCheckpointDir} is missing at startup (including missing expanded <network> subdirectory), persisted checkpoint input is treated as absent and startup precedence continues
  • if ${resolvedCheckpointDir}/checkpoint is missing, persisted checkpoint input is treated as absent and startup precedence continues
  • startup checkpoint precedence fallthrough is absence-driven only; once a checkpoint source is selected, any validation/derivation failure for that selected source is startup failure before listening and must not trigger fallback to lower-precedence sources
  • if ${resolvedCheckpointDir}/checkpoint exists but is unreadable, startup fails before listening
  • malformed initial checkpoint input or malformed readable persisted checkpoint file is startup failure before listening
  • ZEVM does not auto-create ${resolvedCheckpointDir} during startup
  • in phase 1, ${resolvedCheckpointDir}/checkpoint is startup input only; ZEVM does not create, update, or delete this file after the HTTP listener has started
  • -32012 and -32013 remain reserved at runtime and are not emitted after the HTTP listener has started
SelectorMeaning
latestcurrent canonical local head
pendingalias of latest
safealias of latest
finalizedalias of latest
earliestblock 0
numeric quantityexact local block number

pending, safe, and finalized in trusted mode are compatibility aliases only.

Pending-alias rule in trusted mode:

  • there is no separate pending block view for selector-based queries
  • any trusted-mode method that accepts a block selector and receives pending must resolve it exactly as latest
  • methods that need trusted state snapshots may further constrain selectors to the current head; those method-specific constraints are documented in the method section
SelectorMeaning
latestlatest verified optimistic execution head
safeconsensus-backed safe execution head
finalizedconsensus-finalized execution head
earliestblock 0
numeric quantityblock 0 or a retained numeric block inside the moving verified-history window
pendingunsupported -> -32010

Retained-history window contract:

  • constant window size: 8191 verified execution blocks
  • let H be current latest block number when ready = true
  • retained numeric range excluding genesis is [max(1, H - 8190), H]
  • accepted numeric selector set in light mode when ready is:
    • {0} union [max(1, H - 8190), H]
  • numeric selector outside that set -> -32602
  • selector token pending is recognized but unsupported for light proof-backed reads and returns -32010 (it never aliases latest)
  • selector pending rejection occurs before readiness gating and before retained-window numeric validation
  • ZEVM does not promise archive reads outside retained history

Readiness contract:

  • proof-backed reads are callable only when ready = true
  • when ready = false, all proof-backed reads fail with -32011
  • eth_blockNumber also fails with -32011 while not ready
  • eth_chainId and zevm_lightSyncStatus are callable regardless of readiness (zevm_lightSyncStatus remains light-mode only)
  • ready may transition from false to true only when status transitions to synced after ZEVM has accepted verified optimistic, safe, and finalized heads for the selected network
  • while ready = true, zevm_lightSyncStatus slot coherence must hold: finalizedSlot <= safeSlot <= optimisticSlot
  • selector semantics are unchanged: latest resolves to the optimistic execution head, safe resolves to the consensus-backed safe execution head, and finalized resolves to the consensus-finalized execution head
  • if status leaves synced or slot coherence cannot be maintained, ZEVM must set ready = false in the same state transition before serving subsequent gated RPC calls

Proof failure contract when ready:

  • selector is supported but proof cannot be verified against resolved state root -> -32014
  • upstream proof response malformed -> -32015

TransactionRequest is used by eth_call, eth_estimateGas, and eth_sendTransaction.

Allowed fields only:

FieldTypeRule
fromAddressrequired for eth_sendTransaction; optional for eth_call and eth_estimateGas
toAddress or nullomitted or null for create
gasQuantityHexoptional
gasPriceQuantityHexoptional
valueQuantityHexoptional
nonceQuantityHexoptional
dataHexDataoptional
inputHexDataoptional alias of data

Field rules:

  • data and input may both be omitted
  • if both are present they must be byte-identical, else -32602
  • any field not listed above is invalid and fails with -32602

Fee-model and tx-type constraints:

  • phase-1 request fee field is gasPrice
  • maxFeePerGas, maxPriorityFeePerGas, maxFeePerBlobGas, blobVersionedHashes, accessList, authorizationList, type, and chainId are unsupported in TransactionRequest and fail with -32602
  • if eth_sendTransaction omits gasPrice, ZEVM uses trusted-mode node gas price (eth_gasPrice) at submission time

Submission contract:

  • only legacy transaction type 0x0 is supported in phase 1
  • eth_sendTransaction produces legacy 0x0 transactions
  • eth_sendRawTransaction accepts only legacy raw transactions
  • typed EIP-2718 envelopes (0x1, 0x2, 0x3, or unknown type byte) are unsupported and fail with -32602
  • transaction admission computes intrinsic gas and EIP-3860 initcode limits from the runtime-owned hardfork policy configured at trusted startup

Object keyed by address; each value may include:

FieldType
balanceQuantityHex
nonceQuantityHex
codeHexData
storageobject mapping Bytes32 slot -> Bytes32 value

FeeHistoryResult shape:

{
"oldestBlock": "0x0",
"baseFeePerGas": ["0x3b9aca00", "0x3b9aca00"],
"gasUsedRatio": [0.0],
"reward": [["0x0"]]
}

Field rules:

  • oldestBlock: QuantityHex
  • baseFeePerGas: length N + 1
  • gasUsedRatio: length N
  • reward: optional; when present, length N, each inner array length equals requested percentile count
  • N is the number of returned blocks after truncation (see eth_feeHistory)
{
"type": "0x0",
"hash": "0x...",
"nonce": "0x0",
"blockHash": "0x...",
"blockNumber": "0x0",
"transactionIndex": "0x0",
"from": "0x...",
"to": "0x...",
"value": "0x0",
"gas": "0x5208",
"input": "0x"
}

Rules:

  • type is always 0x0 in phase 1
  • to may be null for create
  • for current phase-1 trusted query methods, blockHash, blockNumber, and transactionIndex are non-null because txpool-only pending entries are not surfaced by eth_getTransactionByHash
  • transaction objects in this contract must not include a nonstandard blockTimestamp field
{
"hash": "0x...",
"parentHash": "0x...",
"sha3Uncles": "0x...",
"miner": "0x...",
"stateRoot": "0x...",
"transactionsRoot": "0x...",
"receiptsRoot": "0x...",
"logsBloom": "0x...",
"number": "0x0",
"gasLimit": "0x0",
"gasUsed": "0x0",
"timestamp": "0x0",
"extraData": "0x",
"mixHash": "0x...",
"nonce": "0x0000000000000000",
"size": "0x0",
"transactions": [],
"uncles": [],
"difficulty": "0x0",
"totalDifficulty": "0x0",
"baseFeePerGas": "0x0",
"withdrawalsRoot": "0x...",
"blobGasUsed": "0x0",
"excessBlobGas": "0x0",
"parentBeaconBlockRoot": "0x..."
}

Rules:

  • transactions is array of Hash32 when fullTransactions=false
  • transactions is array of transaction objects when fullTransactions=true
  • hash and number are non-null for returned canonical blocks
  • nonce is HexData encoding exactly 8 bytes (0x + 16 hex chars)
  • fork-era fields may be omitted when not applicable

Field contract:

FieldRequiredTypeNullability / rule
hashyesHash32non-null for returned block objects
parentHashyesHash32non-null
sha3UnclesyesHash32non-null
mineryesAddressnon-null
stateRootyesHash32non-null
transactionsRootyesHash32non-null
receiptsRootyesHash32non-null
logsBloomyesHexDatanon-null bloom bytes
numberyesQuantityHexnon-null for returned block objects
gasLimityesQuantityHexnon-null
gasUsedyesQuantityHexnon-null
timestampyesQuantityHexnon-null
extraDatayesHexDatanon-null
mixHashyesHash32non-null
nonceyesHexDataexactly 8-byte value
sizeyesQuantityHexnon-null
transactionsyesarrayelement type depends on fullTransactions
unclesyesarray of Hash32non-null (empty array allowed)
difficultyyesQuantityHexnon-null
totalDifficultyyesQuantityHexnon-null
baseFeePerGasconditionalQuantityHexomitted when not applicable
withdrawalsRootconditionalHash32omitted when not applicable
blobGasUsedconditionalQuantityHexomitted when not applicable
excessBlobGasconditionalQuantityHexomitted when not applicable
parentBeaconBlockRootconditionalHash32omitted when not applicable
{
"transactionHash": "0x...",
"transactionIndex": "0x0",
"blockHash": "0x...",
"blockNumber": "0x0",
"from": "0x...",
"to": "0x...",
"cumulativeGasUsed": "0x0",
"gasUsed": "0x0",
"contractAddress": null,
"logs": [],
"logsBloom": "0x...",
"status": "0x1",
"root": null,
"effectiveGasPrice": "0x0",
"type": "0x0",
"blobGasUsed": null,
"blobGasPrice": null
}

Field contract:

FieldRequiredTypeNullability / rule
transactionHashyesHash32non-null
transactionIndexyesQuantityHexnon-null
blockHashyesHash32non-null
blockNumberyesQuantityHexnon-null
fromyesAddressnon-null
toyesAddress or nullnull only for create transactions
cumulativeGasUsedyesQuantityHexnon-null
gasUsedyesQuantityHexnon-null
contractAddressyesAddress or nullnon-null only for create transactions
logsyesarray of log objectsnon-null (empty array allowed)
logsBloomyesHexDatanon-null bloom bytes
statusyesQuantityHexmust be 0x0 or 0x1 in phase 1
rootyesHash32 or nullnull in phase 1
effectiveGasPriceyesQuantityHexnon-null
typeyesQuantityHexalways 0x0 in phase 1
blobGasUsedyesQuantityHex or nullnull in phase 1
blobGasPriceyesQuantityHex or nullnull in phase 1

Rules:

  • receipt objects in this contract must not include a nonstandard blockTimestamp field
{
"removed": false,
"logIndex": "0x0",
"transactionIndex": "0x0",
"transactionHash": "0x...",
"blockHash": "0x...",
"blockNumber": "0x0",
"address": "0x...",
"data": "0x",
"topics": []
}

Field contract:

FieldRequiredTypeNullability / rule
removedyesbooleanalways false for canonical ZEVM responses
logIndexyesQuantityHexnon-null
transactionIndexyesQuantityHexnon-null
transactionHashyesHash32non-null
blockHashyesHash32non-null
blockNumberyesQuantityHexnon-null
addressyesAddressnon-null
datayesHexDatanon-null
topicsyesarray of Hash32non-null (empty array allowed)

Rules:

  • log objects in this contract must not include a nonstandard blockTimestamp field

Allowed fields:

FieldType
fromBlockTrustedBlockSelector
toBlockTrustedBlockSelector
blockHashHash32
addressAddress or array of Address
topicsarray of null, Hash32, or array of Hash32

Rules:

  • blockHash is mutually exclusive with fromBlock and toBlock
  • if both fromBlock and toBlock are present, resolved fromBlock <= toBlock is required
  • if blockHash is provided, ZEVM searches only that canonical block’s logs
  • if blockHash is omitted, default fromBlock is latest and default toBlock is latest
  • when blockHash is omitted, fromBlock and toBlock are resolved with trusted selector semantics (pending, safe, finalized alias latest)
  • address filtering:
    • omitted address matches all emitters
    • single address matches exact emitter address
    • address array is OR semantics across provided addresses
  • topics filtering:
    • topic positions are ANDed by index
    • each topic position entry is either wildcard null, one exact topic, or an OR-array of exact topics
  • result ordering is deterministic ascending: blockNumber, then transactionIndex, then logIndex
  • malformed filters fail with -32602

zevm_lightSyncStatus result:

{
"ready": true,
"status": "synced",
"network": "mainnet",
"checkpointSource": "explicit",
"lastCheckpoint": "0x...",
"optimisticSlot": "0x1234",
"safeSlot": "0x1232",
"finalizedSlot": "0x1230"
}

Field rules:

  • ready: boolean; true only when proof-backed reads are available
  • status: syncing, synced, or error
  • network: mainnet, sepolia, or holesky
  • checkpointSource: startup checkpoint-selection source and stable for process lifetime:
    • explicit: selected from user-provided checkpoint input (CLI --checkpoint or config mode.light.checkpoint)
    • persisted: selected from ${resolvedCheckpointDir}/checkpoint (section 5.3)
    • default: selected from ZEVM bundled release/build default checkpoint for the selected network (deterministic for that release/build artifact, may rotate across releases/builds, and is not a frozen API hash)
  • lastCheckpoint: Hash32, non-null after listener startup
  • optimisticSlot: QuantityHex, non-null
  • safeSlot: QuantityHex, non-null
  • finalizedSlot: QuantityHex, non-null
  • finalizedSlot <= safeSlot <= optimisticSlot
  • effective release/build defaults are auditable by startup with no explicit or persisted checkpoint override; in that case checkpointSource = "default" and lastCheckpoint is the selected default
  • release metadata provenance policy for release/build default claims is defined in PRD section 3.4 (docs/specs/prd.md) and applies unchanged here

Lifecycle contract by status:

statusreadyoptimisticSlot / safeSlot / finalizedSlot
syncingmust be falseall required QuantityHex; may be 0x0 until corresponding headers are available
syncedmust be trueall required QuantityHex representing current optimistic/safe/finalized slots
errormust be falseall required QuantityHex representing last known slots at/just before failure; not nullified

Readiness and head-coherence invariants:

  • ready may transition from false to true only when status transitions to synced after ZEVM has accepted verified optimistic, safe, and finalized heads for the selected network
  • while ready = true, slot coherence must hold: finalizedSlot <= safeSlot <= optimisticSlot
  • if status leaves synced or slot coherence cannot be maintained, ZEVM must set ready = false in the same state transition before serving subsequent gated RPC calls

lastCheckpoint semantics:

  • lastCheckpoint is the most recently accepted checkpoint root in the local light-sync state
  • after successful startup checkpoint selection and validation, it equals the selected startup checkpoint
  • it updates whenever ZEVM accepts a newer checkpoint during sync progression
  • it is not pinned to the configured checkpoint once sync has advanced
  • checkpointSource does not track later lastCheckpoint updates and remains the startup source (explicit, persisted, or default)
MethodExact paramsExact resultErrors
eth_chainId[] or omittedQuantityHex-32602 for non-empty params
eth_blockNumber[] or omittedQuantityHex-32602 for non-empty params
eth_getBalance[address, block]QuantityHex-32602 for malformed address or selector
eth_getCode[address, block]HexData-32602 for malformed address or selector
eth_getStorageAt[address, slot, block]Bytes32-32602 for malformed address, slot, or selector
eth_getTransactionCount[address, block]QuantityHex-32602 for malformed address or selector
eth_accounts[] or omittedarray of the 10 managed trusted-mode addresses in ascending index order-32602 for non-empty params
eth_coinbase[] or omittedAddress-32602 for non-empty params
eth_gasPrice[] or omittedQuantityHex-32602 for non-empty params
eth_maxPriorityFeePerGas[] or omittedQuantityHex-32602 for non-empty params
eth_blobBaseFee[] or omittedQuantityHex-32602 for non-empty params
eth_feeHistory[blockCount, newestBlock] or [blockCount, newestBlock, rewardPercentiles]FeeHistoryResult-32602 on malformed count, selector, or percentiles

Trusted-mode state-backed reads (eth_getBalance, eth_getCode, eth_getStorageAt, and eth_getTransactionCount) are current-head only. latest, pending, safe, and finalized are accepted because they alias the head; earliest is accepted only while the current head is genesis; numeric selectors are accepted only when equal to the current head. Other resolved non-head selectors return -32602.

MethodExact paramsExact resultErrors
eth_call[tx, block] or [tx, block, stateOverrides]HexData-32602 for malformed tx/selectors/overrides; -32603 for runtime execution failure
eth_estimateGas[tx], [tx, block], or [tx, block, stateOverrides]QuantityHex-32602 for malformed tx/selectors/overrides; -32603 for runtime execution failure

Simulation semantics:

  • checkpoint-and-revert execution path
  • no canonical state mutation
  • success path:
    • eth_call returns HexData
    • eth_estimateGas returns QuantityHex
  • runtime execution failure path (for example revert/out-of-gas/invalid execution in simulation context): JSON-RPC error -32603 with message Internal error, no result, and no revert-data result payload
  • omitted transaction field defaults:
    • from: trusted runtime coinbase
    • gas: selected simulation block gas limit
    • gasPrice: trusted runtime gas price
    • value: 0x0
    • nonce: no nonce check
    • data/input: empty bytes
  • create semantics:
    • omitted to or to: null executes the request as contract creation
    • create simulations use the sender’s current nonce for CREATE address and collision semantics
    • created code and the temporary sender nonce increment are reverted before the response
  • gas estimation:
    • computes intrinsic gas for the runtime-owned active hardfork and whether the request is create or call
    • uses the explicit gas value as the upper bound when present; otherwise uses the selected simulation block gas limit
    • rejects upper bounds below intrinsic gas or above the selected block gas limit with -32603
    • requires the upper bound to execute successfully, then binary-searches for the lowest successful gas limit in [intrinsic, upperBound]
  • block environment:
    • current-head simulations use the trusted runtime chain ID, coinbase, head block number, head timestamp, gas limit, base fee, blob base fee, and active one-shot block-environment overrides
    • state-backed simulation is current-head only; selectors that resolve to a non-head block return -32602
    • omitted gas defaults to the selected simulation block gas limit
MethodExact paramsExact resultErrors
eth_sendTransaction[tx] (TransactionRequest)Hash32-32602 malformed request/unsupported fields; -32603 runtime rejection
eth_sendRawTransaction[rawTx]Hash32-32602 malformed hex/decode/unsupported tx type; -32603 runtime rejection

Submission outcome semantics:

  • success: ZEVM accepts submission into trusted runtime and returns the tx hash as result (the tx may be pending or already mined depending on mining mode)
  • runtime rejection: ZEVM returns JSON-RPC error -32603
  • runtime rejection must not include a tx hash result (result is absent)
  • eth_sendTransaction signer scope is managed trusted accounts plus currently impersonated accounts; unmanaged non-impersonated from is a runtime rejection (-32603)
  • unmanaged impersonated eth_sendTransaction uses an unsigned legacy envelope plus explicit sender metadata in the trusted txpool/receipt indexes; txpool content, mined transaction queries, block full-transaction hydration, and receipts must report that metadata sender rather than recovering from zero signature fields
  • phase-1 implementation-defined for runtime rejection: exact reason classification and error.message text
MethodExact paramsExact resultErrors
eth_getBlockByNumber[block, fullTransactions]block object or null-32602 malformed selector/boolean
eth_getBlockByHash[blockHash, fullTransactions]block object or null-32602 malformed hash/boolean
eth_getBlockTransactionCountByHash[blockHash]QuantityHex or null-32602 malformed hash
eth_getBlockTransactionCountByNumber[block]QuantityHex or null-32602 malformed selector
eth_getUncleCountByBlockHash[blockHash]QuantityHex-32602 malformed hash
eth_getUncleCountByBlockNumber[block]QuantityHex-32602 malformed selector
eth_getTransactionByHash[transactionHash]tx object or null-32602 malformed hash
eth_getTransactionByBlockHashAndIndex[blockHash, index]tx object or null-32602 malformed hash/index
eth_getTransactionByBlockNumberAndIndex[block, index]tx object or null-32602 malformed selector/index
eth_getTransactionReceipt[transactionHash]receipt object or null-32602 malformed hash
eth_getBlockReceipts[block] (ReceiptSelector)receipt array or null-32602 malformed selector
eth_getLogs[filter]log array-32602 malformed filter

Query selector behavior:

  • for trusted selector-based queries, pending resolves exactly as latest (compatibility alias only)
  • eth_getBlockByNumber("pending", ...), eth_getBlockTransactionCountByNumber("pending"), eth_getUncleCountByBlockNumber("pending"), eth_getTransactionByBlockNumberAndIndex("pending", ...), and eth_getBlockReceipts("pending") therefore query the current canonical head block, not a separate mempool/pending block
  • eth_getBlockTransactionCountByHash, eth_getBlockTransactionCountByNumber, eth_getTransactionByBlockHashAndIndex, and eth_getTransactionByBlockNumberAndIndex return null when the referenced canonical block is not found
  • eth_getUncleCountByBlockHash and eth_getUncleCountByBlockNumber return 0x0 for unknown blocks and for all ZEVM-produced post-Merge blocks
  • eth_getTransactionByBlockHashAndIndex and eth_getTransactionByBlockNumberAndIndex return null when index is out of range for a found block
  • eth_getTransactionByHash is canonical-mined only and returns null for txpool-only pending entries
  • eth_getTransactionReceipt is mined-only and returns null until inclusion

8.5 Compatibility utility and txpool methods

Section titled “8.5 Compatibility utility and txpool methods”

These methods are intentionally exposed in trusted mode as compatibility helpers. They are trusted-only in phase 1; in light mode, well-formed requests return -32010.

MethodExact paramsExact resultErrors
web3_clientVersion[] or omittedimplementation version string-32602 for non-empty params
web3_sha3[HexData]Keccak-256 Hash32-32602 for malformed hex data
net_version[] or omitteddecimal chain-id string-32602 for non-empty params
net_listening[] or omittedtrue-32602 for non-empty params
net_peerCount[] or omittedQuantityHex peer count; phase-1 trusted mode returns 0x0-32602 for non-empty params
eth_mining[] or omittedboolean; true when mining mode is not manual-32602 for non-empty params
eth_syncing[] or omittedfalse in trusted mode-32602 for non-empty params
eth_protocolVersion[] or omittedprotocol version string; phase-1 trusted mode returns 0x41-32602 for non-empty params
txpool_content[] or omittedgeth-style pending/queued txpool content object-32602 for non-empty params
txpool_status[] or omittedobject with pending and queued QuantityHex counts-32602 for non-empty params
txpool_inspect[] or omittedgeth-style pending/queued summary object-32602 for non-empty params

The Engine API listener is trusted-mode only and disabled unless startup config enables engineRpc or CLI --engine-host / --engine-port.

MethodExact paramsExact resultErrors
engine_exchangeCapabilities[capabilities] where capabilities is an array of stringsarray of implemented Engine method names-32602 for malformed params
engine_exchangeTransitionConfigurationV1[config] where config is an objectobject echo of the supplied transition config-32602 for malformed params
engine_forkchoiceUpdatedV1 / engine_forkchoiceUpdatedV2 / engine_forkchoiceUpdatedV3[forkchoiceState] or [forkchoiceState, null]{ payloadStatus, payloadId: null }-32602 for malformed params or non-null payload attributes

forkchoiceState must include headBlockHash, safeBlockHash, and finalizedBlockHash as Hash32 strings. safeBlockHash and finalizedBlockHash may be zero hashes. A known local headBlockHash returns VALID and updates the canonical head; unknown referenced hashes return SYNCING. Payload building, engine_newPayload*, engine_getPayload*, payload-body methods, and blob/body retrieval are out of phase-1 contract and return -32601 (Method not found) when called.

Accepted aliases in this section are alternative method names for the same ZEVM behavior and payload contract.

AccountState:

{
"balance": "0x0",
"nonce": "0x0",
"code": "0x",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
}

Field contract:

FieldRequiredTypeNullability / rule
balanceyesQuantityHexnon-null
nonceyesQuantityHexnon-null
codeyesHexDatanon-null
storageyesobject mapping Bytes32 -> Bytes32non-null (empty object allowed)

StateBlob:

zevm_dumpState returns HexData whose decoded bytes are UTF-8 JSON with this shape:

{
"version": 1,
"accounts": {
"0x0000000000000000000000000000000000000000": {
"balance": "0x0",
"nonce": "0x0",
"code": "0x",
"storage": {}
}
}
}

Field contract:

FieldRequiredTypeNullability / rule
versionyesintegermust be 1
accountsyesobject mapping Address -> AccountStatenon-null; empty object allowed

Rules:

  • dump output is sorted by address for stable blobs
  • zevm_loadState replaces local account/code/storage state-manager caches with the blob contents
  • zevm_loadState does not mutate fork config, chain metadata, mining config, pending txs, snapshots, receipts, logs, or canonical blocks

MinedBlockSummary:

{
"number": "0x1",
"hash": "0x...",
"timestamp": "0x1"
}

Field contract:

FieldRequiredTypeNullability / rule
numberyesQuantityHexnon-null
hashyesHash32non-null
timestampyesQuantityHexnon-null

NodeMetadata:

{
"mode": "trusted",
"chainId": "0x7a69",
"forking": false,
"forkUrl": null,
"forkBlockNumber": null
}

Field contract:

FieldRequiredTypeNullability / rule
modeyesstring literalalways "trusted"
chainIdyesQuantityHexnon-null
forkingyesbooleannon-null
forkUrlyesstring or nullmust be null when forking=false
forkBlockNumberyesQuantityHex or nullmust be null when forking=false

NodeInfo:

{
"chainId": "0x7a69",
"coinbase": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
"blockNumber": "0x0",
"managedAccounts": [
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
],
"mining": {
"type": "auto",
"blockTime": null
},
"fork": {
"enabled": false,
"url": null,
"blockNumber": null
}
}

Field contract:

FieldRequiredTypeNullability / rule
chainIdyesQuantityHexnon-null
coinbaseyesAddressnon-null
blockNumberyesQuantityHexnon-null
managedAccountsyesarray of Addressnon-null; addresses are returned in managed index order
miningyesobjectnon-null; see nested contract below
forkyesobjectnon-null; see nested contract below

NodeInfo.mining nested contract:

FieldRequiredTypeNullability / rule
typeyesstring enumauto, manual, or interval
blockTimeyesQuantityHex or nullnon-null only when type = "interval"

NodeInfo.fork nested contract:

FieldRequiredTypeNullability / rule
enabledyesbooleannon-null
urlyesstring or nullnon-null only when enabled = true
blockNumberyesQuantityHex or nullnull means fork head; may be non-null only when enabled = true

9.3 Canonical methods and accepted aliases

Section titled “9.3 Canonical methods and accepted aliases”
Canonical methodExact paramsExact resultExact accepted aliases
zevm_getAccount[address] or [address, block]AccountStatenone
zevm_setAccount[address, accountState]truenone
zevm_dumpState[] or omittedHexData state blobanvil_dumpState
zevm_loadState[stateBlob]trueanvil_loadState
zevm_setBalance[address, balance]trueanvil_setBalance, hardhat_setBalance
zevm_addBalance[address, delta]trueanvil_addBalance
zevm_setCode[address, code]trueanvil_setCode, hardhat_setCode
zevm_setNonce[address, nonce]trueanvil_setNonce, hardhat_setNonce
zevm_setStorageAt[address, slot, value]trueanvil_setStorageAt, hardhat_setStorageAt
zevm_setChainId[chainId]trueanvil_setChainId
zevm_getAutomine[] or omittedbooleananvil_getAutomine, hardhat_getAutomine
zevm_setAutomine[enabled]trueanvil_setAutomine, evm_setAutomine
zevm_getIntervalMining[] or omittedQuantityHex seconds, 0x0 when disabledanvil_getIntervalMining
zevm_setIntervalMining[seconds]trueanvil_setIntervalMining, evm_setIntervalMining
zevm_mine[], [count], or [count, intervalSeconds]trueanvil_mine, hardhat_mine, evm_mine
zevm_mineDetailed[], [count], or [count, intervalSeconds]array of MinedBlockSummaryanvil_mineDetailed
zevm_dropTransaction[transactionHash]booleananvil_dropTransaction, hardhat_dropTransaction
zevm_dropAllTransactions[] or omittedQuantityHex removed countanvil_dropAllTransactions
zevm_removePoolTransactions[transactionHashes]QuantityHex removed countanvil_removePoolTransactions
zevm_snapshot[] or omittedQuantityHex snapshot idanvil_snapshot, evm_snapshot
zevm_revert[snapshotId]booleananvil_revert, evm_revert
zevm_impersonateAccount[address]trueanvil_impersonateAccount, hardhat_impersonateAccount
zevm_stopImpersonatingAccount[address]trueanvil_stopImpersonatingAccount, hardhat_stopImpersonatingAccount
zevm_autoImpersonateAccount[enabled]trueanvil_autoImpersonateAccount
zevm_increaseTime[seconds]QuantityHex accumulated offsetanvil_increaseTime, evm_increaseTime
zevm_setNextBlockTimestamp[timestamp]trueanvil_setNextBlockTimestamp, evm_setNextBlockTimestamp
zevm_setTime[timestamp]QuantityHex effective current timestampanvil_setTime
zevm_setBlockTimestampInterval[seconds]trueanvil_setBlockTimestampInterval
zevm_removeBlockTimestampInterval[] or omittedtrueanvil_removeBlockTimestampInterval
zevm_reset[] or omitted, or [forkConfig] where forkConfig is null, { "url": "https://..." }, or { "url": "https://...", "blockNumber": "0x..." }trueanvil_reset, hardhat_reset
zevm_setRpcUrl[url]trueanvil_setRpcUrl
zevm_setCoinbase[address]trueanvil_setCoinbase, hardhat_setCoinbase
zevm_setBlockGasLimit[gasLimit]trueanvil_setBlockGasLimit, evm_setBlockGasLimit
zevm_setNextBlockBaseFeePerGas[baseFee]trueanvil_setNextBlockBaseFeePerGas, hardhat_setNextBlockBaseFeePerGas
zevm_setMinGasPrice[gasPrice]trueanvil_setMinGasPrice, hardhat_setMinGasPrice
zevm_deal[address, value]trueanvil_deal
zevm_dealErc20[token, address, value]trueanvil_dealErc20
zevm_setErc20Allowance[token, owner, spender, value]trueanvil_setErc20Allowance
zevm_metadata[] or omittedNodeMetadataanvil_metadata, hardhat_metadata
zevm_nodeInfo[] or omittedNodeInfoanvil_nodeInfo

Parameter token typing contract (applies to the Exact params column above):

Param tokenTypeContract
address, token, owner, spenderAddresssection 1 Address
blockTrustedBlockSelectorsection 1 TrustedBlockSelector
accountStateAccountStatesection 9.2 AccountState object
stateBlob, codeHexDatasection 1 HexData
slotBytes32section 1 Bytes32
transactionHashHash32section 1 Hash32
transactionHashesarray of Hash32each element must satisfy section 1 Hash32
enabledbooleanJSON boolean
seconds, count, intervalSeconds, chainId, balance, delta, nonce, snapshotId, timestamp, gasLimit, baseFee, gasPrice, valueQuantityHexsection 1 QuantityHex
urlstringnon-empty http:// or https:// URL string
forkConfignull or objectexact forms: null, { "url": "https://..." }, or { "url": "https://...", "blockNumber": "0x..." }; when present, blockNumber is QuantityHex

Rules:

  • methods in this section are trusted-mode only -> -32010 in light mode
  • malformed params -> -32602
  • zevm_revert returns false for unknown snapshot id
  • zevm_dropTransaction returns false if tx is absent
  • zevm_setIntervalMining(["0x0"]) disables interval mining
  • zevm_reset uses QuantityHex for forkConfig.blockNumber; startup CLI/config fork block numbers use decimal u64 (example: startup decimal 1000000 corresponds to JSON-RPC "blockNumber": "0xf4240")
  • zevm_autoImpersonateAccount([enabled]) toggles automatic impersonation mode; signer-scope interaction with manual impersonation is defined in section 9.6
  • snapshot/revert boundary:
    • zevm_snapshot/zevm_revert capture and restore trusted local runtime state (local chain/state/journal, receipt/log indexes, pending tx pool, mining/block-environment overrides, impersonation, and time controls)
    • zevm_snapshot/zevm_revert do not capture light-mode consensus/checkpoint-sync state and do not mutate remote fork-source state
  • call forms:
    • [] or omitted: reset trusted runtime state while keeping current fork configuration unchanged
    • [null]: reset trusted runtime state and disable fork backing
    • [forkConfig] object: reset trusted runtime state and replace fork backing with the provided URL and optional pinned block
  • successful reset always:
    • sets canonical local chain back to trusted genesis (0x0)
    • clears pending transaction pool
    • invalidates previously created snapshot IDs
    • clears impersonation state and one-shot time/timestamp overrides
    • keeps configured startup chainId unchanged
    • keeps the startup/configured hardfork policy unchanged
  • fork config object semantics:
    • { "url": "https://..." }: enable fork backing at upstream head
    • { "url": "https://...", "blockNumber": "0x..." }: enable fork backing pinned to that block
  • if fork initialization fails (for example unreachable upstream or invalid fork block), call fails with -32603
  • exact params: [url] with non-empty http:// or https:// URL string
  • precondition: fork backing is currently enabled; otherwise call fails with -32603
  • effect: updates the active fork upstream URL in place
  • non-effects: does not reset local chain state, does not clear pending pool, and does not invalidate snapshots
  • current fork block pin behavior:
    • if current fork config has blockNumber = null, backing remains at upstream head semantics
    • if current fork config has a pinned blockNumber, that same pin remains active after URL update
  • eth_sendTransaction signer scope is the union of:
    • managed trusted accounts
    • manual impersonation set (zevm_impersonateAccount adds, zevm_stopImpersonatingAccount removes)
    • all addresses when auto impersonation is enabled
  • zevm_autoImpersonateAccount([true]) enables automatic impersonation for any from address
  • zevm_autoImpersonateAccount([false]) disables automatic impersonation; signer scope then falls back to managed accounts plus the current manual impersonation set
  • toggling zevm_autoImpersonateAccount does not clear or mutate manual impersonation entries
  • zevm_stopImpersonatingAccount affects only the manual impersonation set; while auto impersonation is enabled, sends from that address remain allowed
  • unmanaged impersonated eth_sendTransaction persists explicit sender metadata for an unsigned legacy envelope, and all txpool, mined transaction, block hydration, and receipt responses must use that metadata sender
  • pending ordering is nonce-aware per sender
  • when a block is mined, ZEVM includes executable pending transactions in canonical order up to block gas limit
  • non-executable queued transactions remain pending
  • auto:
    • trigger: accepting an executable transaction via eth_sendTransaction or eth_sendRawTransaction
    • effect: immediate single-block mining pass
    • empty blocks: not produced by automine trigger
  • manual:
    • trigger: explicit mine RPC only (zevm_mine, zevm_mineDetailed, aliases)
    • effect: no background mining on tx submission
    • empty blocks: allowed during explicit mine calls
  • interval:
    • trigger: periodic timer every configured blockTime seconds
    • effect: one block per tick
    • empty blocks: allowed and expected when no executable tx is pending
    • lifecycle: startup interval config and zevm_setIntervalMining own exactly one runtime timer; switching to auto/manual or setting interval 0 stops it

Explicit mine calls are valid in all mining modes and mine immediately.

For zevm_mine/zevm_mineDetailed:

  • default params ([]) -> mine exactly 1 block
  • [count] -> mine exactly count blocks
  • [count, intervalSeconds] -> mine exactly count blocks and increment timestamp by intervalSeconds between consecutive mined blocks in that call
  • if pending txs are exhausted before count blocks are mined, remaining blocks are empty

Timestamp invariants:

  • every new block must satisfy timestamp > parent.timestamp
  • timer-mined interval blocks advance by interval cadence
  • explicit multi-block mine calls advance timestamp for each mined block

Timestamp precedence for the next mined block:

  1. one-shot zevm_setNextBlockTimestamp override (must be greater than parent)
  2. explicit intervalSeconds argument for current zevm_mine/zevm_mineDetailed call
  3. zevm_setBlockTimestampInterval override if enabled
  4. interval-mining blockTime when block comes from interval tick
  5. otherwise max(parent.timestamp + 1, effective_current_time)

effective_current_time includes active time offset from zevm_increaseTime and zevm_setTime.

Method: eth_feeHistory

Supported params:

  • [blockCount, newestBlock]
  • [blockCount, newestBlock, rewardPercentiles]

Validation:

  • tuple length must be 2 or 3, else -32602
  • blockCount must decode as QuantityHex and be >= 1, else -32602
  • newestBlock is resolved as a trusted selector
    • pending, safe, finalized resolve as latest
    • earliest resolves as 0
    • numeric selector must resolve to an existing canonical block number, else -32602
  • if rewardPercentiles is present:
    • must be an array
    • length must be <= 100
    • each item must be finite numeric 0 <= p <= 100
    • array must be non-decreasing
    • otherwise -32602

Bounds and truncation:

  • maximum effective blockCount is 1024
  • effectiveCount = min(requestedBlockCount, 1024)
  • result range ends at resolved newestBlock
  • range is truncated at genesis if needed
  • no error is raised for either truncation

Returned range computation:

  • newest = resolved newest block number
  • returnedCount = min(effectiveCount, newest + 1)
  • oldest = newest + 1 - returnedCount

Result construction:

  • oldestBlock = oldest
  • baseFeePerGas has returnedCount + 1 items:
    • one per block in [oldest, newest]
    • plus the next-block base fee after newest
  • gasUsedRatio has returnedCount items, one per block in [oldest, newest]
  • reward behavior:
    • omitted entirely when rewardPercentiles param is absent
    • present when rewardPercentiles is provided (including empty array)
    • outer length is returnedCount
    • each inner array length equals rewardPercentiles.length
    • for empty blocks, all reward entries are 0x0

These are outside the exact phase-1 contract:

Canonical deferred helperDeferred accepted aliases
zevm_enableTracesanvil_enableTraces
zevm_addCompilationResulthardhat_addCompilationResult
zevm_setPrevRandaohardhat_setPrevRandao

hardhat_setLoggingEnabled is deferred as a compatibility alias of zevm_enableTraces.

MethodExact paramsExact resultErrors
zevm_lightSyncStatus[] or omittedlight sync status object-32010 in trusted mode; -32602 for non-empty params
eth_chainId[] or omittedQuantityHex from network mapping (0x1, 0xaa36a7, 0x4268)-32602 for non-empty params
eth_blockNumber[] or omittedQuantityHex-32602 for non-empty params; -32011 while not ready
eth_getBalance[address, block] where block is LightBlockSelectorQuantityHex-32602, -32010, -32011, -32015, -32014
eth_getCode[address, block] where block is LightBlockSelectorHexData-32602, -32010, -32011, -32015, -32014
eth_getStorageAt[address, slot, block] where block is LightBlockSelectorBytes32-32602, -32010, -32011, -32015, -32014
eth_getTransactionCount[address, block] where block is LightBlockSelectorQuantityHex-32602, -32010, -32011, -32015, -32014

Rules:

  • unsupported in light mode (-> -32010) includes:
    • eth_call (trusted-only in phase 1; deferred light-mode proof-backed target)
    • eth_estimateGas
    • eth_feeHistory
    • eth_sendTransaction, eth_sendRawTransaction
    • eth_getBlockByNumber, eth_getBlockByHash
    • eth_getBlockTransactionCountByHash, eth_getBlockTransactionCountByNumber
    • eth_getTransactionByHash, eth_getTransactionByBlockHashAndIndex, eth_getTransactionByBlockNumberAndIndex, eth_getTransactionReceipt
    • eth_getBlockReceipts, eth_getLogs
    • all trusted-mode zevm_* mutation, mining, snapshot/revert, and impersonation controls
  • proof-backed read evaluation order in light mode is exact:
    1. malformed tuple/field/encoding input (including malformed selector token) -> -32602
    2. selector pending -> -32010
    3. ready = false -> -32011 for all remaining selectors, including numeric selectors that would be outside retained history
    4. when ready = true, numeric selector outside retained set {0} union [max(1, H - 8190), H] -> -32602
    5. when ready = true, malformed upstream proof payload -> -32015
    6. when ready = true, well-formed proof payload that fails verification against resolved state root -> -32014
  • while not ready: proof-backed reads and eth_blockNumber fail with -32011 after input validation and selector-support checks
  • once ready: eth_blockNumber returns light-mode latest head number
  • light-mode numeric selector acceptance is exactly the retained-history rule in section 6.2
  • in phase 1, ${resolvedCheckpointDir}/checkpoint is startup input only; lastCheckpoint runtime progression is not persisted to this file
  • phase-1 operator-facing light-mode startup inputs are network, consensusRpcUrl, executionRpcUrl, checkpoint, checkpointDir, maxCheckpointAgeSeconds, and strictCheckpointAge
  • executionRpcUrl is the execution JSON-RPC source used for proof-backed execution reads
  • deferred/out-of-contract method families (for example filter lifecycle beyond eth_getLogs, subscriptions, and debug tracing) are listed in section 14
  • deferred/out-of-contract method names return JSON-RPC -32601 (method not found), not -32010
  • WebSocket transport is unsupported at transport layer (section 3) and is not a JSON-RPC method mapping

Not part of the current contract:

  • debug tracing methods
  • filter lifecycle beyond eth_getLogs
  • subscriptions
  • WebSocket transport

JSON-RPC mapping for this deferred/out-of-contract surface:

  • requesting a deferred/out-of-contract JSON-RPC method name returns -32601 (method not found)
  • WebSocket remains transport-level unsupported (section 3) rather than a JSON-RPC method-level mapping