> ## Documentation Index
> Fetch the complete documentation index at: https://seilabs-docs-evm-cookbook.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Sei EVM JSON-RPC API Reference

> Comprehensive reference documentation for Sei's EVM JSON-RPC API endpoints, including standard Ethereum methods and Sei-specific extensions for developers.

export const RPCMethodsViewer = () => {
  const NETWORKS = {
    mainnet: {
      label: 'Sei Mainnet',
      chainId: '1329',
      http: 'https://evm-rpc.sei-apis.com',
      ws: 'wss://evm-ws.sei-apis.com'
    },
    testnet: {
      label: 'Sei Testnet',
      chainId: '1328',
      http: 'https://evm-rpc-testnet.sei-apis.com',
      ws: 'wss://evm-ws-testnet.sei-apis.com'
    }
  };
  const NAMESPACE_META = {
    eth: {
      label: 'eth',
      color: '#b05c6c',
      blurb: 'Standard Ethereum methods for accounts, balances, blocks, transactions, logs, calls, and filters.'
    },
    debug: {
      label: 'debug',
      color: '#966f22',
      blurb: 'Transaction and block tracing.'
    },
    txpool: {
      label: 'txpool',
      color: '#3b82f6',
      blurb: 'Transaction-pool inspection.'
    },
    net: {
      label: 'net',
      color: '#0d9488',
      blurb: 'Network metadata.'
    },
    web3: {
      label: 'web3',
      color: '#7c3aed',
      blurb: 'Client metadata.'
    },
    sei: {
      label: 'sei',
      color: '#600014',
      colorDark: '#b99ba1',
      blurb: 'Remaining legacy Sei extensions for address resolution, cross-VM lookup, and synthetic receipts.',
      deprecated: true
    },
    admin: {
      label: 'admin',
      color: '#6b7280',
      blurb: 'Node administration is not exposed on Sei.',
      unavailable: true
    },
    miner: {
      label: 'miner',
      color: '#6b7280',
      blurb: 'Mining control is not applicable (no proof-of-work).',
      unavailable: true
    },
    clique: {
      label: 'clique',
      color: '#6b7280',
      blurb: 'Clique proof-of-authority is not applicable (CometBFT consensus).',
      unavailable: true
    },
    engine: {
      label: 'engine',
      color: '#6b7280',
      blurb: 'The Consensus Engine API is not applicable (CometBFT consensus).',
      unavailable: true
    },
    les: {
      label: 'les',
      color: '#6b7280',
      blurb: 'The Light Ethereum Subprotocol is not exposed on Sei.',
      unavailable: true
    },
    personal: {
      label: 'personal',
      color: '#6b7280',
      blurb: 'Hosted-key account management is not exposed on Sei.',
      unavailable: true
    }
  };
  const NAMESPACE_ORDER = ['eth', 'debug', 'txpool', 'net', 'web3', 'sei', 'admin', 'miner', 'clique', 'engine', 'les', 'personal'];
  const STATUS_META = {
    supported: {
      label: 'Supported',
      dark: '#22c55e',
      light: '#16a34a',
      tip: 'Implemented with standard Ethereum behavior.'
    },
    limited: {
      label: 'Limited',
      dark: '#f59e0b',
      light: '#b45309',
      tip: 'Works, but is deprecated, returns a static value, or has a Sei-specific caveat.'
    },
    unsupported: {
      label: 'Unavailable',
      dark: '#9ca3af',
      light: '#6b7280',
      tip: 'Not registered on Sei, explicitly errors, or not applicable to the Sei architecture.'
    }
  };
  const LANGUAGES = [{
    id: 'curl',
    name: 'cURL'
  }, {
    id: 'cast',
    name: 'cast'
  }, {
    id: 'javascript',
    name: 'JavaScript'
  }, {
    id: 'typescript',
    name: 'TypeScript'
  }, {
    id: 'python',
    name: 'Python'
  }, {
    id: 'go',
    name: 'Go'
  }, {
    id: 'rust',
    name: 'Rust'
  }, {
    id: 'java',
    name: 'Java'
  }, {
    id: 'kotlin',
    name: 'Kotlin'
  }, {
    id: 'swift',
    name: 'Swift'
  }, {
    id: 'csharp',
    name: 'C#'
  }];
  const SEI_RPC_METHODS = [{
    "namespace": "eth",
    "name": "eth_blockNumber",
    "status": "supported",
    "description": "Returns the number of the most recent committed EVM block as a hex uint64.",
    "seiNote": "Block height comes from the CometBFT latest height. The latest committed block is already final on Sei (instant finality, so latest == safe == finalized)."
  }, {
    "namespace": "eth",
    "name": "eth_chainId",
    "status": "supported",
    "description": "Returns the EVM chain ID as a hex big int.",
    "seiNote": "The chain ID comes from the x/evm keeper. Sei Mainnet = 1329 (0x531). Sei Testnet = 1328 (0x530)."
  }, {
    "namespace": "eth",
    "name": "eth_coinbase",
    "status": "limited",
    "description": "Returns the block reward beneficiary (coinbase) address.",
    "seiNote": "Sei has no miner. This method returns the Cosmos fee-collector module address (GetFeeCollectorAddress), not a validator or miner address. The COINBASE opcode returns the same value."
  }, {
    "namespace": "eth",
    "name": "eth_accounts",
    "status": "limited",
    "description": "Returns the list of addresses for which the node holds hosted keys.",
    "seiNote": "The list comes only from the node's local test keyring. Production and public RPC nodes hold no hosted keys, so this method returns an empty list. Sign client-side and use eth_sendRawTransaction."
  }, {
    "namespace": "eth",
    "name": "eth_gasPrice",
    "status": "limited",
    "description": "Returns a suggested gas price in wei (hex).",
    "seiNote": "The price comes from a Sei-specific congestion heuristic, not a raw mempool oracle. InfoAPI.GasPrice/GasPriceHelper (info.go) returns baseFee * 110/100 (base fee +10%) when the chain is uncongested. When the chain is congested, it returns medianRewardPrevBlock + baseFee (the 50th-percentile priority-fee reward from the previous block, added to the base fee). The base fee comes from the x/evm keeper (GetNextBaseFeePerGas), which is itself floored at the governance-set minimum base fee. The RPC handler applies no other explicit lower-bound clamp. The mainnet minimum gas price (approximately 50 gwei) is enforced for transaction acceptance at the mempool and ante-handler level, not inside eth_gasPrice."
  }, {
    "namespace": "eth",
    "name": "eth_maxPriorityFeePerGas",
    "status": "limited",
    "description": "Returns a suggested priority fee (tip) per gas in wei (hex).",
    "seiNote": "Returns a hardcoded 1 gwei (defaultPriorityFeePerGas) when the chain is uncongested. It derives the tip from the previous block's 50th-percentile reward only when the chain is congested. Sei docs advise using a single gasPrice and omitting EIP-1559 fee fields."
  }, {
    "namespace": "eth",
    "name": "eth_feeHistory",
    "status": "supported",
    "description": "Returns base fees, gas-used ratios, and reward percentile data over a range of blocks.",
    "seiNote": "Base fees and rewards reflect Sei's x/evm fee market (GetNextBaseFee), not an Ethereum EIP-1559 mempool. Sei does not burn the base fee. The method is watermark-aware, so pruned or historical blocks may not be available as far back as on Ethereum archive nodes.",
    "params": [{
      "name": "blockCount",
      "type": "QUANTITY",
      "description": "Number of blocks in the requested range.",
      "example": "0x5"
    }, {
      "name": "newestBlock",
      "type": "BLOCKNUMBER",
      "description": "Highest block of the range (number or tag).",
      "example": "latest"
    }, {
      "name": "rewardPercentiles",
      "type": "array of float",
      "description": "Monotonically increasing percentiles to sample for priority-fee rewards.",
      "example": "[25,50,75]"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_blobBaseFee",
    "status": "unsupported",
    "description": "Returns the EIP-4844 blob base fee. Sei registers this method, but it always returns an unsupported error.",
    "seiNote": "Always returns JSON-RPC error -32000 with the message 'blobs not supported on this chain'. Sei does not implement EIP-4844 blob transactions."
  }, {
    "namespace": "eth",
    "name": "eth_syncing",
    "status": "unsupported",
    "description": "Returns the sync status. Sei registers this method, but it always returns an unsupported error instead of false or a sync object.",
    "seiNote": "InfoAPI.Syncing returns a JSON-RPC error with the exact message 'eth_syncing is not supported on Sei EVM RPC' (from ErrEVMNotSupported, code -32000, not -32601). Sei does not expose Ethereum sync semantics here. Query CometBFT status endpoints instead."
  }, {
    "namespace": "eth",
    "name": "eth_getBalance",
    "status": "supported",
    "description": "Returns the wei balance of an account at a given block.",
    "seiNote": "The balance reflects the account's SEI bank balance (18-decimal wei representation). Both EVM and non-EVM (Cosmos bank send or wasm) transactions can change it. The watermark manager resolves the height with a state-version guard.",
    "params": [{
      "name": "address",
      "type": "DATA, 20 bytes",
      "description": "Account address.",
      "example": "0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55"
    }, {
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Block number, tag (latest/earliest/pending/safe/finalized), or hash.",
      "example": "latest"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getCode",
    "status": "supported",
    "description": "Returns the contract bytecode at an address for a given block.",
    "params": [{
      "name": "address",
      "type": "DATA, 20 bytes",
      "description": "Contract address.",
      "example": "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7"
    }, {
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Block number, tag, or hash.",
      "example": "latest"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getStorageAt",
    "status": "supported",
    "description": "Returns the value stored at a storage slot of an address at a given block.",
    "seiNote": "Reads the EVM keeper's slot value directly rather than from an MPT trie. The slot key must decode to at most 32 bytes.",
    "params": [{
      "name": "address",
      "type": "DATA, 20 bytes",
      "description": "Contract address.",
      "example": "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7"
    }, {
      "name": "key",
      "type": "DATA, 32 bytes",
      "description": "Storage slot key (hex, up to 32 bytes).",
      "example": "0x0"
    }, {
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Block number, tag, or hash.",
      "example": "latest"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getProof",
    "status": "limited",
    "description": "Returns a Merkle proof for an account and the requested storage slots.",
    "seiNote": "Sei stores state in an IAVL tree, not an Ethereum Merkle-Patricia trie. The result is a Sei-specific ProofResult{address, hexValues, storageProof}. Its storageProof entries are CometBFT/IAVL crypto.ProofOps, NOT eth-style MPT proof nodes. There is no accountProof, balance, codeHash, nonce, or storageHash field (Sei has no per-account state root). Standard eth_getProof verifiers do not work.",
    "params": [{
      "name": "address",
      "type": "DATA, 20 bytes",
      "description": "Account address.",
      "example": "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7"
    }, {
      "name": "storageKeys",
      "type": "array of DATA, 32 bytes",
      "description": "Storage slot keys to prove (bounded by MaxStorageKeysPerProof).",
      "example": "[\"0x0\"]"
    }, {
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Block number, tag, or hash.",
      "example": "latest"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getNonce",
    "status": "limited",
    "description": "Sei-specific helper that returns the current EVM nonce for an address (latest state only).",
    "seiNote": "This non-standard Sei extension is exposed as eth_getNonce and implemented as StateAPI.GetNonce in state.go (NOT on TransactionAPI). Unlike eth_getTransactionCount, it takes no block tag (latest only, through ctxProvider(LatestCtxHeight)) and returns a bare uint64. Prefer eth_getTransactionCount for standard nonce queries.",
    "params": [{
      "name": "address",
      "type": "DATA, 20 bytes",
      "description": "Account address.",
      "example": "0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_call",
    "status": "supported",
    "description": "Executes a read-only message call against state without creating a transaction. Supports state and block overrides.",
    "seiNote": "RPCGasCap caps gas, and RPCEVMTimeout caps execution time. A fail-fast limiter may reject the call with 'eth_call rejected due to rate limit: server busy'. Canonical EVM<->Sei address resolution uses eth_call to the addr precompile at 0x0000000000000000000000000000000000001004.",
    "params": [{
      "name": "args",
      "type": "object",
      "description": "Call object (to, from, data/input, gas, gasPrice/maxFeePerGas, value).",
      "example": "{\"to\":\"0x0000000000000000000000000000000000001004\",\"data\":\"0x0c3c20ed000000000000000000000000Da52B9E673d1f48FcD9916b3F606A136a8eA5e55\"}"
    }, {
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Block number, tag, or hash. Defaults to latest.",
      "example": "latest"
    }, {
      "name": "overrides",
      "type": "object",
      "description": "Optional per-account state overrides (balance, code, nonce, state).",
      "example": "{}"
    }, {
      "name": "blockOverrides",
      "type": "object",
      "description": "Optional block-context overrides (number, time, coinbase).",
      "example": "{}"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_estimateGas",
    "status": "supported",
    "description": "Estimates the gas needed to execute a transaction.",
    "seiNote": "RPCGasCap bounds this method, and a fail-fast limiter protects it. The block gas limit on Sei is 12.5M. Parallel execution can cause estimates to vary slightly, so size gasLimit with a modest buffer.",
    "params": [{
      "name": "args",
      "type": "object",
      "description": "Transaction call object.",
      "example": "{\"to\":\"0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7\",\"data\":\"0x18160ddd\"}"
    }, {
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Optional block number, tag, or hash. Defaults to latest.",
      "example": "latest"
    }, {
      "name": "overrides",
      "type": "object",
      "description": "Optional state overrides.",
      "example": "{}"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_estimateGasAfterCalls",
    "status": "limited",
    "description": "Estimates gas for a transaction after first applying a sequence of preceding calls against the same simulated state.",
    "seiNote": "This is a non-standard Sei/geth extension (not part of the standard Ethereum JSON-RPC spec). It has the same gas-cap and fail-fast-limiter behavior as eth_estimateGas.",
    "params": [{
      "name": "args",
      "type": "object",
      "description": "The final call to estimate gas for.",
      "example": "{\"to\":\"0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7\",\"data\":\"0x\"}"
    }, {
      "name": "calls",
      "type": "array of object",
      "description": "Ordered list of preceding calls applied before the estimate.",
      "example": "[]"
    }, {
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Optional block number, tag, or hash. Defaults to latest.",
      "example": "latest"
    }, {
      "name": "overrides",
      "type": "object",
      "description": "Optional state overrides.",
      "example": "{}"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_createAccessList",
    "status": "supported",
    "description": "Generates an EIP-2930 access list (and gas used) for a transaction.",
    "seiNote": "Defaults to the pending block tag (matching geth). A VM error during simulation appears in the result's 'error' field instead of failing the RPC.",
    "params": [{
      "name": "args",
      "type": "object",
      "description": "Transaction call object.",
      "example": "{\"to\":\"0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7\",\"data\":\"0x\"}"
    }, {
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Optional block number, tag, or hash. Defaults to pending.",
      "example": "pending"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_sendRawTransaction",
    "status": "supported",
    "description": "Submits a signed, RLP-encoded raw EVM transaction to the network and returns its hash.",
    "seiNote": "Decodes the bytes to an ethtypes.Transaction, wraps it in a Cosmos MsgEVMTransaction, and broadcasts it through CometBFT. By default, it uses a CheckTx-level BroadcastTx (that is, broadcast_tx_sync), and slow mode uses BroadcastTxCommit. Non-zero CheckTx codes are returned as ABCI errors, not geth mempool errors. Legacy (non-1559) transactions must set gasPrice at or above the governance minimum (currently 50 gwei on Sei Mainnet). Blob (EIP-4844) transactions are not enabled. The method supports per-sender EvmProxy forwarding.",
    "params": [{
      "name": "data",
      "type": "DATA",
      "description": "Signed, RLP-encoded transaction bytes (0x-prefixed).",
      "example": "0x02f8b101808459682f00..."
    }]
  }, {
    "namespace": "eth",
    "name": "eth_sendTransaction",
    "status": "limited",
    "description": "Signs (with a node-hosted key) and submits a transaction in one call.",
    "seiNote": "Requires the 'from' address's private key in the node's local test keyring. Production and public RPC nodes hold no hosted keys, so this method returns 'from address does not have hosted key'. Always signs as LegacyTxType. Sign client-side and use eth_sendRawTransaction instead.",
    "params": [{
      "name": "args",
      "type": "object",
      "description": "Transaction object (from, to, value, data, gas, nonce, and other fields).",
      "example": "{\"from\":\"0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55\",\"to\":\"0x7507454444fa193d39f1392076bc784b77a7a8ff\",\"value\":\"0x1\"}"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_signTransaction",
    "status": "limited",
    "description": "Signs a transaction with a node-hosted key and returns the signed payload without broadcasting.",
    "seiNote": "Requires a node-hosted key for the from address. It does not work on public RPC nodes that hold no keys. Returns both the raw RLP bytes and the decoded tx.",
    "params": [{
      "name": "args",
      "type": "object",
      "description": "SendTxArgs transaction object to sign (from, to, gas, gasPrice, value, nonce, data).",
      "example": "{\"from\":\"0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55\",\"to\":\"0x7507454444fa193d39f1392076bc784b77a7a8ff\",\"value\":\"0x1\",\"nonce\":\"0x0\",\"gas\":\"0x5208\",\"gasPrice\":\"0x3b9aca00\"}"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_sign",
    "status": "limited",
    "description": "Signs an EIP-191 personal message with a node-hosted key for the given address.",
    "seiNote": "Only works for addresses in the node's local test keyring. Production and public RPC nodes hold no hosted keys, so this method returns 'address does not have hosted key'. Applies the EIP-191 personal-message TextHash before signing.",
    "params": [{
      "name": "address",
      "type": "DATA, 20 bytes",
      "description": "Address whose hosted key signs the data.",
      "example": "0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55"
    }, {
      "name": "data",
      "type": "DATA",
      "description": "Message bytes to sign.",
      "example": "0xdeadbeef"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getBlockByNumber",
    "status": "supported",
    "description": "Returns block information by number or tag, with full transactions when fullTx is true.",
    "seiNote": "Under the eth namespace, only EVM transactions are indexed (synthetic and bank-transfer txs are excluded). Block number 0 returns a synthetic genesis block (for The Graph compatibility). Future or non-existent numeric blocks return null. Uncle and PoW header fields (sha3Uncles, nonce, mixHash, difficulty) are placeholders, and the uncles array is always empty (CometBFT consensus). The safe, finalized, and latest tags are equivalent because of instant finality.",
    "params": [{
      "name": "number",
      "type": "BLOCKNUMBER",
      "description": "Block number (hex) or tag (latest/safe/finalized/pending/earliest).",
      "example": "latest"
    }, {
      "name": "fullTx",
      "type": "boolean",
      "description": "If true, the block includes full transaction objects. If false, it includes only hashes.",
      "example": "true"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getBlockByHash",
    "status": "supported",
    "description": "Returns block information by block hash, with full transactions when fullTx is true.",
    "seiNote": "Block hashes are CometBFT block hashes (computed from the Tendermint header), so they differ from Ethereum block hashes and are not interchangeable across chains. Under the eth namespace, synthetic txs and bank transfers are excluded. The genesis hash returns a synthetic genesis block. An unknown or zero hash returns null. The uncles array is always empty.",
    "params": [{
      "name": "blockHash",
      "type": "DATA, 32 bytes",
      "description": "Block hash.",
      "example": "0x5620c15afd9a1d0ab19d7560043df6e038d731c6205974dca7a55900071e3864"
    }, {
      "name": "fullTx",
      "type": "boolean",
      "description": "If true, the block includes full transaction objects. If false, it includes only hashes.",
      "example": "false"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getBlockTransactionCountByNumber",
    "status": "supported",
    "description": "Returns the number of EVM transactions in a block by number, as a hex quantity.",
    "seiNote": "Counts EVM transactions only (through getEvmTxCount). Synthetic and bank-transfer txs are excluded. Genesis returns 0x0. Non-existent or future blocks return null.",
    "params": [{
      "name": "number",
      "type": "BLOCKNUMBER",
      "description": "Block number or tag.",
      "example": "latest"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getBlockTransactionCountByHash",
    "status": "supported",
    "description": "Returns the number of EVM transactions in a block by hash, as a hex quantity.",
    "seiNote": "Counts EVM transactions only. Synthetic and bank-transfer txs are excluded. The genesis hash returns 0x0. An unknown hash returns null.",
    "params": [{
      "name": "blockHash",
      "type": "DATA, 32 bytes",
      "description": "Block hash.",
      "example": "0x5620c15afd9a1d0ab19d7560043df6e038d731c6205974dca7a55900071e3864"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getBlockReceipts",
    "status": "supported",
    "description": "Returns all EVM transaction receipts for a given block.",
    "seiNote": "Under the eth namespace, synthetic and shell receipts are excluded (includeShellReceipts=false). Genesis returns an empty array. A zero hash returns null. transactionIndex is recomputed sequentially over the compacted receipt list.",
    "params": [{
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Block number, tag, or hash.",
      "example": "latest"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getTransactionByHash",
    "status": "supported",
    "description": "Returns the EVM transaction matching the given hash, or null if not found.",
    "seiNote": "Sees EVM transactions only. If the hash resolves to a non-EVM Cosmos tx, it returns an error. Pending lookups read from the CometBFT mempool, not a geth txpool.",
    "params": [{
      "name": "hash",
      "type": "DATA, 32 bytes",
      "description": "Transaction hash.",
      "example": "0x828c91592453fe7c5bf743204495a35bf02b67b579b8f59ee7eea8af031d7c14"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getTransactionReceipt",
    "status": "supported",
    "description": "Returns the receipt of a transaction by hash, or null if not found.",
    "seiNote": "The receipt is reconstructed from keeper.GetReceipt and CometBFT block data, not from a native MPT receipt trie. Status and logs use the standard Ethereum format.",
    "params": [{
      "name": "hash",
      "type": "DATA, 32 bytes",
      "description": "Transaction hash.",
      "example": "0x828c91592453fe7c5bf743204495a35bf02b67b579b8f59ee7eea8af031d7c14"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getTransactionByBlockNumberAndIndex",
    "status": "supported",
    "description": "Returns the EVM transaction at the given index within the block at the specified number.",
    "seiNote": "Index maps over EVM transactions only. An out-of-range index returns a null result, not an error.",
    "params": [{
      "name": "blockNr",
      "type": "BLOCKNUMBER",
      "description": "Block number or tag.",
      "example": "latest"
    }, {
      "name": "index",
      "type": "QUANTITY",
      "description": "Transaction index within the block.",
      "example": "0x0"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getTransactionByBlockHashAndIndex",
    "status": "supported",
    "description": "Returns the EVM transaction at the given index within the block identified by hash.",
    "seiNote": "Index maps over EVM transactions only. It has the same null-on-overflow semantics as the block-number variant.",
    "params": [{
      "name": "blockHash",
      "type": "DATA, 32 bytes",
      "description": "Block hash.",
      "example": "0x5620c15afd9a1d0ab19d7560043df6e038d731c6205974dca7a55900071e3864"
    }, {
      "name": "index",
      "type": "QUANTITY",
      "description": "Transaction index within the block.",
      "example": "0x0"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getTransactionCount",
    "status": "supported",
    "description": "Returns the number of transactions sent from an address (nonce) at a given block.",
    "seiNote": "For the 'pending' tag, Sei returns EvmNextPendingNonce from the CometBFT mempool (or redirects to an EvmProxy if the sender is sharded there). The safe, finalized, and latest tags are equivalent because of instant finality.",
    "params": [{
      "name": "address",
      "type": "DATA, 20 bytes",
      "description": "Account address.",
      "example": "0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55"
    }, {
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Block number, tag, or hash. The 'pending' tag returns the next pending nonce.",
      "example": "latest"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getVMError",
    "status": "limited",
    "description": "Sei extension that returns the EVM VM error string recorded in a transaction's receipt by hash.",
    "seiNote": "This non-standard Sei extension is registered under the eth namespace. Returns the receipt's VmError field and propagates a not-found error (unlike eth_getTransactionErrorByHash, which returns an empty string on not-found).",
    "params": [{
      "name": "hash",
      "type": "DATA, 32 bytes",
      "description": "Transaction hash.",
      "example": "0x828c91592453fe7c5bf743204495a35bf02b67b579b8f59ee7eea8af031d7c14"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getTransactionErrorByHash",
    "status": "limited",
    "description": "Sei extension that returns the recorded VM error string for a transaction by hash (empty string if it succeeded or is not found).",
    "seiNote": "This non-standard Sei extension is registered under the eth namespace. Unlike eth_getVMError, a not-found lookup returns an empty string and no error.",
    "params": [{
      "name": "hash",
      "type": "DATA, 32 bytes",
      "description": "Transaction hash.",
      "example": "0x828c91592453fe7c5bf743204495a35bf02b67b579b8f59ee7eea8af031d7c14"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_newFilter",
    "status": "supported",
    "description": "Creates a log filter for the given criteria and returns a filter ID for later polling.",
    "seiNote": "It has the same range and size caps as eth_getLogs. Open-ended ranges return up to 10,000 logs (DefaultMaxLogLimit). Close-ended ranges are limited to 2,000 blocks (DefaultMaxBlockRange), with large-query rate limiting.",
    "params": [{
      "name": "crit",
      "type": "object",
      "description": "Filter criteria: fromBlock, toBlock (or blockHash), address(es), and topics.",
      "example": "{\"fromBlock\":\"latest\",\"address\":\"0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7\",\"topics\":[]}"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_newBlockFilter",
    "status": "supported",
    "description": "Creates a filter that tracks newly arrived block hashes and returns its ID."
  }, {
    "namespace": "eth",
    "name": "eth_newPendingTransactionFilter",
    "status": "unsupported",
    "description": "Creates a pending-transaction filter. Sei registers this method, but it always returns an unsupported error.",
    "seiNote": "Always returns JSON-RPC -32000. Sei has no geth-style public pending mempool to filter. The corresponding newPendingTransactions subscription type is also unavailable."
  }, {
    "namespace": "eth",
    "name": "eth_getFilterChanges",
    "status": "supported",
    "description": "Polls a filter and returns new logs (log filters) or block hashes (block filters) since the last poll.",
    "params": [{
      "name": "filterID",
      "type": "QUANTITY/ID",
      "description": "Filter ID from a New*Filter call.",
      "example": "0x1"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getFilterLogs",
    "status": "supported",
    "description": "Returns all logs matching a previously created log filter, including historical logs.",
    "seiNote": "Bounded by the same caps as eth_getLogs (2,000-block range, 10,000-log limit) with large-query rate limiting.",
    "params": [{
      "name": "filterID",
      "type": "QUANTITY/ID",
      "description": "Filter ID from a NewFilter call.",
      "example": "0x1"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getLogs",
    "status": "supported",
    "description": "Returns logs matching the given filter criteria.",
    "seiNote": "Returns EVM logs only. Hard limits: a maximum of 2,000 blocks per close-ended query and up to 10,000 logs per response. A query that exceeds the range returns the error 'block range too large'. Large queries are globally rate-limited.",
    "params": [{
      "name": "crit",
      "type": "object",
      "description": "Filter criteria: fromBlock, toBlock (or blockHash), address(es), topics.",
      "example": "{\"fromBlock\":\"0x0\",\"toBlock\":\"latest\",\"address\":\"0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7\",\"topics\":[]}"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_uninstallFilter",
    "status": "supported",
    "description": "Removes a previously installed filter by ID. Returns true if the filter existed and was removed.",
    "seiNote": "Returns false instead of an error if the filter did not exist. Filters also expire automatically when they are not polled.",
    "params": [{
      "name": "filterID",
      "type": "QUANTITY/ID",
      "description": "Filter ID to remove.",
      "example": "0x1"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_subscribe",
    "status": "limited",
    "description": "Opens a WebSocket-only push subscription for newHeads or logs notifications.",
    "seiNote": "This method works over WebSocket only. SubscriptionAPI is not registered on the HTTP server, so calls over HTTP return rpc.ErrNotificationsUnsupported. Only 'newHeads' and 'logs' are implemented in source. There is no 'newPendingTransactions' subscription, although some client docs imply otherwise. MaxSubscriptionsNewHead caps newHeads subscriptions.",
    "params": [{
      "name": "subscriptionType",
      "type": "string",
      "description": "Subscription name: 'newHeads' or 'logs'.",
      "example": "newHeads"
    }, {
      "name": "filter",
      "type": "object",
      "description": "Optional filter criteria (address and topics) for the 'logs' subscription.",
      "example": "{\"address\":\"0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7\",\"topics\":[]}"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_unsubscribe",
    "status": "supported",
    "description": "Cancels an existing WebSocket subscription by ID. Returns true on success.",
    "seiNote": "This method works over WebSocket only. It has no effect over HTTP, where notifications are not supported.",
    "params": [{
      "name": "subscriptionID",
      "type": "string",
      "description": "The subscription ID returned by a prior eth_subscribe call.",
      "example": "0x9cef478923ff08bf67fde6c64013158d"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_mining",
    "status": "unsupported",
    "description": "Returns whether the node is mining. Sei does not register this method.",
    "seiNote": "Sei uses CometBFT proof-of-stake consensus with no PoW mining. The method is not registered and returns -32601 method not found."
  }, {
    "namespace": "eth",
    "name": "eth_hashrate",
    "status": "unsupported",
    "description": "Returns the node mining hashrate. Sei does not register this method.",
    "seiNote": "Sei has no PoW mining (CometBFT consensus). The method is not registered and returns -32601 method not found."
  }, {
    "namespace": "eth",
    "name": "eth_getWork",
    "status": "unsupported",
    "description": "Returns the PoW work package (current header hash, seed, target). Sei does not register this method.",
    "seiNote": "The proof-of-work concept does not exist under Sei's CometBFT consensus. The method is not registered."
  }, {
    "namespace": "eth",
    "name": "eth_submitWork",
    "status": "unsupported",
    "description": "Submits a PoW solution. Sei does not register this method.",
    "seiNote": "PoW submission is meaningless on Sei (CometBFT PoS). The method is not registered.",
    "params": [{
      "name": "nonce",
      "type": "DATA, 8 bytes",
      "description": "Found PoW nonce.",
      "example": "0x0000000000000001"
    }, {
      "name": "powHash",
      "type": "DATA, 32 bytes",
      "description": "Header pow-hash.",
      "example": "0x0000000000000000000000000000000000000000000000000000000000000000"
    }, {
      "name": "mixDigest",
      "type": "DATA, 32 bytes",
      "description": "Mix digest.",
      "example": "0x0000000000000000000000000000000000000000000000000000000000000000"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_submitHashrate",
    "status": "unsupported",
    "description": "Submits a node's mining hashrate. Sei does not register this method.",
    "seiNote": "Sei has no PoW mining. The method is not registered.",
    "params": [{
      "name": "hashrate",
      "type": "QUANTITY",
      "description": "Hashrate value (hex).",
      "example": "0x500000"
    }, {
      "name": "id",
      "type": "DATA, 32 bytes",
      "description": "Random hex ID that identifies the client.",
      "example": "0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_protocolVersion",
    "status": "unsupported",
    "description": "Returns the Ethereum (devp2p) protocol version. Sei does not register this method.",
    "seiNote": "Sei does not expose the Ethereum devp2p protocol version. The method is not registered and returns -32601 method not found."
  }, {
    "namespace": "eth",
    "name": "eth_getUncleCountByBlockNumber",
    "status": "unsupported",
    "description": "Returns the uncle count by block number. Sei has no uncles and does not register this method.",
    "seiNote": "Sei uses CometBFT (single canonical chain, no uncles or ommers). The method is not registered and returns -32601.",
    "params": [{
      "name": "number",
      "type": "BLOCKNUMBER",
      "description": "Block number or tag.",
      "example": "latest"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getUncleCountByBlockHash",
    "status": "unsupported",
    "description": "Returns the uncle count by block hash. Sei has no uncles and does not register this method.",
    "seiNote": "CometBFT consensus has no uncle blocks. The method is not registered and returns -32601.",
    "params": [{
      "name": "blockHash",
      "type": "DATA, 32 bytes",
      "description": "Block hash.",
      "example": "0x5620c15afd9a1d0ab19d7560043df6e038d731c6205974dca7a55900071e3864"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getUncleByBlockNumberAndIndex",
    "status": "unsupported",
    "description": "Returns an uncle block by number and index. Sei has no uncles and does not register this method.",
    "seiNote": "CometBFT consensus has no uncle blocks. The method is not registered and returns -32601.",
    "params": [{
      "name": "number",
      "type": "BLOCKNUMBER",
      "description": "Block number or tag.",
      "example": "latest"
    }, {
      "name": "index",
      "type": "QUANTITY",
      "description": "Uncle index.",
      "example": "0x0"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_getUncleByBlockHashAndIndex",
    "status": "unsupported",
    "description": "Returns an uncle block by hash and index. Sei has no uncles and does not register this method.",
    "seiNote": "CometBFT consensus has no uncle blocks. The method is not registered and returns -32601.",
    "params": [{
      "name": "blockHash",
      "type": "DATA, 32 bytes",
      "description": "Block hash.",
      "example": "0x5620c15afd9a1d0ab19d7560043df6e038d731c6205974dca7a55900071e3864"
    }, {
      "name": "index",
      "type": "QUANTITY",
      "description": "Uncle index.",
      "example": "0x0"
    }]
  }, {
    "namespace": "eth",
    "name": "eth_pendingTransactions",
    "status": "unsupported",
    "description": "Lists the pending transactions in the node's transaction pool. Sei does not register this method.",
    "seiNote": "Sei exposes no geth-style mempool through this method. Pending state is exposed only through the 'pending' tag on eth_getTransactionCount and through txpool_content. The method is not registered and returns -32601."
  }, {
    "namespace": "net",
    "name": "net_version",
    "status": "supported",
    "description": "Returns the network or chain ID as a decimal string.",
    "seiNote": "Returns the EVM chain ID in decimal (alias of eth_chainId): '1329' on Sei Mainnet and '1328' on Sei Testnet."
  }, {
    "namespace": "net",
    "name": "net_listening",
    "status": "unsupported",
    "description": "Returns whether the node is listening for connections. Sei does not register this method.",
    "seiNote": "The method is not registered on Sei's NetAPI and returns -32601 method not found. CometBFT handles P2P, not this RPC."
  }, {
    "namespace": "net",
    "name": "net_peerCount",
    "status": "unsupported",
    "description": "Returns the number of connected peers. Sei does not register this method.",
    "seiNote": "The method is not registered on Sei's NetAPI and returns -32601. Query CometBFT net_info for peer data instead."
  }, {
    "namespace": "web3",
    "name": "web3_clientVersion",
    "status": "supported",
    "description": "Returns the client version string.",
    "seiNote": "Reports a synthetic 'Geth/<os>-<arch>/<goVersion>' string (Sei's EVM is backed by go-ethereum). It does NOT embed the actual sei-chain/seid version, so it is not a reliable Sei version indicator."
  }, {
    "namespace": "web3",
    "name": "web3_sha3",
    "status": "unsupported",
    "description": "Returns the Keccak-256 hash of the input. Sei's Web3API does not implement this method.",
    "seiNote": "Unlike go-ethereum, Sei's Web3API does not implement web3_sha3. It is not registered and returns -32601 method not found.",
    "params": [{
      "name": "data",
      "type": "DATA",
      "description": "Bytes to hash.",
      "example": "0x68656c6c6f20776f726c64"
    }]
  }, {
    "namespace": "txpool",
    "name": "txpool_content",
    "status": "limited",
    "description": "Returns the transactions currently in the pool, grouped by sender address and nonce into pending and queued buckets.",
    "seiNote": "As a Sei-specific simplification, every unconfirmed EVM tx from the CometBFT mempool is reported under 'pending'. The 'queued' bucket is always empty (no geth-style nonce-gap distinction between pending and queued). The result set is truncated to the node's MaxTxPoolTxs config, so it may not reflect the entire mempool."
  }, {
    "namespace": "txpool",
    "name": "txpool_contentFrom",
    "status": "unsupported",
    "description": "Returns the pending and queued transactions for a single account. Sei does not implement this method.",
    "seiNote": "The method is not registered and returns -32601 method not found. The only txpool method available on Sei is txpool_content.",
    "params": [{
      "name": "address",
      "type": "DATA, 20 bytes",
      "description": "The account address to filter by.",
      "example": "0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55"
    }]
  }, {
    "namespace": "txpool",
    "name": "txpool_status",
    "status": "unsupported",
    "description": "Returns the counts of pending and queued transactions. Sei does not implement this method.",
    "seiNote": "The method is not registered and returns -32601 method not found."
  }, {
    "namespace": "txpool",
    "name": "txpool_inspect",
    "status": "unsupported",
    "description": "Returns a human-readable summary of pending and queued transactions. Sei does not implement this method.",
    "seiNote": "The method is not registered and returns -32601 method not found."
  }, {
    "namespace": "debug",
    "name": "debug_traceTransaction",
    "status": "supported",
    "description": "Replays a transaction by hash and returns an execution trace using the configured tracer.",
    "seiNote": "Works over HTTP only (the debug namespace is not registered on the WebSocket server). Supports geth tracers (callTracer, prestateTracer, flatCallTracer, struct or opcode logger). TraceBaker pre-bakes and caches callTracer, prestateTracer, and flatCallTracer results. Requires trace-enabled or archive state for the target height.",
    "params": [{
      "name": "hash",
      "type": "DATA, 32 bytes",
      "description": "Transaction hash to trace.",
      "example": "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060"
    }, {
      "name": "config",
      "type": "object",
      "description": "Optional tracer config (tracer name, tracerConfig, timeout, reexec, disableStorage/Stack/Memory).",
      "example": "{\"tracer\":\"callTracer\"}"
    }]
  }, {
    "namespace": "debug",
    "name": "debug_traceBlockByNumber",
    "status": "supported",
    "description": "Traces all transactions in a block by number and returns per-transaction execution traces.",
    "seiNote": "Works over HTTP only. The safe, finalized, and latest tags are equivalent because of instant finality.",
    "params": [{
      "name": "number",
      "type": "BLOCKNUMBER",
      "description": "Block number or tag.",
      "example": "latest"
    }, {
      "name": "config",
      "type": "object",
      "description": "Optional tracer config.",
      "example": "{\"tracer\":\"callTracer\"}"
    }]
  }, {
    "namespace": "debug",
    "name": "debug_traceBlockByHash",
    "status": "supported",
    "description": "Traces all transactions in a block by hash and returns per-transaction execution traces.",
    "seiNote": "Works over HTTP only.",
    "params": [{
      "name": "hash",
      "type": "DATA, 32 bytes",
      "description": "Block hash.",
      "example": "0x5620c15afd9a1d0ab19d7560043df6e038d731c6205974dca7a55900071e3864"
    }, {
      "name": "config",
      "type": "object",
      "description": "Optional tracer config.",
      "example": "{\"tracer\":\"callTracer\"}"
    }]
  }, {
    "namespace": "debug",
    "name": "debug_traceCall",
    "status": "supported",
    "description": "Executes and traces a call against a block's state without creating a transaction.",
    "seiNote": "Works over HTTP only. Arbitrary geth tracer names pass through. Tracing on the pending block is not supported.",
    "params": [{
      "name": "args",
      "type": "object",
      "description": "Transaction call object.",
      "example": "{\"to\":\"0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7\",\"data\":\"0x70a08231\"}"
    }, {
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Block number, tag, or hash.",
      "example": "latest"
    }, {
      "name": "config",
      "type": "object",
      "description": "Optional trace-call config (tracer name, state overrides, block overrides).",
      "example": "{\"tracer\":\"callTracer\"}"
    }]
  }, {
    "namespace": "debug",
    "name": "debug_traceStateAccess",
    "status": "limited",
    "description": "Sei extension that replays a transaction and returns its app, tendermint, and receipt state-access traces.",
    "seiNote": "This is a Sei-specific extension (not part of upstream go-ethereum's debug namespace). It works over HTTP only and is subject to historical-debug-trace availability guards.",
    "params": [{
      "name": "hash",
      "type": "DATA, 32 bytes",
      "description": "Transaction hash whose state accesses are returned.",
      "example": "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060"
    }]
  }, {
    "namespace": "debug",
    "name": "debug_traceTransactionProfile",
    "status": "limited",
    "description": "Sei extension that traces a transaction and returns the trace plus a phase-by-phase timing profile of the trace execution.",
    "seiNote": "This is a Sei-specific extension (not part of upstream go-ethereum's debug namespace). Returns {trace, profile}, where profile carries totalNanos, historicalDbLookupNanos, otherNanos, and per-phase timings. It works over HTTP only and is subject to the max_trace_lookback_blocks historical guard.",
    "params": [{
      "name": "hash",
      "type": "DATA, 32 bytes",
      "description": "Transaction hash to trace and profile.",
      "example": "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060"
    }, {
      "name": "config",
      "type": "object",
      "description": "Optional tracer config.",
      "example": "{\"tracer\":\"callTracer\"}"
    }]
  }, {
    "namespace": "debug",
    "name": "debug_getRawHeader",
    "status": "unsupported",
    "description": "Returns the RLP-encoded block header. Sei registers this method, but it always returns an unsupported error.",
    "seiNote": "Always returns JSON-RPC -32000. Sei block headers are CometBFT headers, not RLP-encoded Ethereum headers.",
    "params": [{
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Block number, tag, or hash.",
      "example": "latest"
    }]
  }, {
    "namespace": "debug",
    "name": "debug_getRawBlock",
    "status": "unsupported",
    "description": "Returns the RLP-encoded full block. Sei registers this method, but it always returns an unsupported error.",
    "seiNote": "Always returns JSON-RPC -32000. No canonical RLP-encoded Ethereum block exists on Sei.",
    "params": [{
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Block number, tag, or hash.",
      "example": "latest"
    }]
  }, {
    "namespace": "debug",
    "name": "debug_getRawReceipts",
    "status": "unsupported",
    "description": "Returns the RLP-encoded receipts for a block. Sei registers this method, but it always returns an unsupported error.",
    "seiNote": "Always returns JSON-RPC -32000.",
    "params": [{
      "name": "blockNrOrHash",
      "type": "BLOCKNUMBER or DATA",
      "description": "Block number, tag, or hash.",
      "example": "latest"
    }]
  }, {
    "namespace": "debug",
    "name": "debug_getRawTransaction",
    "status": "unsupported",
    "description": "Returns an RLP-encoded signed transaction by hash. Sei registers this method, but it always returns an unsupported error.",
    "seiNote": "Always returns JSON-RPC -32000.",
    "params": [{
      "name": "hash",
      "type": "DATA, 32 bytes",
      "description": "Transaction hash.",
      "example": "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060"
    }]
  }, {
    "namespace": "debug",
    "name": "debug_storageRangeAt",
    "status": "unsupported",
    "description": "Returns a range of storage entries for a contract at a block or tx. Sei does not implement this method.",
    "seiNote": "The method is not registered and returns -32601. Sei uses IAVL state, not an Ethereum MPT, so geth's MPT-based storage-range walk is not available.",
    "params": [{
      "name": "blockHash",
      "type": "DATA, 32 bytes",
      "description": "Block hash.",
      "example": "0x5620c15afd9a1d0ab19d7560043df6e038d731c6205974dca7a55900071e3864"
    }, {
      "name": "txIndex",
      "type": "QUANTITY",
      "description": "Transaction index.",
      "example": "0x0"
    }, {
      "name": "address",
      "type": "DATA, 20 bytes",
      "description": "Contract address.",
      "example": "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7"
    }, {
      "name": "startKey",
      "type": "DATA",
      "description": "Start storage key.",
      "example": "0x00"
    }, {
      "name": "maxResult",
      "type": "QUANTITY",
      "description": "Maximum number of entries.",
      "example": "0x64"
    }]
  }, {
    "namespace": "debug",
    "name": "debug_traceBlock",
    "status": "unsupported",
    "description": "Traces a block supplied as raw RLP bytes. Sei does not implement this method.",
    "seiNote": "The method is not registered and returns -32601. Sei does not accept RLP-encoded Ethereum blocks. Use debug_traceBlockByNumber or debug_traceBlockByHash instead.",
    "params": [{
      "name": "blockRlp",
      "type": "DATA",
      "description": "RLP-encoded block bytes.",
      "example": "0xf90211..."
    }]
  }, {
    "namespace": "debug",
    "name": "debug_intermediateRoots",
    "status": "unsupported",
    "description": "Returns the intermediate state roots while a block executes. Sei does not implement this method.",
    "seiNote": "The method is not registered and returns -32601. Sei uses IAVL state, not an Ethereum MPT, so it does not produce per-transaction MPT intermediate roots.",
    "params": [{
      "name": "blockHash",
      "type": "DATA, 32 bytes",
      "description": "Block hash.",
      "example": "0x5620c15afd9a1d0ab19d7560043df6e038d731c6205974dca7a55900071e3864"
    }, {
      "name": "config",
      "type": "object",
      "description": "Optional trace config.",
      "example": "{}"
    }]
  }, {
    "namespace": "debug",
    "name": "debug_setHead",
    "status": "unsupported",
    "description": "Rewinds the chain head to a given block. Sei does not implement this method.",
    "seiNote": "The method is not registered and returns -32601. CometBFT consensus controls the chain head, not the EVM RPC layer.",
    "params": [{
      "name": "number",
      "type": "QUANTITY",
      "description": "Block number to set as head.",
      "example": "0x1a2b3c"
    }]
  }, {
    "namespace": "sei",
    "name": "sei_getSeiAddress",
    "status": "limited",
    "description": "Returns the native Sei bech32 (sei1...) address associated with a given EVM (0x) address.",
    "seiNote": "This legacy sei_* method is deprecated but ENABLED by default in the enabled_legacy_sei_apis allowlist on seid init. New integrations should call the addr precompile at 0x0000000000000000000000000000000000001004 (getSeiAddr) with eth_call. Returns an error if the address is not yet associated. Works over HTTP only.",
    "params": [{
      "name": "ethAddress",
      "type": "DATA, 20 bytes",
      "description": "The EVM address to resolve.",
      "example": "0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55"
    }]
  }, {
    "namespace": "sei",
    "name": "sei_getEVMAddress",
    "status": "limited",
    "description": "Returns the EVM (0x) address associated with a given native Sei bech32 (sei1...) address.",
    "seiNote": "This legacy sei_* method is deprecated but ENABLED by default in enabled_legacy_sei_apis. Prefer the addr precompile at 0x0000000000000000000000000000000000001004 (getEvmAddr) with eth_call. Returns an error if the bech32 is malformed or the address is not yet associated. Works over HTTP only.",
    "params": [{
      "name": "seiAddress",
      "type": "string",
      "description": "The Sei bech32 address to resolve.",
      "example": "sei13ytysxs88z0fp9cssagg77ekpecrrlrwce9pwl"
    }]
  }, {
    "namespace": "sei",
    "name": "sei_getCosmosTx",
    "status": "limited",
    "description": "Returns the underlying CometBFT/Cosmos transaction hash corresponding to a given EVM transaction hash.",
    "seiNote": "This legacy sei_* method is deprecated but ENABLED by default in enabled_legacy_sei_apis (it has no precompile equivalent yet). Returns the wrapping Cosmos transaction hash as uppercase hexadecimal without a 0x prefix. Works over HTTP only.",
    "params": [{
      "name": "ethHash",
      "type": "DATA, 32 bytes",
      "description": "The EVM transaction hash to map to its underlying Cosmos tx hash.",
      "example": "0x828c91592453fe7c5bf743204495a35bf02b67b579b8f59ee7eea8af031d7c14"
    }]
  }, {
    "namespace": "sei",
    "name": "sei_getTransactionReceipt",
    "status": "limited",
    "description": "Returns a transaction receipt by hash, including synthetic receipts for Cosmos transactions.",
    "seiNote": "This legacy sei_* method is deprecated and DISABLED by default. It can get logs for a synthetic transaction when its hash is already known. Works over HTTP only.",
    "params": [{
      "name": "hash",
      "type": "DATA, 32 bytes",
      "description": "Transaction hash.",
      "example": "0x828c91592453fe7c5bf743204495a35bf02b67b579b8f59ee7eea8af031d7c14"
    }]
  }, {
    "namespace": "admin",
    "name": "admin_*",
    "status": "unsupported",
    "description": "Geth node administration namespace (admin_nodeInfo, admin_peers, admin_addPeer, admin_datadir, and others). Sei does not run this namespace.",
    "seiNote": "Sei does not run go-ethereum's admin namespace. Node administration goes through the CometBFT/Cosmos stack. All admin_* methods return -32601 method not found."
  }, {
    "namespace": "miner",
    "name": "miner_*",
    "status": "unsupported",
    "description": "Geth miner-control namespace (miner_start, miner_stop, miner_setEtherbase, miner_setGasPrice, and others). Sei does not run this namespace.",
    "seiNote": "Sei has no PoW or PoA miner (CometBFT PoS consensus) and does not serve the namespace. All miner_* methods return -32601."
  }, {
    "namespace": "clique",
    "name": "clique_*",
    "status": "unsupported",
    "description": "Clique proof-of-authority consensus namespace (clique_getSnapshot, clique_propose, and others). Sei does not run this namespace.",
    "seiNote": "Sei uses CometBFT, not the Clique PoA engine, and does not serve the namespace. All clique_* methods return -32601."
  }, {
    "namespace": "engine",
    "name": "engine_*",
    "status": "unsupported",
    "description": "Ethereum Engine API namespace (engine_newPayloadV*, engine_forkchoiceUpdatedV*, engine_getPayloadV*) for payload exchange between the consensus and execution layers. Sei does not run this namespace.",
    "seiNote": "Sei is not a post-merge Ethereum execution client. It has no CL/EL split or payload engine (consensus is CometBFT). All engine_* methods return -32601."
  }, {
    "namespace": "les",
    "name": "les_*",
    "status": "unsupported",
    "description": "Light Ethereum Subprotocol (LES) light-server namespace. Sei does not run this namespace.",
    "seiNote": "Sei does not implement LES light-server endpoints and does not serve the namespace. All les_* methods return -32601."
  }, {
    "namespace": "personal",
    "name": "personal_*",
    "status": "unsupported",
    "description": "Geth account-management namespace (personal_newAccount, personal_unlockAccount, personal_sendTransaction, personal_sign, and others). Sei does not run this namespace.",
    "seiNote": "Sei does not expose the deprecated personal namespace. Hosted RPC nodes hold no user keys. Key management and signing happen client-side, and eth_sendRawTransaction is the supported path. All personal_* methods return -32601."
  }];
  const parseValue = raw => {
    if (typeof raw !== 'string') return raw;
    const t = raw.trim();
    if (t === '') return '';
    const looksJson = t[0] === '{' || t[0] === '[' || t === 'true' || t === 'false' || t === 'null';
    if (looksJson) {
      try {
        return JSON.parse(t);
      } catch (e) {
        return raw;
      }
    }
    return raw;
  };
  const isEmptyValue = v => {
    if (v === '' || v === undefined || v === null) return true;
    if (Array.isArray(v)) return v.length === 0;
    if (typeof v === 'object') return Object.keys(v).length === 0;
    return false;
  };
  const buildParams = (method, values) => {
    const defs = method.params || [];
    const raw = defs.map(p => {
      const v = values ? values[p.name] : undefined;
      return v !== undefined ? v : p.example || '';
    });
    const isBlank = v => typeof v === 'string' && v.trim() === '';
    let end = raw.length;
    while (end > 0 && isEmptyValue(parseValue(raw[end - 1]))) end--;
    const params = raw.slice(0, end).map((v, i) => isBlank(v) ? parseValue(defs[i].example || '') : parseValue(v));
    const sub = typeof params[0] === 'string' ? params[0].trim().toLowerCase() : params[0];
    if (method.name === 'eth_subscribe' && sub !== 'logs') params.length = 1;
    return params;
  };
  const deriveWsEndpoint = httpUrl => {
    if (!httpUrl) return 'wss://<your-ws-endpoint>';
    try {
      const u = new URL(httpUrl);
      u.protocol = u.protocol === 'http:' ? 'ws:' : 'wss:';
      return u.toString().replace(/\/$/, '');
    } catch (e) {
      return 'wss://<your-ws-endpoint>';
    }
  };
  const isWsOnly = name => name === 'eth_subscribe' || name === 'eth_unsubscribe';
  const isMutation = name => name === 'eth_sendRawTransaction' || name === 'eth_sendTransaction' || name === 'eth_signTransaction' || name === 'eth_sign' || name.startsWith('personal_');
  const [theme, setTheme] = useState('dark');
  const [isMobile, setIsMobile] = useState(false);
  const [mobileView, setMobileView] = useState('list');
  const rootRef = useRef(null);
  const runIdRef = useRef(0);
  const probeIdRef = useRef(0);
  const [network, setNetwork] = useState('mainnet');
  const [customEndpoint, setCustomEndpoint] = useState('');
  const endpoint = network === 'custom' ? customEndpoint : NETWORKS[network].http;
  const wsEndpoint = network === 'custom' ? deriveWsEndpoint(customEndpoint) : NETWORKS[network].ws;
  const [connection, setConnection] = useState('idle');
  const [consoleActive, setConsoleActive] = useState(false);
  const [searchTerm, setSearchTerm] = useState('');
  const [selectedNamespace, setSelectedNamespace] = useState('all');
  const [showAll, setShowAll] = useState(false);
  const isHiddenByDefault = m => m.status === 'unsupported' || !!(NAMESPACE_META[m.namespace] && NAMESPACE_META[m.namespace].deprecated);
  const [selectedMethod, setSelectedMethod] = useState(null);
  const [selectedLanguage, setSelectedLanguage] = useState('curl');
  const [paramValues, setParamValues] = useState({});
  const [debouncedParams, setDebouncedParams] = useState({});
  const [requestResult, setRequestResult] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [copied, setCopied] = useState('');
  const isDark = theme === 'dark';
  useLayoutEffect(() => {
    const detect = () => setTheme(document.documentElement.classList.contains('dark') ? 'dark' : 'light');
    detect();
    const observer = new MutationObserver(detect);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['class']
    });
    return () => observer.disconnect();
  }, []);
  useEffect(() => {
    const stackBelow = w => setIsMobile(w < 768);
    const el = rootRef.current;
    if (el && typeof ResizeObserver !== 'undefined') {
      const ro = new ResizeObserver(entries => stackBelow(entries[0].contentRect.width));
      ro.observe(el);
      return () => ro.disconnect();
    }
    const check = () => stackBelow(window.innerWidth);
    check();
    window.addEventListener('resize', check);
    return () => window.removeEventListener('resize', check);
  }, []);
  useEffect(() => {
    const t = setTimeout(() => setDebouncedParams(paramValues), 250);
    return () => clearTimeout(t);
  }, [paramValues]);
  const validateEndpoint = useCallback(async () => {
    if (!endpoint) {
      setConnection('idle');
      return;
    }
    const probeId = ++probeIdRef.current;
    try {
      const res = await fetch(endpoint, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          jsonrpc: '2.0',
          id: 1,
          method: 'web3_clientVersion',
          params: []
        })
      });
      if (probeId === probeIdRef.current) setConnection(res.ok ? 'ok' : 'fail');
    } catch (e) {
      if (probeId === probeIdRef.current) setConnection('fail');
    }
  }, [endpoint]);
  useEffect(() => {
    if (consoleActive) validateEndpoint();
  }, [validateEndpoint, consoleActive]);
  useEffect(() => {
    runIdRef.current++;
    setRequestResult(null);
    setIsLoading(false);
  }, [endpoint]);
  const allMethods = useMemo(() => SEI_RPC_METHODS.map(m => ({
    ...m,
    meta: NAMESPACE_META[m.namespace] || ({
      label: m.namespace,
      color: '#6b7280'
    })
  })), []);
  const filteredMethods = useMemo(() => {
    let list = allMethods;
    if (selectedNamespace !== 'all') list = list.filter(m => m.namespace === selectedNamespace);
    if (!showAll) list = list.filter(m => !isHiddenByDefault(m));
    if (searchTerm) {
      const q = searchTerm.toLowerCase();
      list = list.filter(m => m.name.toLowerCase().includes(q) || (m.description || '').toLowerCase().includes(q));
    }
    const rank = s => s === 'supported' ? 0 : s === 'limited' ? 1 : 2;
    return [...list].sort((a, b) => {
      const ns = NAMESPACE_ORDER.indexOf(a.namespace) - NAMESPACE_ORDER.indexOf(b.namespace);
      if (ns !== 0) return ns;
      return rank(a.status) - rank(b.status);
    });
  }, [allMethods, selectedNamespace, showAll, searchTerm]);
  const visibleNamespaces = useMemo(() => {
    const present = new Set();
    allMethods.forEach(m => {
      if (showAll || !isHiddenByDefault(m)) present.add(m.namespace);
    });
    return NAMESPACE_ORDER.filter(ns => present.has(ns));
  }, [allMethods, showAll]);
  const counts = useMemo(() => allMethods.reduce((a, m) => (a[m.status] = (a[m.status] || 0) + 1, a), {}), [allMethods]);
  const selectMethod = m => {
    setConsoleActive(true);
    setSelectedMethod(m);
    setParamValues({});
    setDebouncedParams({});
    runIdRef.current++;
    setRequestResult(null);
    setIsLoading(false);
    setSelectedLanguage('curl');
    if (isMobile) setMobileView('detail');
  };
  const copy = (text, key) => {
    navigator.clipboard.writeText(text);
    setCopied(key);
    setTimeout(() => setCopied(''), 1500);
  };
  const execute = async () => {
    if (!selectedMethod) return;
    const runId = ++runIdRef.current;
    setIsLoading(true);
    setRequestResult(null);
    const params = buildParams(selectedMethod, paramValues);
    try {
      const res = await fetch(endpoint, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          jsonrpc: '2.0',
          id: 1,
          method: selectedMethod.name,
          params
        })
      });
      const json = await res.json();
      if (runId === runIdRef.current) setRequestResult(json);
    } catch (e) {
      if (runId === runIdRef.current) setRequestResult({
        error: {
          code: -1,
          message: e.message + ' (the endpoint may not allow CORS requests from a browser)'
        }
      });
    } finally {
      if (runId === runIdRef.current) setIsLoading(false);
    }
  };
  const generateCode = useCallback((method, language) => {
    if (!method) return '';
    const params = buildParams(method, debouncedParams);
    const paramsJson = JSON.stringify(params);
    const bodyJson = JSON.stringify({
      jsonrpc: '2.0',
      id: 1,
      method: method.name,
      params
    });
    const url = endpoint || 'https://evm-rpc.sei-apis.com';
    const ws = wsEndpoint;
    const BT = String.fromCharCode(96);
    const csBody = bodyJson.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
    if (isWsOnly(method.name)) {
      if (language === 'javascript') {
        return [`// ${method.name} runs over WebSocket only.`, `const socket = new WebSocket('${ws}');`, 'socket.onopen = () => socket.send(JSON.stringify({', `  jsonrpc: '2.0', id: 1, method: '${method.name}', params: ${paramsJson},`, '}));', 'socket.onmessage = (e) => console.log(JSON.parse(e.data));', '', '// ethers v6', "import { WebSocketProvider } from 'ethers';", `const provider = new WebSocketProvider('${ws}');`, `console.log(await provider.send('${method.name}', ${paramsJson}));`].join('\n');
      }
      if (language === 'typescript') {
        return [`// ${method.name} runs over WebSocket only.`, `const socket = new WebSocket('${ws}');`, 'socket.onopen = () => socket.send(JSON.stringify({', `  jsonrpc: '2.0', id: 1, method: '${method.name}', params: ${paramsJson},`, '}));', 'socket.onmessage = (e: MessageEvent) => console.log(JSON.parse(e.data));'].join('\n');
      }
      if (language === 'python') {
        return ['# pip install websocket-client', 'from websocket import create_connection', `socket = create_connection("${ws}")`, `socket.send(r"""${bodyJson}""")`, 'print(socket.recv())', 'socket.close()'].join('\n');
      }
      if (language === 'go') {
        return ['// go get github.com/gorilla/websocket', 'package main', '', 'import (', '\t"fmt"', '\t"github.com/gorilla/websocket"', ')', '', 'func main() {', `\tc, _, err := websocket.DefaultDialer.Dial("${ws}", nil)`, '\tif err != nil {', '\t\tpanic(err)', '\t}', '\tdefer c.Close()', '\tc.WriteMessage(websocket.TextMessage, []byte(' + BT + bodyJson + BT + '))', '\t_, msg, _ := c.ReadMessage()', '\tfmt.Println(string(msg))', '}'].join('\n');
      }
      if (language === 'rust') {
        return ['// tokio-tungstenite = "0.23"  futures-util = "0.3"  tokio = { version = "1", features = ["full"] }', 'use futures_util::{SinkExt, StreamExt};', 'use tokio_tungstenite::{connect_async, tungstenite::Message};', '', '#[tokio::main]', 'async fn main() -> Result<(), Box<dyn std::error::Error>> {', `    let (mut socket, _) = connect_async("${ws}").await?;`, '    socket.send(Message::Text(r#"' + bodyJson + '"#.to_string())).await?;', '    if let Some(msg) = socket.next().await {', '        println!("{}", msg?);', '    }', '    Ok(())', '}'].join('\n');
      }
      if (language === 'csharp') {
        return ['using System;', 'using System.Net.WebSockets;', 'using System.Text;', 'using System.Threading;', '', 'using var socket = new ClientWebSocket();', `await socket.ConnectAsync(new Uri("${ws}"), CancellationToken.None);`, `var body = Encoding.UTF8.GetBytes("${csBody}");`, 'await socket.SendAsync(body, WebSocketMessageType.Text, true, CancellationToken.None);', 'var buffer = new byte[8192];', 'var res = await socket.ReceiveAsync(buffer, CancellationToken.None);', 'Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, res.Count));'].join('\n');
      }
      if (language === 'cast') {
        return [`# ${method.name} is WebSocket-only. cast has no native WebSocket support.`, '# Use wscat (npm i -g wscat):', `wscat -c ${ws}`, `> ${bodyJson}`].join('\n');
      }
      if (language === 'java') {
        return ['import java.net.URI;', 'import java.net.http.*;', 'import java.util.concurrent.CompletableFuture;', 'import java.util.concurrent.CompletionStage;', '', 'var done = new CompletableFuture<Void>();', 'HttpClient.newHttpClient().newWebSocketBuilder()', `    .buildAsync(URI.create("${ws}"), new WebSocket.Listener() {`, '        public void onOpen(WebSocket ws) {', `            ws.sendText("${csBody}", true); ws.request(1);`, '        }', '        public CompletionStage<?> onText(WebSocket ws, CharSequence data, boolean last) {', '            System.out.println(data); done.complete(null); return null;', '        }', '    }).join();', 'done.join();'].join('\n');
      }
      if (language === 'kotlin') {
        return ['import java.net.URI', 'import java.net.http.*', 'import java.util.concurrent.CompletableFuture', 'import java.util.concurrent.CompletionStage', '', 'val done = CompletableFuture<Void>()', 'HttpClient.newHttpClient().newWebSocketBuilder()', `    .buildAsync(URI.create("${ws}"), object : WebSocket.Listener {`, '        override fun onOpen(ws: WebSocket) {', `            ws.sendText("${csBody}", true); ws.request(1)`, '        }', '        override fun onText(ws: WebSocket, data: CharSequence, last: Boolean): CompletionStage<*>? {', '            println(data); done.complete(null); ws.request(1); return null', '        }', '    }).join()', 'done.join()'].join('\n');
      }
      if (language === 'swift') {
        return ['import Foundation', '', `let task = URLSession.shared.webSocketTask(with: URL(string: "${ws}")!)`, 'task.resume()', `try await task.send(.string(#"${bodyJson}"#))`, 'let msg = try await task.receive()', 'if case .string(let text) = msg { print(text) }', 'task.cancel(with: .normalClosure, reason: nil)'].join('\n');
      }
      return [`# ${method.name} is WebSocket-only. Use wscat (npm i -g wscat):`, `wscat -c ${ws}`, `> ${bodyJson}`].join('\n');
    }
    if (language === 'javascript') {
      return ['// fetch', `const res = await fetch('${url}', {`, "  method: 'POST',", "  headers: { 'Content-Type': 'application/json' },", '  body: JSON.stringify({', "    jsonrpc: '2.0', id: 1,", `    method: '${method.name}',`, `    params: ${paramsJson},`, '  }),', '});', 'console.log((await res.json()).result);', '', '// ethers v6', "import { JsonRpcProvider } from 'ethers';", `const provider = new JsonRpcProvider('${url}');`, `console.log(await provider.send('${method.name}', ${paramsJson}));`, '', '// viem', "import { createPublicClient, http } from 'viem';", `const client = createPublicClient({ transport: http('${url}') });`, `console.log(await client.request({ method: '${method.name}', params: ${paramsJson} }));`].join('\n');
    }
    if (language === 'typescript') {
      return ['type RpcResponse<T> = {', '  jsonrpc: string; id: number;', '  result?: T; error?: { code: number; message: string };', '};', '', `const res = await fetch('${url}', {`, "  method: 'POST',", "  headers: { 'Content-Type': 'application/json' },", '  body: JSON.stringify({', "    jsonrpc: '2.0', id: 1,", `    method: '${method.name}',`, `    params: ${paramsJson},`, '  }),', '});', 'const data: RpcResponse<unknown> = await res.json();', 'console.log(data.result);', '', '// ethers v6', "import { JsonRpcProvider } from 'ethers';", `const provider = new JsonRpcProvider('${url}');`, `console.log(await provider.send('${method.name}', ${paramsJson}));`].join('\n');
    }
    if (language === 'python') {
      return ['import requests, json', '', `url = "${url}"`, `params = json.loads(r"""${paramsJson}""")`, 'res = requests.post(url, json={', '    "jsonrpc": "2.0", "id": 1,', `    "method": "${method.name}", "params": params,`, '})', 'print(res.json().get("result"))', '', '# web3.py', 'from web3 import Web3', 'w3 = Web3(Web3.HTTPProvider(url))', `print(w3.provider.make_request("${method.name}", params))`].join('\n');
    }
    if (language === 'go') {
      return ['package main', '', 'import (', '\t"bytes"', '\t"fmt"', '\t"io"', '\t"net/http"', ')', '', 'func main() {', '\tbody := []byte(' + BT + bodyJson + BT + ')', `\tresp, err := http.Post("${url}", "application/json", bytes.NewBuffer(body))`, '\tif err != nil {', '\t\tpanic(err)', '\t}', '\tdefer resp.Body.Close()', '\tout, _ := io.ReadAll(resp.Body)', '\tfmt.Println(string(out))', '}'].join('\n');
    }
    if (language === 'rust') {
      return ['// reqwest = { version = "0.12", features = ["json"] }', '// serde_json = "1"   tokio = { version = "1", features = ["full"] }', 'use serde_json::Value;', '', '#[tokio::main]', 'async fn main() -> Result<(), Box<dyn std::error::Error>> {', '    let body: Value = serde_json::from_str(r#"' + bodyJson + '"#)?;', `    let res = reqwest::Client::new().post("${url}")`, '        .json(&body).send().await?', '        .json::<Value>().await?;', '    println!("{:#?}", res["result"]);', '    Ok(())', '}'].join('\n');
    }
    if (language === 'csharp') {
      return ['using System;', 'using System.Net.Http;', 'using System.Text;', '', 'using var http = new HttpClient();', `var json = "${csBody}";`, 'var content = new StringContent(json, Encoding.UTF8, "application/json");', `var res = await http.PostAsync("${url}", content);`, 'Console.WriteLine(await res.Content.ReadAsStringAsync());'].join('\n');
    }
    if (language === 'cast') {
      const castArgs = params.map(p => `'${JSON.stringify(p)}'`).join(' ');
      return `cast rpc --rpc-url ${url} ${method.name}${params.length ? ' ' + castArgs : ''}`;
    }
    if (language === 'java') {
      return ['import java.net.URI;', 'import java.net.http.*;', '', `var json = "${csBody}";`, `var req = HttpRequest.newBuilder(URI.create("${url}"))`, '    .header("Content-Type", "application/json")', '    .POST(HttpRequest.BodyPublishers.ofString(json))', '    .build();', 'var res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());', 'System.out.println(res.body());'].join('\n');
    }
    if (language === 'kotlin') {
      return ['import java.net.URI', 'import java.net.http.HttpClient', 'import java.net.http.HttpRequest', 'import java.net.http.HttpResponse', '', `val json = "${csBody}"`, `val req = HttpRequest.newBuilder(URI.create("${url}"))`, '    .header("Content-Type", "application/json")', '    .POST(HttpRequest.BodyPublishers.ofString(json))', '    .build()', 'val res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString())', 'println(res.body())'].join('\n');
    }
    if (language === 'swift') {
      return ['import Foundation', '', `let url = URL(string: "${url}")!`, 'var request = URLRequest(url: url)', 'request.httpMethod = "POST"', 'request.setValue("application/json", forHTTPHeaderField: "Content-Type")', `request.httpBody = Data(#"${bodyJson}"#.utf8)`, '', 'let (data, _) = try await URLSession.shared.data(for: request)', 'print(String(decoding: data, as: UTF8.self))'].join('\n');
    }
    const curlBody = bodyJson.replace(/'/g, "'\\''");
    return `curl -s -X POST ${url} \\\n  -H "Content-Type: application/json" \\\n  -d '${curlBody}'`;
  }, [endpoint, wsEndpoint, debouncedParams]);
  const codeExample = useMemo(() => generateCode(selectedMethod, selectedLanguage), [selectedMethod, selectedLanguage, generateCode]);
  const c = {
    bg: isDark ? '#000000' : '#f5f5f7',
    panel: isDark ? '#0a0a0a' : '#ffffff',
    panel2: isDark ? '#121212' : '#f5f5f7',
    border: isDark ? '#1f1f1f' : '#ececee',
    text: isDark ? '#ffffff' : '#131313',
    sub: isDark ? '#9ca3af' : '#666666',
    faint: isDark ? '#8b919c' : '#707070',
    input: isDark ? '#161616' : '#ffffff',
    code: isDark ? '#0d0d0d' : '#1a1a1a',
    maroon: '#600014'
  };
  const mono = 'var(--sei-font-mono, ui-monospace, "SF Mono", Menlo, monospace)';
  const bd = '1px solid ' + c.border;
  const fieldStyle = {
    width: '100%',
    fontSize: 12,
    fontFamily: mono,
    padding: '7px 10px',
    background: c.input,
    color: c.text,
    border: bd,
    borderRadius: 4,
    outline: 'none',
    boxSizing: 'border-box'
  };
  const statusColor = s => isDark ? STATUS_META[s].dark : STATUS_META[s].light;
  const StatusDot = ({status}) => <span title={STATUS_META[status].label} style={{
    display: 'inline-block',
    width: 7,
    height: 7,
    borderRadius: 9,
    background: statusColor(status),
    flexShrink: 0
  }} />;
  const Badge = ({status}) => <span style={{
    fontSize: 11,
    fontWeight: 600,
    padding: '2px 8px',
    borderRadius: 3,
    color: statusColor(status),
    background: statusColor(status) + '22',
    border: `1px solid ${statusColor(status)}55`
  }}>
      {STATUS_META[status].label}
    </span>;
  const CopyBtn = ({text, k}) => <button onClick={() => copy(text, k)} style={{
    fontSize: 11,
    color: c.sub,
    background: 'transparent',
    border: bd,
    borderRadius: 3,
    padding: '3px 8px',
    cursor: 'pointer'
  }}>
      {copied === k ? 'Copied' : 'Copy'}
    </button>;
  const CodeBlock = ({text, maxHeight}) => <pre style={{
    margin: 0,
    padding: 14,
    borderRadius: 4,
    background: c.code,
    border: bd,
    overflowX: 'auto',
    maxHeight
  }}>
      <code style={{
    fontFamily: mono,
    fontSize: 12,
    color: '#d4d4d4',
    whiteSpace: 'pre',
    lineHeight: 1.6
  }}>{text}</code>
    </pre>;
  const m = selectedMethod;
  const mMeta = m ? NAMESPACE_META[m.namespace] || ({}) : {};
  return <div ref={rootRef} className="not-prose rpc-explorer-root" style={{
    fontFamily: 'var(--sei-font-body, inherit)',
    color: c.text,
    background: c.bg,
    border: bd,
    borderRadius: 6,
    overflow: 'hidden',
    display: 'flex',
    flexDirection: 'column',
    height: '96vh',
    minHeight: 768
  }}>
      <div style={{
    borderBottom: bd,
    background: c.panel,
    padding: '14px 18px',
    display: 'flex',
    flexDirection: 'column',
    gap: 12,
    flexShrink: 0
  }}>
        <div>
          <div style={{
    fontSize: 16,
    fontWeight: 700,
    letterSpacing: '-0.01em'
  }}>Sei EVM JSON-RPC Explorer</div>
          <div style={{
    fontSize: 12,
    color: c.sub,
    marginTop: 2
  }}>
            {allMethods.length} methods · {counts.supported} supported · {counts.limited} limited · {counts.unsupported} unavailable
          </div>
        </div>
        <div style={{
    display: 'flex',
    gap: 8,
    alignItems: 'center',
    flexWrap: 'wrap'
  }}>
          {}
          <div style={{
    display: 'flex',
    border: bd,
    borderRadius: 4,
    overflow: 'hidden'
  }}>
            {['mainnet', 'testnet', 'custom'].map(n => <button key={n} onClick={() => {
    setNetwork(n);
    setConnection('idle');
  }} style={{
    fontSize: 12,
    padding: '6px 12px',
    cursor: 'pointer',
    border: 'none',
    textTransform: 'capitalize',
    background: network === n ? c.maroon : 'transparent',
    color: network === n ? '#fff' : c.sub,
    fontWeight: network === n ? 600 : 400
  }}>
                {n}
              </button>)}
          </div>
          {network === 'custom' ? <input value={customEndpoint} onChange={e => {
    setCustomEndpoint(e.target.value);
    setConnection('idle');
  }} onBlur={validateEndpoint} placeholder="https://your-rpc" style={{
    fontSize: 12,
    fontFamily: mono,
    padding: '6px 10px',
    width: 220,
    background: c.input,
    color: c.text,
    border: bd,
    borderRadius: 4,
    outline: 'none'
  }} /> : <code style={{
    fontSize: 12,
    fontFamily: mono,
    color: c.sub,
    padding: '5px 10px',
    background: c.panel2,
    borderRadius: 4,
    border: bd,
    maxWidth: '100%',
    overflowWrap: 'anywhere'
  }}>{endpoint}</code>}
          <span title={connection === 'ok' ? 'Reachable' : connection === 'fail' ? 'Unreachable from this browser' : 'Not checked'} style={{
    display: 'inline-flex',
    alignItems: 'center',
    gap: 5,
    fontSize: 11,
    color: connection === 'ok' ? '#22c55e' : connection === 'fail' ? '#ef4444' : c.faint
  }}>
            <span style={{
    width: 8,
    height: 8,
    borderRadius: 9,
    background: connection === 'ok' ? '#22c55e' : connection === 'fail' ? '#ef4444' : c.faint
  }} />
            {connection === 'ok' ? 'Live' : connection === 'fail' ? 'Offline' : '—'}
          </span>
        </div>
      </div>

      {}
      <div style={{
    flex: 1,
    display: 'flex',
    overflow: 'hidden'
  }}>
        {}
        <div style={{
    width: isMobile ? '100%' : 320,
    flexShrink: 0,
    display: isMobile && mobileView !== 'list' ? 'none' : 'flex',
    flexDirection: 'column',
    borderRight: isMobile ? 'none' : bd,
    background: c.panel,
    overflow: 'hidden'
  }}>
          <div style={{
    padding: 14,
    borderBottom: bd
  }}>
            <input value={searchTerm} onChange={e => setSearchTerm(e.target.value)} placeholder="Search methods…" style={{
    width: '100%',
    fontSize: 13,
    padding: '8px 12px',
    background: c.input,
    color: c.text,
    border: bd,
    borderRadius: 4,
    outline: 'none',
    boxSizing: 'border-box'
  }} />
            <div style={{
    display: 'flex',
    flexWrap: 'wrap',
    gap: 5,
    marginTop: 10
  }}>
              <button onClick={() => setSelectedNamespace('all')} style={{
    fontSize: 11,
    padding: '3px 9px',
    borderRadius: 3,
    cursor: 'pointer',
    fontWeight: 600,
    border: `1px solid ${selectedNamespace === 'all' ? c.maroon : c.border}`,
    background: selectedNamespace === 'all' ? c.maroon : 'transparent',
    color: selectedNamespace === 'all' ? '#fff' : c.sub
  }}>
                All
              </button>
              {visibleNamespaces.map(ns => {
    const active = selectedNamespace === ns;
    const col = NAMESPACE_META[ns].color;
    const colFg = isDark && NAMESPACE_META[ns].colorDark ? NAMESPACE_META[ns].colorDark : col;
    return <button key={ns} onClick={() => setSelectedNamespace(ns)} style={{
      fontSize: 11,
      padding: '3px 9px',
      borderRadius: 3,
      cursor: 'pointer',
      fontWeight: 600,
      border: `1px solid ${active ? col : colFg}`,
      background: active ? col : 'transparent',
      color: active ? '#fff' : colFg,
      opacity: active ? 1 : 0.85
    }}>
                    {NAMESPACE_META[ns].label}
                  </button>;
  })}
            </div>
            <label style={{
    display: 'flex',
    alignItems: 'center',
    gap: 7,
    marginTop: 11,
    fontSize: 12,
    color: c.sub,
    cursor: 'pointer'
  }}>
              <input type="checkbox" checked={showAll} onChange={e => {
    const next = e.target.checked;
    setShowAll(next);
    if (!next) {
      if (selectedNamespace !== 'all') {
        const meta = NAMESPACE_META[selectedNamespace];
        if (meta && (meta.deprecated || meta.unavailable)) setSelectedNamespace('all');
      }
      if (selectedMethod && isHiddenByDefault(selectedMethod)) {
        runIdRef.current++;
        setSelectedMethod(null);
        setRequestResult(null);
        setIsLoading(false);
      }
    }
  }} style={{
    accentColor: c.maroon
  }} />
              Show deprecated & unavailable methods
            </label>
          </div>
          <div style={{
    flex: 1,
    overflowY: 'auto'
  }}>
            {filteredMethods.length === 0 && <div style={{
    padding: 24,
    fontSize: 13,
    color: c.faint,
    textAlign: 'center'
  }}>No methods match.</div>}
            {filteredMethods.map(mm => {
    const active = m && m.name === mm.name;
    return <button key={mm.name} onClick={() => selectMethod(mm)} style={{
      width: '100%',
      textAlign: 'left',
      padding: '9px 13px 9px 12px',
      cursor: 'pointer',
      border: 'none',
      borderLeft: `3px solid ${isDark && mm.meta.colorDark ? mm.meta.colorDark : mm.meta.color}`,
      borderBottom: bd,
      background: active ? isDark ? '#161616' : '#f0eef0' : 'transparent',
      display: 'block',
      opacity: mm.status === 'unsupported' ? 0.6 : 1
    }}>
                  <div style={{
      display: 'flex',
      alignItems: 'center',
      gap: 7
    }}>
                    <StatusDot status={mm.status} />
                    <code style={{
      fontFamily: mono,
      fontSize: 12.5,
      color: active ? c.text : isDark ? '#e5e5e5' : '#1a1a1a',
      fontWeight: active ? 600 : 500,
      whiteSpace: 'nowrap',
      overflow: 'hidden',
      textOverflow: 'ellipsis'
    }}>{mm.name}</code>
                  </div>
                  <div style={{
      fontSize: 11.5,
      color: c.faint,
      marginTop: 3,
      lineHeight: 1.35,
      display: '-webkit-box',
      WebkitLineClamp: 2,
      WebkitBoxOrient: 'vertical',
      overflow: 'hidden'
    }}>{mm.description}</div>
                </button>;
  })}
          </div>
        </div>

        {}
        <div style={{
    flex: 1,
    display: isMobile && mobileView !== 'detail' ? 'none' : 'flex',
    flexDirection: 'column',
    overflowY: 'auto',
    background: c.bg
  }}>
          {!m ? <div style={{
    flex: 1,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    color: c.faint,
    fontSize: 14,
    padding: 24,
    textAlign: 'center'
  }}>
              Select a method to see its reference, parameters, and runnable examples.
            </div> : <div style={{
    padding: isMobile ? 16 : 24,
    maxWidth: 860
  }}>
              {isMobile && <button onClick={() => setMobileView('list')} style={{
    fontSize: 12,
    color: c.sub,
    background: 'transparent',
    border: 'none',
    cursor: 'pointer',
    padding: 0,
    marginBottom: 12
  }}>← Methods</button>}
              <div style={{
    display: 'flex',
    alignItems: 'center',
    gap: 10,
    flexWrap: 'wrap'
  }}>
                <code style={{
    fontFamily: mono,
    fontSize: 19,
    fontWeight: 700,
    color: c.text
  }}>{m.name}</code>
                <Badge status={m.status} />
                <span style={{
    fontSize: 11,
    padding: '2px 8px',
    borderRadius: 3,
    color: '#fff',
    background: mMeta.color
  }}>{mMeta.label}</span>
              </div>
              <p style={{
    fontSize: 14,
    color: c.sub,
    marginTop: 10,
    lineHeight: 1.55
  }}>{m.description}</p>

              {mMeta.deprecated && <div style={{
    marginTop: 14,
    padding: '10px 14px',
    borderRadius: 4,
    background: '#f59e0b18',
    border: '1px solid #f59e0b55',
    fontSize: 12.5,
    color: isDark ? '#fbbf24' : '#92400e',
    lineHeight: 1.5
  }}>
                  <strong>Deprecated.</strong> The <code style={{
    fontFamily: mono
  }}>{m.namespace}_*</code> namespace is scheduled for removal. The <code style={{
    fontFamily: mono
  }}>enabled_legacy_sei_apis</code> setting in <code style={{
    fontFamily: mono
  }}>app.toml</code> controls access to it. Prefer standard <code style={{
    fontFamily: mono
  }}>eth_*</code> and <code style={{
    fontFamily: mono
  }}>debug_*</code> methods for new integrations.
                </div>}
              {mMeta.unavailable && <div style={{
    marginTop: 14,
    padding: '10px 14px',
    borderRadius: 4,
    background: isDark ? '#ffffff0a' : '#0000000a',
    border: bd,
    fontSize: 12.5,
    color: c.sub,
    lineHeight: 1.5
  }}>
                  The entire <code style={{
    fontFamily: mono
  }}>{m.namespace}_*</code> namespace is not exposed on Sei. {mMeta.blurb}
                </div>}
              {m.seiNote && <div style={{
    marginTop: 14,
    padding: '12px 14px',
    borderRadius: 4,
    background: c.maroon + (isDark ? '22' : '12'),
    border: `1px solid ${c.maroon}${isDark ? '66' : '44'}`,
    fontSize: 12.5,
    color: isDark ? '#e9b8c0' : '#600014',
    lineHeight: 1.55
  }}>
                  <div style={{
    fontWeight: 700,
    marginBottom: 4,
    fontSize: 11,
    letterSpacing: '0.04em',
    textTransform: 'uppercase'
  }}>Sei-specific behavior</div>
                  {m.seiNote}
                </div>}

              {}
              {m.params && m.params.length > 0 && <div style={{
    marginTop: 22
  }}>
                  <div style={{
    fontSize: 13,
    fontWeight: 700,
    marginBottom: 10
  }}>Parameters</div>
                  <div style={{
    display: 'flex',
    flexDirection: 'column',
    gap: 8
  }}>
                    {m.params.map(p => <div key={p.name} style={{
    padding: '10px 13px',
    borderRadius: 4,
    background: c.panel2,
    border: bd
  }}>
                        <div style={{
    display: 'flex',
    alignItems: 'center',
    gap: 8,
    flexWrap: 'wrap'
  }}>
                          <code style={{
    fontFamily: mono,
    fontSize: 12.5,
    color: isDark ? '#e9b8c0' : c.maroon,
    fontWeight: 600
  }}>{p.name}</code>
                          <span style={{
    fontSize: 10.5,
    padding: '1px 7px',
    borderRadius: 3,
    color: c.sub,
    background: isDark ? '#ffffff10' : '#00000008',
    border: bd,
    fontFamily: mono
  }}>{p.type}</span>
                        </div>
                        <div style={{
    fontSize: 12.5,
    color: c.sub,
    marginTop: 5,
    lineHeight: 1.5
  }}>{p.description}</div>
                      </div>)}
                  </div>
                </div>}

              {}
              {m.status !== 'unsupported' && <div style={{
    marginTop: 22
  }}>
                  <div style={{
    fontSize: 13,
    fontWeight: 700,
    marginBottom: 10,
    display: 'flex',
    alignItems: 'center',
    gap: 8
  }}>
                    Try it
                    <span style={{
    fontSize: 11,
    fontWeight: 400,
    color: c.faint
  }}>· {network === 'custom' ? endpoint || 'set a custom endpoint' : NETWORKS[network].label}</span>
                  </div>

                  {isWsOnly(m.name) && <div style={{
    padding: '10px 14px',
    borderRadius: 4,
    background: c.panel2,
    border: bd,
    fontSize: 12.5,
    color: c.sub,
    lineHeight: 1.5,
    marginBottom: 10
  }}>
                      This is a WebSocket subscription method. Connect to <code style={{
    fontFamily: mono
  }}>{wsEndpoint}</code> and send the payload below. To customize the subscription, edit the parameters.
                      {network === 'custom' && ' This URL is a best guess, derived from your HTTP endpoint. Sei serves WebSocket on a separate host (evm-ws…) from HTTP (evm-rpc…). If this URL differs from the actual WebSocket endpoint of your node, replace it.'}
                    </div>}
                  {m.params && m.params.length > 0 && <div style={{
    display: 'flex',
    flexDirection: 'column',
    gap: 8,
    marginBottom: 10
  }}>
                      {m.params.map(p => {
    const ex = p.example || '';
    const big = ex.trim().startsWith('{') || ex.trim().startsWith('[') || (p.type || '').toLowerCase().includes('object');
    const fieldId = `rpc-param-${p.name}`;
    const field = {
      id: fieldId,
      value: paramValues[p.name] !== undefined ? paramValues[p.name] : '',
      onChange: e => setParamValues(prev => ({
        ...prev,
        [p.name]: e.target.value
      })),
      placeholder: ex
    };
    return <div key={p.name}>
                            <label htmlFor={fieldId} style={{
      fontSize: 11,
      color: c.faint,
      fontFamily: mono,
      display: 'block',
      marginBottom: 3
    }}>{p.name}</label>
                            {big ? <textarea rows={2} {...field} style={{
      ...fieldStyle,
      resize: 'vertical'
    }} /> : <input {...field} style={fieldStyle} />}
                          </div>;
  })}
                    </div>}
                  {isMutation(m.name) && <div style={{
    fontSize: 11.5,
    color: c.faint,
    marginBottom: 8,
    lineHeight: 1.45
  }}>
                      This is a state-changing or signing method. Public RPC nodes hold no keys, so it generally returns an error unless you supply a signed payload.
                    </div>}

                  {}
                  <div style={{
    marginTop: 12
  }}>
                    <div style={{
    display: 'flex',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: 8,
    flexWrap: 'wrap',
    gap: 8
  }}>
                      <div style={{
    fontSize: 12,
    fontWeight: 700,
    color: c.sub
  }}>Request</div>
                      <div style={{
    display: 'flex',
    gap: 8,
    alignItems: 'center'
  }}>
                        <div style={{
    display: 'flex',
    gap: 3,
    flexWrap: 'wrap'
  }}>
                          {LANGUAGES.map(l => <button key={l.id} onClick={() => setSelectedLanguage(l.id)} style={{
    fontSize: 11,
    padding: '3px 9px',
    borderRadius: 3,
    cursor: 'pointer',
    border: 'none',
    background: selectedLanguage === l.id ? c.maroon : isDark ? '#161616' : '#ececee',
    color: selectedLanguage === l.id ? '#fff' : c.sub
  }}>
                              {l.name}
                            </button>)}
                        </div>
                        <CopyBtn text={codeExample} k="code" />
                      </div>
                    </div>
                    <CodeBlock text={codeExample} />
                  </div>

                  {}
                  {!isWsOnly(m.name) && <div style={{
    marginTop: 14
  }}>
                      <button onClick={execute} disabled={isLoading || !endpoint} style={{
    fontSize: 13,
    fontWeight: 600,
    padding: '8px 18px',
    borderRadius: 4,
    cursor: isLoading || !endpoint ? 'not-allowed' : 'pointer',
    border: 'none',
    background: c.maroon,
    color: '#fff',
    opacity: isLoading || !endpoint ? 0.55 : 1
  }}>
                        {isLoading ? 'Running…' : 'Run request'}
                      </button>
                      {requestResult && <div style={{
    marginTop: 12
  }}>
                          <div style={{
    display: 'flex',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: 6
  }}>
                            <span style={{
    fontSize: 11,
    color: requestResult.error ? '#ef4444' : '#22c55e',
    fontWeight: 600
  }}>{requestResult.error ? 'Error' : 'Result'}</span>
                            <CopyBtn text={JSON.stringify(requestResult, null, 2)} k="resp" />
                          </div>
                          <CodeBlock text={JSON.stringify(requestResult, null, 2)} maxHeight={280} />
                        </div>}
                    </div>}
                </div>}
            </div>}
        </div>
      </div>
    </div>;
};

Sei fully supports the standard Ethereum JSON-RPC API, so existing EVM tools (ethers.js, viem, Hardhat, Foundry, and others) work without changes. Use the explorer below to browse every method that Sei exposes and inspect its parameters. You can also run requests against a live endpoint and copy ready-to-use snippets in a range of popular languages. The text below the explorer is the authoritative reference for the request format, the remaining deprecated `sei_*` extensions, and address resolution.

<RPCMethodsViewer />

<Note>
  By default, the explorer lists only the current methods that are available. Each method has one of three status labels:

  * **Supported**: The method is registered and has a full implementation with standard Ethereum behavior.
  * **Limited**: The method is callable, but it returns a static value or has a Sei-specific caveat (shown in the method's **Sei-specific behavior** note). For example, `eth_coinbase` returns the fee-collector address, and `eth_getProof` returns an IAVL proof.
  * **Unavailable**: The method is not registered, returns an explicit error, or does not apply to Sei's architecture. This includes blob methods (`eth_blobBaseFee`), proof-of-work and uncle methods, and the `admin`, `miner`, `clique`, `engine`, `les`, and `personal` namespaces.

  By default, the explorer hides the remaining deprecated `sei_*` extensions and the unavailable methods. To browse them, enable **Show deprecated & unavailable methods**. The deprecated extensions are also documented under [Sei custom endpoints](#sei-custom-endpoints).
</Note>

## Overview

Sei supports the [Ethereum JSON-RPC API](https://ethereum.org/en/developers/docs/apis/json-rpc/). It also has some Sei-specific extensions for cross-VM operations, synthetic transactions, and other advanced features. Because Sei has [instant finality](/evm/differences-with-ethereum#finality), the `safe`, `finalized`, and `latest` block tags all resolve to the same (latest committed) block.

All endpoints follow the standard JSON-RPC format:

<Accordion title="JSON-RPC request/response format">
  **Request format**

  * HTTP method: always `POST`
  * Header: `accept: application/json`
  * Header: `content-type: application/json`
  * Body (JSON):
    * `id`: an arbitrary string identifier
    * `jsonrpc`: always "2.0"
    * `method`: endpoint name (for example, `eth_sendRawTransaction`)
    * `params`: an array that differs from endpoint to endpoint

  **Response format**

  * Body (JSON):
    * `id`: the same identifier as in the request
    * `jsonrpc`: always "2.0"
    * `result`: an object that differs from endpoint to endpoint
    * `error` (if applicable): error details
</Accordion>

### Network endpoints

| Network | EVM chain ID | HTTP endpoint | WebSocket endpoint |
| - | - | - | - |
| Sei Mainnet | `1329` (`0x531`) | `https://evm-rpc.sei-apis.com` | `wss://evm-ws.sei-apis.com` |
| Sei Testnet | `1328` (`0x530`) | `https://evm-rpc-testnet.sei-apis.com` | `wss://evm-ws-testnet.sei-apis.com` |

For more public and commercial endpoints, see [RPC providers](/learn/rpc-providers) and [Chains & endpoints](/learn/dev-chains).

### Tendermint `/status` endpoint

In addition to the EVM JSON-RPC surface, Sei nodes expose the underlying Tendermint (CometBFT) RPC, including the `/status` endpoint. Its `SyncInfo` object reports a `last_committed_block_height` field: the height of the last block finalized by consensus.

```bash theme={null}
curl -s $SEI_TENDERMINT_RPC/status | jq '.result.sync_info.last_committed_block_height'
```

The field is serialized to JSON as a string (`last_committed_block_height`), like the other height fields in `SyncInfo`.

| Field | JSON | Description |
| :- | :- | :- |
| `last_committed_block_height` | string | Height of the last block finalized by consensus. |

**Consensus-engine behavior:**

* **Under CometBFT**: Commit and app-apply happen in a single step, so `last_committed_block_height` is guaranteed to equal `latest_block_height`.
* **Under Autobahn**: The value is derived from the latest `CommitQC`. Consensus finalizes a block before the app executes it, so the invariant is `last_committed_block_height >= latest_block_height`. The two values can differ for a short time while the app catches up.

**`validator_info` shape.** The `validator_info` object in the `/status` response always includes both a `pub_key` and an `address` field. On nodes that are not validators, the response does not omit these fields. Instead, `pub_key` is a zero (empty) public key, `address` is derived from it, and `voting_power` is `0`. This keeps the response shape stable, so clients like CosmJS can parse `/status` without special handling for non-validator nodes. On validator nodes, `pub_key` and `voting_power` carry the real values.

<Note>
  Under Autobahn (`AutobahnConfigFile` set), the CometBFT block store is not populated. For this reason, `/status` derives `latest_block_height` and `latest_app_hash` from the app layer (`ABCIInfo`), not from the block store. Several other `SyncInfo` fields are also not populated in this mode: block hash and time, earliest-block metadata, `catching_up`, and the peer-height fields.
</Note>

### Tendermint block and validator endpoints under Autobahn

Under Autobahn (`AutobahnConfigFile` set), the CometBFT `BlockStore` and `StateStore` are not populated. These Tendermint RPC endpoints do not return empty or failing responses in this mode. Instead:

* `/block` and `/block_by_hash` route through the GigaRouter's in-memory state (the finalized global blocks that the Autobahn data layer retains).
* `/block_results` and `/validators` synthesize their responses (an empty result set and the genesis committee, respectively).

This keeps downstream consumers, including evmrpc, block explorers, and monitoring tools, working without each one branching on the consensus engine.

`/block` and `/block_by_hash` serve responses only for heights that are still inside Autobahn's retained window. Heights pruned per `RetainHeight` are no longer available. `/block_results` and `/validators` do not read the retained block data. They respond for any height up to the current ABCI head. Requests are validated against the current ABCI head, so heights above it return the same `ErrHeightExceedsChainHead`-class errors as the CometBFT path. Pruned heights on `/block` return `ErrHeightNotAvailable`.

| Endpoint | Autobahn behavior |
| :- | :- |
| `/block` | Returns the fully populated translated block at the requested height: `BlockID.Hash` (the Autobahn header hash), the header (`ChainID`, `Height`, `Time`), and `Data.Txs`. Other header fields, such as `AppHash`, `ProposerAddress`, and `LastCommit`, stay at zero values. |
| `/block_by_hash` | Resolves the block by its Autobahn header hash through an in-memory hash index. An unknown or wrong-size hash returns `{Block: nil}` with no error. This matches CometBFT semantics for a missing block. |
| `/block_results` | Returns a valid but empty `ResultBlockResults` at the requested height. `ConsensusParamUpdates.Block.MaxGas` is populated from the producer config. `TxsResults` (per-transaction `ExecTxResult` details) is empty on purpose, because `FinalizeBlock` responses are not persisted under Autobahn. |
| `/validators` | Returns the genesis committee for any height up to the current ABCI head. Under Autobahn, the committee is fixed at genesis (there is no validator-updates path). The endpoint does not read the retained block data, so pruned heights still answer. `block_height` matches the requested height. Pagination (`page` and `per_page`) behaves the same as on the CometBFT path. |

<Note>
  Because `FinalizeBlock` responses are not stored on disk under Autobahn, `/block_results` cannot return per-transaction execution results (`TxsResults` is empty). For per-transaction EVM data, use the EVM JSON-RPC methods `eth_getTransactionReceipt` and `eth_getBlockReceipts` instead.
</Note>

### Filter and subscription limits

<Info>
  By default, log filters (`eth_getLogs`, `eth_getFilterLogs`) have these limits:

  * **Open-ended block range:** up to 10,000 logs in one response
  * **Close-ended block range:** up to 2,000 blocks in one query

  Real-time subscriptions (`eth_subscribe` for `newHeads` and `logs`) are available over WebSocket only. For transport details, see [WebSocket connections](/evm/evm-parity/websocket).
</Info>

## Standard Ethereum endpoints

You can also browse every method below in the interactive explorer above. This section is the static, copy-friendly reference. Methods are grouped by purpose and labeled with their Sei support status. Block parameters accept a hex number or one of the tags `latest`, `earliest`, `pending`, `safe`, or `finalized`. On Sei, `safe`, `finalized`, and `latest` all resolve to the latest committed block because of [instant finality](/evm/differences-with-ethereum#finality). The remaining deprecated `sei_*` extensions are documented separately under [Sei custom endpoints](#sei-custom-endpoints).

<Accordion title="Send transactions">
  #### `eth_sendRawTransaction`

  **Supported.** Submits a signed, RLP-encoded raw EVM transaction to the network and returns its hash.

  **Sei-specific behavior:** Decodes the bytes to an ethtypes.Transaction, wraps it in a Cosmos MsgEVMTransaction, and broadcasts it through CometBFT. By default, it uses a CheckTx-level BroadcastTx (that is, `broadcast_tx_sync`), and slow mode uses BroadcastTxCommit. Non-zero CheckTx codes are returned as ABCI errors, not geth mempool errors. Legacy (non-1559) transactions must set gasPrice at or above the governance minimum (currently 50 gwei on Sei Mainnet). Blob (EIP-4844) transactions are not enabled. The method supports per-sender EvmProxy forwarding.

  **Under Autobahn (`AutobahnConfigFile` set):** Transaction broadcast routes through Autobahn's producer-backed mempool instead of CometBFT's `TxMempool`. This mempool admits EVM transactions strictly in sequential nonce order for each sender. It rejects a transaction with a bad-nonce error if its nonce does not match the sender's next expected nonce. Senders must therefore submit nonces contiguously.

  Under Autobahn, the default CheckTx-synchronous broadcast (`broadcast_tx_sync`, the same path named above) blocks while the mempool is full. It returns only after capacity is available. As a result, a default `eth_sendRawTransaction` call can stall for as long as the mempool stays full. The async path (`broadcast_tx_async`) may silently drop the transaction instead. The `unsafe_flush_mempool` Tendermint RPC endpoint is not supported under Autobahn and returns `unsafe_flush_mempool is not supported with autobahn mempool`.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `data` | DATA | Signed, RLP-encoded transaction bytes (0x-prefixed). |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_sendRawTransaction",
    "params": [
      "0x02f8b101808459682f00..."
    ]
  }
  ```

  #### `eth_sendTransaction`

  **Limited.** Signs a transaction with a node-hosted key and submits it in one call.

  **Sei-specific behavior:** Requires the private key of the 'from' address in the node's local test keyring. Production and public RPC nodes hold no hosted keys, so on those nodes this method returns 'from address does not have hosted key'. Always signs as LegacyTxType. Sign client-side and use `eth_sendRawTransaction` instead.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `args` | object | Transaction object (from, to, value, data, gas, nonce, and other fields). |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_sendTransaction",
    "params": [
      {
        "from": "0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55",
        "to": "0x7507454444fa193d39f1392076bc784b77a7a8ff",
        "value": "0x1"
      }
    ]
  }
  ```

  #### `eth_signTransaction`

  **Limited.** Signs a transaction with a node-hosted key and returns the signed payload without broadcasting it.

  **Sei-specific behavior:** Requires a node-hosted key for the from address. It does not work on public RPC nodes that hold no keys. Returns both the raw RLP bytes and the decoded transaction.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `args` | object | SendTxArgs transaction object to sign (from, to, gas, gasPrice, value, nonce, data). |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_signTransaction",
    "params": [
      {
        "from": "0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55",
        "to": "0x7507454444fa193d39f1392076bc784b77a7a8ff",
        "value": "0x1",
        "nonce": "0x0",
        "gas": "0x5208",
        "gasPrice": "0x3b9aca00"
      }
    ]
  }
  ```

  #### `eth_sign`

  **Limited.** Signs an EIP-191 personal message with a node-hosted key for the given address.

  **Sei-specific behavior:** Works only for addresses in the node's local test keyring. Production and public RPC nodes hold no hosted keys, so on those nodes this method returns 'address does not have hosted key'. Applies the EIP-191 personal-message TextHash before signing.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `address` | DATA, 20 bytes | Address whose hosted key signs the data. |
  | 2 | `data` | DATA | Message bytes to sign. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_sign",
    "params": [
      "0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55",
      "0xdeadbeef"
    ]
  }
  ```
</Accordion>

<Accordion title="Transaction lookup">
  #### `eth_getTransactionByHash`

  **Supported.** Returns the EVM transaction that matches the given hash, or null if it is not found.

  **Sei-specific behavior:** Looks up EVM transactions only. If the hash resolves to a non-EVM Cosmos transaction, the method returns an error. Pending lookups resolve the transaction directly from the CometBFT mempool through an EVM-hash index, not a geth txpool. As a result, the method finds a pending EVM transaction by its hash without scanning through pages of unconfirmed transactions.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `hash` | DATA, 32 bytes | Transaction hash. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getTransactionByHash",
    "params": [
      "0x828c91592453fe7c5bf743204495a35bf02b67b579b8f59ee7eea8af031d7c14"
    ]
  }
  ```

  #### `eth_getTransactionReceipt`

  **Supported.** Returns the receipt of a transaction by hash, or null if it is not found.

  **Sei-specific behavior:** The receipt is reconstructed from keeper.GetReceipt and CometBFT block data, not from a native MPT receipt trie. The status and logs use the standard Ethereum format.

  Under the Giga executor, an EVM transaction can bump the sender's nonce and then fail during state transition. For such a transaction, the method returns a `status=0` failed-transaction receipt. It does not return null indefinitely, which would hang clients that poll for the receipt. The known natural case is an EIP-7623 floor-data-gas shortfall (post-Pectra), which fails inside go-ethereum's `Execute()` before any opcode runs. This synthetic receipt is written at EndBlock, with `gasUsed` and `effectiveGasPrice` of 0.

  The `VmError` reason is not part of the `eth_getTransactionReceipt` response. To get it, use the non-standard `eth_getVMError` method.

  If a receipt exists but its block height is above the safe-latest watermark, the method returns JSON null rather than an error. This can happen, for example, when the Tendermint status lags the receipt store for a moment. JSON null is the Ethereum JSON-RPC 'not yet mined' signal, so clients poll again. This matches the behavior of `eth_getBlockByNumber`.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `hash` | DATA, 32 bytes | Transaction hash. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getTransactionReceipt",
    "params": [
      "0x828c91592453fe7c5bf743204495a35bf02b67b579b8f59ee7eea8af031d7c14"
    ]
  }
  ```

  #### `eth_getTransactionByBlockNumberAndIndex`

  **Supported.** Returns the EVM transaction at the given index within the block at the specified number.

  **Sei-specific behavior:** The index counts EVM transactions only. An out-of-range index returns a null result, not an error.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `blockNr` | BLOCKNUMBER | Block number or tag. |
  | 2 | `index` | QUANTITY | Transaction index within the block. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getTransactionByBlockNumberAndIndex",
    "params": [
      "latest",
      "0x0"
    ]
  }
  ```

  #### `eth_getTransactionByBlockHashAndIndex`

  **Supported.** Returns the EVM transaction at the given index within the block identified by hash.

  **Sei-specific behavior:** The index counts EVM transactions only. As with the block-number variant, an out-of-range index returns null.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `blockHash` | DATA, 32 bytes | Block hash. |
  | 2 | `index` | QUANTITY | Transaction index within the block. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getTransactionByBlockHashAndIndex",
    "params": [
      "0x5620c15afd9a1d0ab19d7560043df6e038d731c6205974dca7a55900071e3864",
      "0x0"
    ]
  }
  ```

  #### `eth_getTransactionCount`

  **Supported.** Returns the number of transactions sent from an address (nonce) at a given block.

  **Sei-specific behavior:** For the 'pending' tag, Sei returns EvmNextPendingNonce from the CometBFT mempool. If the sender is sharded to an EvmProxy, Sei redirects the request there. The safe, finalized, and latest tags are equivalent because of instant finality.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `address` | DATA, 20 bytes | Account address. |
  | 2 | `blockNrOrHash` | BLOCKNUMBER or DATA | Block number, tag, or hash. The 'pending' tag returns the next pending nonce. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getTransactionCount",
    "params": [
      "0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55",
      "latest"
    ]
  }
  ```

  #### `eth_getNonce`

  **Limited.** Sei-specific helper that returns the current EVM nonce for an address (latest state only).

  **Sei-specific behavior:** This non-standard Sei extension is exposed as `eth_getNonce` and implemented as StateAPI.GetNonce in `state.go` (not on TransactionAPI). Unlike `eth_getTransactionCount`, it takes no block tag (latest only, through ctxProvider(LatestCtxHeight)) and returns a bare uint64. For standard nonce queries, prefer `eth_getTransactionCount`.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `address` | DATA, 20 bytes | Account address. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getNonce",
    "params": [
      "0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55"
    ]
  }
  ```

  #### `eth_getTransactionErrorByHash`

  **Limited.** Sei extension that returns the recorded VM error string for a transaction by hash (empty string if it succeeded or is not found).

  **Sei-specific behavior:** This non-standard Sei extension is registered under the eth namespace. Unlike `eth_getVMError`, this method returns an empty string and no error for a not-found lookup.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `hash` | DATA, 32 bytes | Transaction hash. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getTransactionErrorByHash",
    "params": [
      "0x828c91592453fe7c5bf743204495a35bf02b67b579b8f59ee7eea8af031d7c14"
    ]
  }
  ```

  #### `eth_getVMError`

  **Limited.** Sei extension that returns the EVM VM error string recorded in a transaction's receipt by hash.

  **Sei-specific behavior:** This non-standard Sei extension is registered under the eth namespace. It returns the receipt's VmError field and propagates a not-found error. In contrast, `eth_getTransactionErrorByHash` returns an empty string when the transaction is not found.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `hash` | DATA, 32 bytes | Transaction hash. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getVMError",
    "params": [
      "0x828c91592453fe7c5bf743204495a35bf02b67b579b8f59ee7eea8af031d7c14"
    ]
  }
  ```
</Accordion>

<Accordion title="Account information">
  #### `eth_getBalance`

  **Supported.** Returns the wei balance of an account at a given block.

  **Sei-specific behavior:** The balance reflects the account's SEI bank balance (18-decimal wei representation). Both EVM and non-EVM transactions (Cosmos bank send or wasm) can change it. The height is resolved through the watermark manager with a state-version guard.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `address` | DATA, 20 bytes | Account address. |
  | 2 | `blockNrOrHash` | BLOCKNUMBER or DATA | Block number, tag (latest/earliest/pending/safe/finalized), or hash. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getBalance",
    "params": [
      "0xDa52B9E673d1f48FcD9916b3F606A136a8eA5e55",
      "latest"
    ]
  }
  ```

  #### `eth_getCode`

  **Supported.** Returns the contract bytecode at an address for a given block.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `address` | DATA, 20 bytes | Contract address. |
  | 2 | `blockNrOrHash` | BLOCKNUMBER or DATA | Block number, tag, or hash. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getCode",
    "params": [
      "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7",
      "latest"
    ]
  }
  ```

  #### `eth_getStorageAt`

  **Supported.** Returns the value stored at a storage slot of an address at a given block.

  **Sei-specific behavior:** Reads the slot value directly from the EVM keeper, not from an MPT trie. The slot key must decode to at most 32 bytes.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `address` | DATA, 20 bytes | Contract address. |
  | 2 | `key` | DATA, 32 bytes | Storage slot key (hex, up to 32 bytes). |
  | 3 | `blockNrOrHash` | BLOCKNUMBER or DATA | Block number, tag, or hash. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getStorageAt",
    "params": [
      "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7",
      "0x0",
      "latest"
    ]
  }
  ```

  #### `eth_getProof`

  **Limited.** Returns a Merkle proof for an account and the requested storage slots.

  **Sei-specific behavior:** Sei stores state in an IAVL-style tree, not an Ethereum Merkle-Patricia trie. The handler unwraps the EVM store through any intervening wrappers (cache, tracing, Giga cache, prefix stores). It continues until it reaches an underlying proof-capable queryable store: classic IAVL, a store/v2 memiavl commitment, or any other proof-capable root. Proofs therefore work across these backends, not only on classic IAVL. If the handler cannot reach a proof-capable queryable store, it returns `cannot find a proof-capable queryable KV store`.

  The result is a Sei-specific ProofResult\{address, hexValues, storageProof}. Its storageProof entries are CometBFT/IAVL crypto.ProofOps, not eth-style MPT proof nodes. The result has no accountProof, balance, codeHash, nonce, or storageHash field (Sei has no per-account state root). Standard `eth_getProof` verifiers do not work with it.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `address` | DATA, 20 bytes | Account address. |
  | 2 | `storageKeys` | array of DATA, 32 bytes | Storage slot keys to prove (bounded by MaxStorageKeysPerProof). |
  | 3 | `blockNrOrHash` | BLOCKNUMBER or DATA | Block number, tag, or hash. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getProof",
    "params": [
      "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7",
      [
        "0x0"
      ],
      "latest"
    ]
  }
  ```

  #### `eth_accounts`

  **Limited.** Returns the list of addresses for which the node holds hosted keys.

  **Sei-specific behavior:** The list comes only from the node's local test keyring. Production and public RPC nodes hold no hosted keys, so on those nodes this method returns an empty list. Sign client-side and use `eth_sendRawTransaction`.

  **Parameters:** none.
</Accordion>

<Accordion title="Block information">
  #### `eth_getBlockByNumber`

  **Supported.** Returns block information by number or tag, with full transactions when fullTx is true.

  **Sei-specific behavior:** Under the eth namespace, only EVM transactions are indexed. Synthetic and bank-transfer transactions are excluded. Block number 0 returns a synthetic genesis block, for compatibility with The Graph. Future or non-existent numeric blocks return null. Uncle and PoW header fields (sha3Uncles, nonce, mixHash, difficulty) are placeholders, and the uncles array is always empty (CometBFT consensus). The safe, finalized, and latest tags are equivalent because of instant finality.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `number` | BLOCKNUMBER | Block number (hex) or tag (latest/safe/finalized/pending/earliest). |
  | 2 | `fullTx` | boolean | If true, the block includes full transaction objects. Otherwise, it includes only hashes. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getBlockByNumber",
    "params": [
      "latest",
      true
    ]
  }
  ```

  #### `eth_getBlockByHash`

  **Supported.** Returns block information by block hash, with full transactions when fullTx is true.

  **Sei-specific behavior:** Block hashes are CometBFT block hashes, computed from the Tendermint header. They differ from Ethereum block hashes and are not interchangeable across chains. Under the eth namespace, synthetic transactions and bank transfers are excluded. The uncles array is always empty.

  The genesis block hash is `0xF9D3845DF25B43B1C6926F3CEDA6845C17F5624E12212FD8847D0BA01DA1AB9E`. It is a synthetic constant, identical on every Sei network. The node returns it in this uppercase form, and lookups are case-insensitive. The method recognizes this hash and returns the encoded genesis block directly. This keeps hash-based lookups consistent with `eth_getBlockByNumber("0x0")`. Other unknown or zero hashes return null.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `blockHash` | DATA, 32 bytes | Block hash. |
  | 2 | `fullTx` | boolean | If true, the block includes full transaction objects. Otherwise, it includes only hashes. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getBlockByHash",
    "params": [
      "0x5620c15afd9a1d0ab19d7560043df6e038d731c6205974dca7a55900071e3864",
      false
    ]
  }
  ```

  #### `eth_getBlockTransactionCountByNumber`

  **Supported.** Returns the number of EVM transactions in a block by number, as a hex quantity.

  **Sei-specific behavior:** Counts the same transactions that appear in the transaction list of `eth_getBlockByNumber`. EVM transactions are counted only when a receipt exists for them. Synthetic (wasm `MsgExecuteContract`) and bank-transfer (`MsgSend`) transactions remain excluded. Genesis returns 0x0. Non-existent or future blocks return null.

  The receipt store can be configured with a smaller `KeepRecent` than the block and state stores. For this reason, the method verifies that the requested block's receipts have not been pruned before it counts. If they have, it returns an error of the form `requested height N receipts have been pruned; earliest available is M` instead of a count. As a result, the call can fail for older blocks even when the block data itself is still available.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `number` | BLOCKNUMBER | Block number or tag. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getBlockTransactionCountByNumber",
    "params": [
      "latest"
    ]
  }
  ```

  #### `eth_getBlockTransactionCountByHash`

  **Supported.** Returns the number of EVM transactions in a block by hash, as a hex quantity.

  **Sei-specific behavior:** Counts EVM transactions only. Synthetic and bank-transfer transactions are excluded. The genesis hash returns 0x0, and an unknown hash returns null. Like `eth_getBlockTransactionCountByNumber`, it returns a "receipts have been pruned" error if the requested block's receipts have been pruned from the receipt store.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `blockHash` | DATA, 32 bytes | Block hash. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getBlockTransactionCountByHash",
    "params": [
      "0x5620c15afd9a1d0ab19d7560043df6e038d731c6205974dca7a55900071e3864"
    ]
  }
  ```

  #### `eth_getBlockReceipts`

  **Supported.** Returns all EVM transaction receipts for a given block.

  **Sei-specific behavior:** Under the eth namespace, synthetic and shell receipts are excluded (includeShellReceipts=false). Genesis returns an empty array. An empty (zero), non-existent, or unknown block hash returns `result: null` instead of an error. This matches the Ethereum RPC spec. The transactionIndex value is recomputed sequentially over the compacted receipt list.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `blockNrOrHash` | BLOCKNUMBER or DATA | Block number, tag, or hash. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getBlockReceipts",
    "params": [
      "latest"
    ]
  }
  ```
</Accordion>

<Accordion title="Blockchain information">
  #### `eth_blockNumber`

  **Supported.** Returns the number of the most recent committed EVM block as a hex uint64.

  **Sei-specific behavior:** The block height comes from the latest CometBFT height. The latest committed block is already final on Sei (instant finality, so latest == safe == finalized).

  **Parameters:** none.

  #### `eth_chainId`

  **Supported.** Returns the EVM chain ID as a hex big int.

  **Sei-specific behavior:** The value comes from the x/evm keeper. Sei Mainnet is 1329 (`0x531`), and Sei Testnet is 1328 (`0x530`).

  **Parameters:** none.

  #### `eth_coinbase`

  **Limited.** Returns the block reward beneficiary (coinbase) address.

  **Sei-specific behavior:** Sei has no miner. This method returns the Cosmos fee-collector module address (GetFeeCollectorAddress), not a validator or miner address. The COINBASE opcode returns the same value.

  **Parameters:** none.

  #### `eth_gasPrice`

  **Limited.** Returns a suggested gas price in wei (hex).

  **Sei-specific behavior:** The method uses a Sei-specific congestion heuristic, not a raw mempool oracle. The logic is in InfoAPI.GasPrice and GasPriceHelper (`info.go`). When the chain is uncongested, the method returns baseFee \* 110/100 (base fee +10%). When the chain is congested, it returns medianRewardPrevBlock + baseFee. This is the 50th-percentile priority-fee reward from the previous block, added to the base fee.

  The base fee comes from the x/evm keeper (GetNextBaseFeePerGas) and is itself floored at the governance-set minimum base fee. The RPC handler applies no other explicit lower-bound clamp. The Sei Mainnet minimum gas price (approximately 50 gwei) is enforced for transaction acceptance at the mempool or ante-handler level, not inside `eth_gasPrice`.

  **Parameters:** none.

  #### `eth_maxPriorityFeePerGas`

  **Limited.** Returns a suggested priority fee (tip) per gas in wei (hex).

  **Sei-specific behavior:** When the chain is uncongested, the method returns a hardcoded 1 gwei (defaultPriorityFeePerGas). It derives the tip from the previous block's 50th-percentile reward only when the chain is congested. The Sei docs advise you to use a single gasPrice and omit the EIP-1559 fee fields.

  **Parameters:** none.

  #### `eth_feeHistory`

  **Supported.** Returns base fees, gas-used ratios, and reward percentile data over a range of blocks.

  **Sei-specific behavior:** Base fees and rewards reflect Sei's x/evm fee market (GetNextBaseFee), not an Ethereum EIP-1559 mempool. Sei does not burn the base fee. The method is watermark-aware: pruned or historical blocks may not be available as far back as on Ethereum archive nodes.

  On ranges where every block has base-fee data, `baseFeePerGas` contains one more element than `gasUsedRatio`. This matches go-ethereum and execution-apis semantics. The trailing element is the projected base fee for the child of the newest block in the range. It is appended only when the newest block's own header base fee was available.

  Heights with pruned or partial base-fee data are skipped in `baseFeePerGas`, but they still contribute a `gasUsedRatio` row (0.0 fallback). On ranges with pruned history, the two arrays can therefore diverge from that `+1` relationship. Each block's base fee uses header base fee semantics. That is the same value that the block header reports: `GetNextBaseFee` at the parent's committed height. For early blocks, the base fee falls back to `DefaultMinFeePerGas`.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `blockCount` | QUANTITY | Number of blocks in the requested range. |
  | 2 | `newestBlock` | BLOCKNUMBER | Highest block of the range (number or tag). |
  | 3 | `rewardPercentiles` | array of float | Monotonically increasing percentiles to sample for priority-fee rewards. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_feeHistory",
    "params": [
      "0x5",
      "latest",
      [
        25,
        50,
        75
      ]
    ]
  }
  ```

  #### `net_version`

  **Supported.** Returns the network ID (chain ID) as a decimal string.

  **Sei-specific behavior:** Returns the EVM chain ID in decimal (an alias of `eth_chainId`): `'1329'` on Sei Mainnet and `'1328'` on Sei Testnet.

  **Parameters:** none.

  #### `web3_clientVersion`

  **Supported.** Returns the client version string.

  **Sei-specific behavior:** Reports a synthetic 'Geth/\<os>-\<arch>/\<goVersion>' string (Sei's EVM is backed by go-ethereum). The string does not include the actual sei-chain or `seid` version, so it is not a reliable Sei version indicator.

  **Parameters:** none.
</Accordion>

<Accordion title="Filters & subscriptions">
  #### `eth_newFilter`

  **Supported.** Creates a log filter for the given criteria and returns a filter ID for later polling.

  **Sei-specific behavior:** Has the same range and size caps as `eth_getLogs`. Open-ended ranges return up to 10,000 logs (DefaultMaxLogLimit). Close-ended ranges are limited to 2,000 blocks (DefaultMaxBlockRange), and large queries are rate-limited.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `crit` | object | Filter criteria: fromBlock, toBlock (or blockHash), address(es), and topics. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_newFilter",
    "params": [
      {
        "fromBlock": "latest",
        "address": "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7",
        "topics": []
      }
    ]
  }
  ```

  #### `eth_newBlockFilter`

  **Supported.** Creates a filter that tracks newly arrived block hashes and returns its ID.

  **Parameters:** none.

  #### `eth_getFilterChanges`

  **Supported.** Polls a filter and returns new logs (log filters) or block hashes (block filters) since the last poll.

  **Sei-specific behavior:** For log filters, the method returns an empty array (`[]`) instead of `null` when no logs match. It does the same when a bounded filter's block range has been fully consumed. This is in line with the Ethereum JSON-RPC spec.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `filterID` | QUANTITY/ID | Filter ID from a New\*Filter call. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getFilterChanges",
    "params": [
      "0x1"
    ]
  }
  ```

  #### `eth_getFilterLogs`

  **Supported.** Returns all logs that match a previously created log filter, including historical logs.

  **Sei-specific behavior:** Has the same caps as `eth_getLogs` (2,000-block range, 10,000-log limit). Large queries are rate-limited.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `filterID` | QUANTITY/ID | Filter ID from a NewFilter call. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getFilterLogs",
    "params": [
      "0x1"
    ]
  }
  ```

  #### `eth_getLogs`

  **Supported.** Returns the logs that match the given filter criteria.

  **Sei-specific behavior:** Returns EVM logs only. The hard limits are a maximum of 2,000 blocks per close-ended query and up to 10,000 logs per response. A query that exceeds the range limit fails with 'block range too large'. Large queries are rate-limited globally.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `crit` | object | Filter criteria: fromBlock, toBlock (or blockHash), address(es), topics. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getLogs",
    "params": [
      {
        "fromBlock": "0x0",
        "toBlock": "latest",
        "address": "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7",
        "topics": []
      }
    ]
  }
  ```

  #### `eth_uninstallFilter`

  **Supported.** Removes a previously installed filter by ID. Returns true if the filter existed and was removed.

  **Sei-specific behavior:** Returns false, not an error, if the filter did not exist. Filters also expire automatically when they are not polled.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `filterID` | QUANTITY/ID | Filter ID to remove. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_uninstallFilter",
    "params": [
      "0x1"
    ]
  }
  ```

  #### `eth_subscribe`

  **Limited.** Opens a WebSocket-only push subscription for newHeads or logs notifications.

  **Sei-specific behavior:** Available over WebSocket only. SubscriptionAPI is not registered on the HTTP server, so over HTTP the method returns rpc.ErrNotificationsUnsupported. Only 'newHeads' and 'logs' are implemented in source. There is no 'newPendingTransactions' subscription, although some client docs imply otherwise. MaxSubscriptionsNewHead caps newHeads subscriptions.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `subscriptionType` | string | Subscription name: 'newHeads' or 'logs'. |
  | 2 | `filter` | object | Optional filter criteria (address/topics) for the 'logs' subscription. |

  The `filter` object applies only to `logs` subscriptions. For `newHeads`, pass the subscription name alone: `"params": ["newHeads"]`.

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_subscribe",
    "params": [
      "logs",
      {
        "address": "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7",
        "topics": []
      }
    ]
  }
  ```

  #### `eth_unsubscribe`

  **Supported.** Cancels an existing WebSocket subscription by ID. Returns true on success.

  **Sei-specific behavior:** Available over WebSocket only. It has no effect over HTTP, where notifications are not supported.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `subscriptionID` | string | The subscription ID returned by a prior `eth_subscribe` call. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_unsubscribe",
    "params": [
      "0x9cef478923ff08bf67fde6c64013158d"
    ]
  }
  ```
</Accordion>

<Accordion title="Simulation">
  #### `eth_call`

  **Supported.** Executes a read-only message call against state without creating a transaction. Supports state and block overrides.

  **Sei-specific behavior:** Gas is capped by RPCGasCap, and execution time is capped by RPCEVMTimeout. A fail-fast limiter may reject the call with 'eth\_call rejected due to rate limit: server busy'. Canonical EVM\<->Sei address resolution uses `eth_call` to the addr precompile at 0x0000000000000000000000000000000000001004.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `args` | object | Call object (to, from, data/input, gas, gasPrice/maxFeePerGas, value). |
  | 2 | `blockNrOrHash` | BLOCKNUMBER or DATA | Block number, tag, or hash. Defaults to latest. |
  | 3 | `overrides` | object | Optional per-account state overrides (balance, code, nonce, state). |
  | 4 | `blockOverrides` | object | Optional block-context overrides (number, time, coinbase). |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_call",
    "params": [
      {
        "to": "0x0000000000000000000000000000000000001004",
        "data": "0x0c3c20ed000000000000000000000000Da52B9E673d1f48FcD9916b3F606A136a8eA5e55"
      },
      "latest"
    ]
  }
  ```

  #### `eth_estimateGas`

  **Supported.** Estimates the gas needed to execute a transaction.

  **Sei-specific behavior:** The method is bounded by RPCGasCap and protected by a fail-fast limiter. The block gas limit on Sei is 12.5M. Parallel execution can make estimates vary slightly, so set gasLimit with a modest buffer.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `args` | object | Transaction call object. |
  | 2 | `blockNrOrHash` | BLOCKNUMBER or DATA | Optional block number, tag, or hash. Defaults to latest. |
  | 3 | `overrides` | object | Optional state overrides. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_estimateGas",
    "params": [
      {
        "to": "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7",
        "data": "0x18160ddd"
      },
      "latest"
    ]
  }
  ```

  #### `eth_estimateGasAfterCalls`

  **Limited.** Estimates gas for a transaction after it applies a sequence of preceding calls to the same simulated state.

  **Sei-specific behavior:** This is a non-standard Sei/geth extension (not part of the standard Ethereum JSON-RPC spec). It has the same gas-cap and fail-fast-limiter behavior as `eth_estimateGas`.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `args` | object | The final call to estimate gas for. |
  | 2 | `calls` | array of object | Ordered list of preceding calls applied before the estimate. |
  | 3 | `blockNrOrHash` | BLOCKNUMBER or DATA | Optional block number, tag, or hash. Defaults to latest. |
  | 4 | `overrides` | object | Optional state overrides. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_estimateGasAfterCalls",
    "params": [
      {
        "to": "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7",
        "data": "0x"
      },
      [],
      "latest"
    ]
  }
  ```

  #### `eth_createAccessList`

  **Supported.** Generates an EIP-2930 access list (and gas used) for a transaction.

  **Sei-specific behavior:** Defaults to the pending block tag, as geth does. If a VM error occurs during simulation, the method reports it in the result's 'error' field instead of failing the RPC.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `args` | object | Transaction call object. |
  | 2 | `blockNrOrHash` | BLOCKNUMBER or DATA | Optional block number, tag, or hash. Defaults to pending. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_createAccessList",
    "params": [
      {
        "to": "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7",
        "data": "0x"
      },
      "pending"
    ]
  }
  ```
</Accordion>

<Accordion title="Transaction pool">
  #### `txpool_content`

  **Limited.** Returns the transactions currently in the pool, grouped by sender address and nonce into pending and queued buckets.

  **Sei-specific behavior:** As a simplification, the method reports every unconfirmed EVM transaction from the CometBFT mempool under 'pending'. The 'queued' bucket is always empty (there is no geth-style nonce-gap distinction between pending and queued). The result set is truncated to the node's MaxTxPoolTxs config, so it may not reflect the entire mempool.

  **Parameters:** none.
</Accordion>

<Accordion title="Debugging & tracing">
  #### `debug_traceTransaction`

  **Supported.** Replays a transaction by hash and returns an execution trace from the configured tracer.

  **Sei-specific behavior:** Available over HTTP only, because the debug namespace is not registered on the WebSocket server. Supports geth tracers: callTracer, prestateTracer, flatCallTracer, and the struct (opcode) logger. TraceBaker pre-bakes and caches the results of callTracer, prestateTracer, and flatCallTracer. Requires trace-enabled or archive state for the target height.

  The max block lookback guard (`max_trace_lookback_blocks`) applies. If a request's target block is older than the configured lookback, the request is rejected with an error of the form `block number X is beyond max lookback of Y`. Each such request increments the `evmrpc_historical_debug_trace_attempts_total` metric. This guard applies consistently across all `debug_trace*` endpoints.

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `hash` | DATA, 32 bytes | Transaction hash to trace. |
  | 2 | `config` | object | Optional tracer config (tracer name, tracerConfig, timeout, reexec, disableStorage/Stack/Memory). |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "debug_traceTransaction",
    "params": [
      "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060",
      {
        "tracer": "callTracer"
      }
    ]
  }
  ```

  #### `debug_traceBlockByNumber`

  **Supported.** Traces all transactions in a block by number and returns per-transaction execution traces.

  **Sei-specific behavior:** Available over HTTP only. The safe, finalized, and latest tags are equivalent because of instant finality. The `max_trace_lookback_blocks` historical guard applies (see `debug_traceTransaction`).

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `number` | BLOCKNUMBER | Block number or tag. |
  | 2 | `config` | object | Optional tracer config. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "debug_traceBlockByNumber",
    "params": [
      "latest",
      {
        "tracer": "callTracer"
      }
    ]
  }
  ```

  #### `debug_traceBlockByHash`

  **Supported.** Traces all transactions in a block by hash and returns per-transaction execution traces.

  **Sei-specific behavior:** Available over HTTP only. The `max_trace_lookback_blocks` historical guard applies (see `debug_traceTransaction`).

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `hash` | DATA, 32 bytes | Block hash. |
  | 2 | `config` | object | Optional tracer config. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "debug_traceBlockByHash",
    "params": [
      "0x5620c15afd9a1d0ab19d7560043df6e038d731c6205974dca7a55900071e3864",
      {
        "tracer": "callTracer"
      }
    ]
  }
  ```

  #### `debug_traceCall`

  **Supported.** Executes and traces a call against a block's state without creating a transaction.

  **Sei-specific behavior:** Available over HTTP only. Arbitrary geth tracer names pass through. Tracing on the pending block is not supported. The `max_trace_lookback_blocks` historical guard applies (see `debug_traceTransaction`).

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `args` | object | Transaction call object. |
  | 2 | `blockNrOrHash` | BLOCKNUMBER or DATA | Block number, tag, or hash. |
  | 3 | `config` | object | Optional trace-call config (tracer name, state overrides, block overrides). |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7",
        "data": "0x70a08231"
      },
      "latest",
      {
        "tracer": "callTracer"
      }
    ]
  }
  ```

  #### `debug_traceStateAccess`

  **Limited.** Sei extension that replays a transaction and returns its app/tendermint/receipt state-access traces.

  **Sei-specific behavior:** This Sei-specific extension is not part of the upstream go-ethereum debug namespace. It is available over HTTP only and subject to the availability guards for historical debug traces. The `max_trace_lookback_blocks` historical guard applies (see `debug_traceTransaction`).

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `hash` | DATA, 32 bytes | Transaction hash whose state accesses are returned. |

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "debug_traceStateAccess",
    "params": [
      "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060"
    ]
  }
  ```

  #### `debug_traceTransactionProfile`

  **Limited.** Sei extension that replays a transaction by hash and returns its execution trace with a detailed timing and store-access profile.

  **Sei-specific behavior:** This Sei-specific extension is not part of the upstream go-ethereum debug namespace. It is available over HTTP only and subject to the availability guards for historical debug traces.

  In addition to the standard trace result, the method returns a `profile` object that shows where the time was spent. The profile has the total wall time, the historical DB lookup time, and per-phase timings. The phases are transaction lookup, block load, historical transaction replay, block-context build, transaction preparation, execution, and trace-result assembly. The method also returns a per-module `store` access trace. This trace has reads, iterators with the keys they surfaced, and per-operation `stats` roll-ups.

  Per-transaction caps bound the trace size. For each module, the trace retains at most 16 iterators and 64 keys per iterator, and `truncated` flags any overflow. To run this method across a whole block range and generate aggregate reports, use the `seidb trace-profile-report` command. The `max_trace_lookback_blocks` historical guard applies (see `debug_traceTransaction`).

  **Parameters:**

  | # | Name | Type | Description |
  | :- | :- | :- | :- |
  | 1 | `hash` | DATA, 32 bytes | Transaction hash to trace and profile. |
  | 2 | `config` | object | Optional tracer config (tracer name, tracerConfig, timeout, reexec, disableStorage/Stack/Memory). |

  The response `result` contains a `trace` field (the standard tracer output) and a `profile` object with this shape:

  * `totalNanos`: total wall-clock nanoseconds for the profiled trace.
  * `historicalDbLookupNanos`: nanoseconds spent in historical store lookups (get, has, iterator, iteratorNext).
  * `otherNanos`: remaining time not attributed to historical lookups or execution.
  * `phases`: the per-phase timings `lookupTransactionNanos`, `loadBlockNanos`, `replayHistoricalTxsNanos`, `buildBlockContextNanos`, `prepareTxNanos`, `executionNanos`, and `traceResultNanos`.
  * `store`: the per-module store access trace, with `modules` (each with `reads`, `has`, `iterators`, and per-operation `stats`) and top-level `stats`.

  **Example request:**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "debug_traceTransactionProfile",
    "params": [
      "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060",
      {
        "timeout": "60s"
      }
    ]
  }
  ```

  **Example response (trimmed):**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "trace": { "...": "standard tracer output" },
      "profile": {
        "totalNanos": 18422119,
        "historicalDbLookupNanos": 10021554,
        "otherNanos": 8400565,
        "phases": {
          "lookupTransactionNanos": 310221,
          "loadBlockNanos": 902114,
          "replayHistoricalTxsNanos": 6114203,
          "buildBlockContextNanos": 421900,
          "prepareTxNanos": 188212,
          "executionNanos": 9873341,
          "traceResultNanos": 612128
        }
      }
    }
  }
  ```
</Accordion>

## Sei custom endpoints

Sei keeps four legacy custom endpoints for address resolution, cross-VM transaction lookup, and synthetic receipts.

<Warning>
  For new integrations, use standard `eth_*` and `debug_*` methods. The four remaining `sei_*` methods are deprecated and scheduled for removal.

  The `sei2_*` namespace has been removed. Most legacy `sei_*` methods have also been removed, including block, filter, log, signing, association, and transaction lookup methods. The `sei_*` cleanup is tracked in [sei-chain PR #3927](https://github.com/sei-protocol/sei-chain/pull/3927).
</Warning>

<Note>No remaining block or filter method can discover synthetic logs from Cosmos-originated transactions. If you already know a synthetic transaction hash, enable `sei_getTransactionReceipt` to fetch its receipt and logs.</Note>

The `enabled_legacy_sei_apis` setting under `[evm]` in `app.toml` controls access. Only methods explicitly listed in this allowlist are available. Disabled methods return a standard JSON-RPC error (code `-32601`, data `"legacy_sei_deprecated"`). Allowed single-object calls pass through unchanged, with an optional `Sei-Legacy-RPC-Deprecation` HTTP response header that signals deprecation.

The gate handles JSON-RPC batches. It does not pass them through as a whole. Only allowed methods are forwarded to the inner handler. The handler then merges the responses by matching the JSON-RPC `id` of each response. Disallowed methods return the usual `-32601` legacy deprecation error in their slot. A batch element that is not a JSON object returns a JSON-RPC `-32600` `"Invalid Request"` error in its slot.

In JSON-RPC 2.0, requests that omit the `id` member are notifications. They do not produce a response entry, and this also applies within a batch. A request with `"id": null` is not a notification and receives a response. If a batch produces no response objects, the gateway returns an empty HTTP body with HTTP 200 instead of an empty JSON array (`[]`).

### Legacy API configuration

The `enabled_legacy_sei_apis` setting controls which remaining `sei_*` methods are accessible on the EVM HTTP endpoint. By default, `seid init` enables the three address and cross-VM lookup helpers:

```toml theme={null}
[evm]
enabled_legacy_sei_apis = [
  "sei_getSeiAddress",
  "sei_getEVMAddress",
  "sei_getCosmosTx",

  # Optional: enable synthetic receipt lookup.
  # "sei_getTransactionReceipt",
]
```

Only these four methods are available:

| Method | Description |
| - | - |
| `sei_getSeiAddress` | Returns the Sei address associated with an EVM address. |
| `sei_getEVMAddress` | Returns the EVM address associated with a Sei address. |
| `sei_getCosmosTx` | Returns the wrapping Cosmos transaction hash as uppercase hexadecimal without a `0x` prefix. |
| `sei_getTransactionReceipt` | Returns a receipt, including a synthetic receipt when its transaction hash is known. |

### Address resolution

To resolve the EVM (`0x…`) ↔ Sei (`sei1…`) address pair, use the **`addr` precompile at `0x0000000000000000000000000000000000001004`** through a standard `eth_call`. The precompile is available on every Sei RPC and is not part of the deprecated `sei_*` namespace. It is the canonical resolution path going forward.

```bash theme={null}
# EVM → Sei (getSeiAddr(address), selector 0x0c3c20ed)
curl -X POST $SEIEVM -H "Content-Type: application/json" -d '{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [{
    "to": "0x0000000000000000000000000000000000001004",
    "data": "0x0c3c20ed000000000000000000000000<evmAddressWithout0x>"
  }, "latest"],
  "id": 1
}'
```

In TypeScript with viem:

```ts theme={null}
import { createPublicClient, http } from 'viem';
import { sei } from 'viem/chains';

const ADDR_PRECOMPILE = '0x0000000000000000000000000000000000001004';
const ADDR_ABI = [
  { name: 'getSeiAddr', type: 'function', stateMutability: 'view',
    inputs: [{ name: 'addr', type: 'address' }],
    outputs: [{ name: 'response', type: 'string' }] },
  { name: 'getEvmAddr', type: 'function', stateMutability: 'view',
    inputs: [{ name: 'addr', type: 'string' }],
    outputs: [{ name: 'response', type: 'address' }] },
] as const;

const client = createPublicClient({ chain: sei, transport: http() });

const seiAddr = await client.readContract({
  address: ADDR_PRECOMPILE, abi: ADDR_ABI, functionName: 'getSeiAddr', args: ['0x…'],
});

const evmAddr = await client.readContract({
  address: ADDR_PRECOMPILE, abi: ADDR_ABI, functionName: 'getEvmAddr', args: ['sei1…'],
});
```

The call reverts when the input address is not yet associated. For the full association lifecycle and how the bidirectional mapping is established, see [Accounts](/learn/accounts).

<Note>In the past, the legacy JSON-RPC helpers `sei_getSeiAddress` and `sei_getEVMAddress` handled address resolution. They are still enabled by default on nodes today. However, they belong to the deprecated `sei_*` namespace and may be removed in a future release. New integrations should call the precompile.</Note>

### Cross-VM transaction lookup

`sei_getCosmosTx` resolves the underlying Cosmos transaction hash for a given EVM transaction. It returns the hash as uppercase hexadecimal without a `0x` prefix. The method does not have a precompile equivalent yet. It is enabled by default on Sei nodes.

<Accordion title="View cross-VM lookup endpoints">
  #### sei\_getCosmosTx

  Returns the wrapping Cosmos transaction hash for a given EVM transaction hash.

  * **Parameters**:

  | Type | Description |
  | :- | :- |
  | `DATA, 32 bytes` | The `0x`-prefixed EVM transaction hash. |

  * **Result**:

  | Type | Description |
  | :- | :- |
  | `string` | The Cosmos transaction hash as uppercase hexadecimal without a `0x` prefix. |

  **Example request**

  ```json theme={null}
  {
    "jsonrpc": "2.0",
    "method": "sei_getCosmosTx",
    "params": ["0x828c91592453fe7c5bf743204495a35bf02b67b579b8f59ee7eea8af031d7c14"],
    "id": 1
  }
  ```
</Accordion>

### Legacy deprecation error

If a client calls a remaining `sei_*` method that is not listed in `enabled_legacy_sei_apis`, the node returns:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "sei_getTransactionReceipt is not enabled on this node. The sei_* JSON-RPC surface is deprecated, scheduled for removal, and should not be used for new integrations - prefer standard eth_* (and debug_*) methods and official migration guidance. To allow this legacy method, add it to enabled_legacy_sei_apis under [evm] in app.toml.",
    "data": "legacy_sei_deprecated"
  }
}
```

### Deprecation HTTP header

When a call to an allowlisted `sei_*` method succeeds, the response includes an optional HTTP header that signals deprecation:

```
Sei-Legacy-RPC-Deprecation: All sei_* JSON-RPC methods are deprecated and scheduled for removal; migrate to eth_* and supported APIs.
```

Clients can use this header to detect legacy API use and plan their migration.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.