Monad JSON-RPC Overview

JSON-RPC Overview

Available JSON-RPC methods, behavioral differences from Ethereum, rate limits, and error handling.

Monad exposes a JSON-RPC interface for on-chain interaction. The implementation closely follows Geth conventions, though certain behaviors differ due to Monad's distinct consensus and execution architecture.

Supported methods#

MethodNotes
eth_blockNumber
eth_callGas limits, state availability limits
eth_chainId
eth_createAccessList
eth_estimateGasGas limits
eth_feeHistoryDifference from Ethereum
eth_gasPrice
eth_getBalance
eth_getBlockByHash
eth_getBlockByNumber
eth_getBlockReceipts
eth_getBlockTransactionCountByHash
eth_getBlockTransactionCountByNumber
eth_getCode
eth_getLogsBlock range limits
eth_getStorageAt
eth_getTransactionByBlockHashAndIndex
eth_getTransactionByBlockNumberAndIndex
eth_getTransactionByHashDoes not return pending txs
eth_getTransactionCount
eth_getTransactionReceipt
eth_maxPriorityFeePerGasReturns hardcoded value
eth_sendRawTransactionAsync validation behavior
eth_syncing
eth_subscribeWebSocket only, see WebSocket subscriptions
debug_getRawBlock
debug_getRawHeader
debug_getRawReceipts
debug_getRawTransaction
debug_traceBlockByHashTrace options required
debug_traceBlockByNumberTrace options required
debug_traceCallTrace options required
debug_traceTransactionTrace options required
admin_ethCallStatisticsMonad-specific
net_version
txpool_statusByAddressMonad-specific
txpool_statusByHashMonad-specific
web3_clientVersion

Behavioral differences from Ethereum#

Monad maintains Geth compatibility, yet its architecture — featuring asynchronous execution and sub-second block times — results in notable behavioral differences across several RPC methods.

Transaction lifecycle#

Deferred nonce/balance validation. eth_sendRawTransaction does not always reject transactions with a nonce gap or insufficient gas balance on arrival. Because Monad's RPC layer operates asynchronously, the most recent account state may not yet be available when the transaction is received. Such transactions are tentatively accepted because they can become valid by the time the next block is built.

No pending transaction queries. eth_getTransactionByHash only surfaces transactions that have already been included in a block. Looking up a hash that is still in the mempool returns null.

State availability#

eth_call requests that target historical state (by specifying an older block number) may fail, as full nodes do not retain access to arbitrary past state. Refer to Historical Data for information on available state windows and access methods.

Fee estimation#

eth_maxPriorityFeePerGas currently returns a fixed suggestion of 2 gwei. This is a temporary value and will change in a future release.

eth_feeHistory with newest_block = latest: by convention this method returns fee data for the requested range plus a projected fee for the upcoming block. Because Monad cannot yet determine the next block's base fee at query time, the most recent baseFeePerGas is repeated as the projection when latest is requested.

Debug / tracing#

Trace options parameter is required. debug_traceCall, debug_traceTransaction, and other debug_trace* endpoints expect the trace options object to be passed explicitly. In contrast to standard EVM clients, where this parameter can be omitted, Monad RPC responds with -32602 Invalid params when it is missing. Always supply the object, even if empty:

{
  "method": "debug_traceCall",
  "params": [
    {
      "to": "0x6b175474e89094c44da98b954eedeac495271d0f"
    },
    "latest",
    {}
  ]
}

Default tracer is callTracer. When an empty trace options object {} is passed, Monad uses callTracer by default rather than the struct-log tracer common in other EVM clients. Opcode-level struct logs are not currently available on Monad's VM.

Unsupported features#

FeatureAffected methodsDetails
EIP-4844 (blob transactions)eth_sendRawTransaction, eth_call, eth_estimateGasBlob transaction type is rejected
syncing subscriptioneth_subscribeNot supported
newPendingTransactions subscriptioneth_subscribeNot supported

Limits#

eth_call / eth_estimateGas#

Gas limit per call#

ProviderPublic RPCGas limit
QuickNoderpc.monad.xyz200M gas
Alchemyrpc1.monad.xyz200M gas
Ankrrpc3.monad.xyz1B gas
Monad Foundationrpc-mainnet.monadinfra.com200M gas

Node operators can adjust these caps with --eth-call-provider-gas-limit (default 30M) and --eth-estimate-gas-provider-gas-limit (default 30M).

Gas limit resolution#

If the caller sets a gas price (gasPrice or maxFeePerGas), the effective gas limit becomes min(gas limit allowance, provider gas limit) — the gas limit allowance being the maximum gas affordable given the caller's balance and the specified price. Without a gas price, the provider gas limit is used as-is. This matches Geth's behaviour.

Dual-pool execution model#

Incoming eth_call and eth_estimateGas requests are dispatched to one of two execution pools depending on the gas limit specified by the caller:

PoolGas limitPurpose
Low-gas≤ 8,100,000Most calls; higher throughput
High-gas> 8,100,000Large simulations; limited concurrency

When no gas limit is provided, the request first runs in the low-gas pool. If execution exceeds the pool's gas cap, it is automatically retried in the high-gas pool.

Node operators can tune pool concurrency with --eth-call-max-concurrent-requests (default 1000) and --eth-call-high-max-concurrent-requests (default 20).

eth_getLogs#

Block range limit per call#

ProviderPublic RPCBlock range limit
QuickNoderpc.monad.xyz100 blocks
Alchemyrpc1.monad.xyz1,000 blocks and 10,000 logs (whichever is more constraining)
Ankrrpc3.monad.xyz1,000 blocks
Monad Foundationrpc-mainnet.monadinfra.com100 blocks

Node operators can set the range cap with --eth-get-logs-max-block-range.

Why are block range limits low?#

Monad produces a block roughly every 400 ms, each capable of holding up to 5,000 transactions and 200M gas of computation. Because blocks arrive far more frequently and carry substantially more data than Ethereum blocks, per-call range limits are kept intentionally tight.

Errors#

Monad's JSON-RPC error codes follow Ethereum conventions where possible, though some values differ because error codes are not fully standardized across Ethereum clients.

Request-level errors (-32601)#

MessageExplanationCommon cause
Parse errorUnable to parse the JSON-RPC requestMalformed JSON
Invalid requestThe request is structurally invalidRequest exceeds size limit
Method not foundThe method is not part of the JSON-RPC specTypo in method name
Method not supportedThe method exists in the spec but is not yet supported by MonadCalling an unimplemented method

Parameter errors (-32602)#

MessageExplanationCommon cause
Invalid block rangeThe requested eth_getLogs block range exceeds the provider limitSee block range limits
Invalid paramsIncorrect parameters for the methodWrong types, missing required fields, omitted trace options

Execution errors (-32603)#

MessageExplanationCommon cause
Internal errorThe request could not be fulfilledServer-side failure
Execution revertedThe simulated transaction revertedFailed eth_call or eth_estimateGas
Transaction decoding errorThe raw transaction could not be decodedInvalid RLP in eth_sendRawTransaction

WebSocket subscriptions#

Monad's RPC server accepts JSON-RPC connections over WebSocket, providing persistent channels for real-time event streaming through eth_subscribe. Refer to the Geth documentation for general eth_subscribe semantics. In addition to the standard types, Monad offers two speculative subscription variants — monadNewHeads and monadLogs — that deliver data roughly one second sooner on average by leveraging speculative execution. See Speculative Real-Time Data for background and Block States for the full block lifecycle.

Subscription types#

TypeFires when
newHeadsA new header is appended, once the block is Voted
logsMatching logs appear in a new block, once the block is Voted
monadNewHeadsA new header is available, once the block is Proposed and speculatively executed
monadLogsMatching logs are available, once the block is Proposed and speculatively executed

The syncing and newPendingTransactions subscription types are not available.

Speculative subscription behavior#

monadNewHeads and monadLogs notifications carry two extra fields that the standard variants do not include:

  • blockId — a unique identifier for this particular block proposal (separate from the block number, because several proposals may exist at the same height).
  • commitState — the block's current commit state: Proposed, Voted, Finalized, or Verified.

A single block typically generates multiple notifications as its commitState progresses through the lifecycle. A block can jump directly from Proposed to Finalized, bypassing Voted, when consensus runs ahead of execution. If a block ultimately fails to finalize, no explicit cancellation event is emitted — finalization of a different block at the same height implicitly supersedes it.