Differences from Ethereum
A Supra node serves the Ethereum JSON-RPC API at /rpc/v1/eth, with Ethereum’s transaction
envelopes, address format and log format; on Devnet that is
https://rpc-devnet.supra.com/rpc/v1/eth. Compilers, ABIs and signing libraries carry over
unchanged, and so does a contract unless it reads one of the
block values or system contracts that differ. This page states
what changes for existing contracts and tooling.
The node describes every method, its parameters and its errors on its /docs page, generated from
the version it runs; Devnet’s is
https://rpc-devnet.supra.com/docs. Per-method parameter
rules, debug_traceCall’s options, and each method’s answer for a pruned height or a height above
the tip are stated there. Gas, fees, transaction types and the EVM
version are in Gas and Fees.
Block values and system contracts
| Opcode | Solidity | On SupraEVM | On Ethereum |
|---|---|---|---|
COINBASE | block.coinbase | the zero address; no fee is paid to it (Where the fee goes) | the block’s fee recipient |
PREVRANDAO (DIFFICULTY) | block.prevrandao, block.difficulty | 0; for randomness, use the randomness precompile | the beacon chain’s RANDAO value |
GASLIMIT | block.gaslimit | the epoch’s block gas budget plus its per-transaction gas cap, in a block and under eth_call, eth_estimateGas and debug_traceCall; the block header’s gasLimit adds the gas the block’s system pseudo-transactions used (GASLIMIT) | the block header’s gasLimit |
TIMESTAMP | block.timestamp | seconds, truncated from the block’s microsecond timestamp (Block Timestamp) | seconds |
BLOCKHASH | blockhash(n) | the hash eth_getBlockByNumber returns for block n, for the 256 blocks before the current one | the same |
BLOBHASH | blobhash(i) | 0 | the versioned hash of the transaction’s ith blob |
BLOBBASEFEE | block.blobbasefee | 1 | the block’s blob base fee |
GASLIMIT
GASLIMIT (block.gaslimit) returns the block gas limit of the epoch the block belongs to: the
epoch’s block gas budget plus its per-transaction gas
cap. It returns that value to every transaction a block executes, submitted and system alike, and
to eth_call, eth_estimateGas and debug_traceCall simulated in that block, whatever gas limit
the request is simulated with.
A block header’s gasLimit is that value plus the gas the block’s block-metadata transaction,
automated transactions and automation records used, which is known only once the block has
executed. The two differ by that gas.
Blob transactions (type 3) are refused at submission; the transaction types accepted are in Gas and Fees.
Ethereum’s system contracts are not deployed. There is no code at the EIP-2935 block-hash history
contract (0x0000F90827F1C53a10cb7A02335B175320002935), the EIP-4788 beacon-root contract
(0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02), the EIP-7002 and EIP-7251 request contracts
(0x00000961Ef480Eb55e80D19ad83579A64c007002, 0x0000BBdDc7CE488642fb579F8B00f3a590007251), or the
deposit contract (0x00000000219ab540356cBB839Cbe05303d7705Fa). A block hash older than 256 blocks
cannot be read on chain. The contracts that are deployed at fixed addresses are listed in
Predeployed Contracts.
A block’s hash is the hash the consensus layer certified, not keccak256 of the RLP-encoded header,
and the header’s stateRoot, transactionsRoot, receiptsRoot and sha3Uncles are zero. A client
cannot recompute a block hash from its header or verify a Merkle proof against a header root, and
eth_getProof is not served.
The node keeps current state only
The node holds the state at the chain’s head and no earlier state. A balance, code, a storage slot or a call simulated as of a past height is not available from any method, so code that depends on one has to be changed rather than pointed at another endpoint. Blocks, transactions, receipts and logs are served for every height the node retains.
The wallet-integration endpoint
/rpc/v1/eth/wallet_integration serves the methods /rpc/v1/eth serves except debug_traceCall,
which it answers with -32601. For eth_call, eth_estimateGas, eth_getBalance, eth_getCode,
eth_getStorageAt and eth_getTransactionCount it accepts any block parameter, for wallet software
that sends one /rpc/v1/eth refuses. The parameter is accepted, not honoured: the answer describes
the head whatever height was named, with one exception. eth_estimateGas given a height or
earliest runs in that block’s environment — its number, timestamp, base fee and randomness seed,
and its epoch’s EVM version and per-transaction gas cap — against the latest state, because EVM
state is kept for the latest block only. Given a block hash, it is answered for the head.
A 200 from this endpoint carries the height it was answered from in the x-supra-block-height
response header, as a decimal string; for a batch it is a lower bound on the height each method
saw. The header is omitted when the node has no executed block, and /rpc/v1/eth does not send it.
Block tags and finality
Every tag but earliest resolves to the newest executed block. earliest resolves to the oldest
block the node still retains, which is genesis only on a node that has not pruned.
The methods that name a block to read (eth_getBlockByNumber,
eth_getBlockTransactionCountByNumber, eth_getTransactionByBlockNumberAndIndex, eth_getLogs,
eth_feeHistory) accept every tag and a height. An eth_getLogs range whose fromBlock is above
the head, or above toBlock, is answered with an empty list rather than an error. For the methods that read or simulate against
state, a block parameter naming exactly the state the node would return is accepted; one naming a
different state is refused with -39001 (“Unknown block”). safe and finalized resolve to the
head, so their answer is byte-identical to the latest answer, while a height and earliest name a
state this node does not keep. pending is answered from committed state; eth_getTransactionCount
adds the sender’s accepted-but-unexecuted transactions to it, and eth_getBalance, eth_getCode
and eth_getStorageAt refuse it.
safe and finalized resolve to the newest executed block because that block is already final: a
block is executed only after consensus has committed it. A client whose confirmation rule reads
finalized is given the same block, with the same guarantee, as one reading latest.
A height below the node’s retention floor is answered with -32002 and the floor in
data.oldestBlock. Devnet’s retention window is in
Devnet.
Following logs
The filter API is not served. Poll eth_getLogs over a height range, advancing fromBlock with
eth_blockNumber, or subscribe with eth_subscribe ["logs", <filter>] over
WebSocket. A library helper that watches events through eth_newFilter
has to be configured for one of these instead.
Methods not served
A method the node does not serve is answered with -32601 and geth’s wording,
the method <name> does not exist/is not available. The six filter methods also carry the supported
alternative in data.alternative; no other unsupported method carries data:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32601,
"message": "the method eth_newFilter does not exist/is not available",
"data": {
"alternative": "Poll eth_getLogs over a height range, advancing fromBlock with eth_blockNumber, or subscribe with eth_subscribe [\"logs\", filter] on the WebSocket endpoint."
}
}
}| Not served | Use instead |
|---|---|
debug_traceTransaction, trace_* | The receipt, which states why a transaction failed, and its logs. No method reports an executed transaction’s internal calls; debug_traceCall runs against the head, not the past block. |
txpool_*, eth_subscribe ["newPendingTransactions"] | Nothing enumerates the pending pool. eth_getTransactionByHash answers for an accepted, unexecuted transaction with blockNumber null; supra_executedTransactions streams transactions once executed. |
The six filter methods (eth_newFilter, eth_newBlockFilter, eth_newPendingTransactionFilter, eth_getFilterChanges, eth_getFilterLogs, eth_uninstallFilter) | Following logs, and newHeads for new blocks. |
eth_subscribe ["newPendingTransactions"] is answered with -32602 and
Unsupported subscription type.
Methods that need state proofs, an unlocked account or a multi-block simulation are not served
either, among them eth_getProof, eth_createAccessList, eth_simulateV1, eth_accounts,
eth_sign, eth_signTransaction, eth_sendTransaction, eth_coinbase, eth_mining,
eth_blobBaseFee, the eth_getUncle* methods, net_listening, net_peerCount and web3_sha3.
Sign transactions in the client and submit them with eth_sendRawTransaction.
eth_call and eth_estimateGas refuse state and block overrides (their third and fourth
parameters) with -32602, unless the override is null or {}.
eth_syncing, web3_clientVersion, and the block transaction-count and by-index methods are
served. net_version returns the chain ID as a decimal string.
debug_traceCall implements callTracer and prestateTracer, and is served on /rpc/v1/eth and the WebSocket
endpoint. Its options and bounds are on the /docs page.
Transaction and log indices
transactionIndex is a transaction’s position among the block’s EVM transactions, 0..n in
execution order, as listed by eth_getBlockByNumber, eth_getBlockByHash and
eth_getBlockReceipts. logIndex is block-wide over the block’s EVM logs only.
A Supra block also carries Move transactions. The REST endpoints
GET /rpc/v4/block/height/{height}?with_finalized_transactions=true and
GET /rpc/v4/block/{block_hash}/transactions list every transaction of the block across both
virtual machines, so an EVM transaction’s position there is not its transactionIndex. The
transaction hash is the join key between the two.
System pseudo-transactions
Four kinds of transaction that no user signed appear in blocks, receipts and logs, and in the
supra_executedTransactions and logs subscriptions:
- Block-metadata: the first transaction of every block, one per block.
- Settlement credits: a cross-VM crossing into SupraEVM, directly after block-metadata.
- Automated transactions: the execution of a due automation task.
- Automation records: the automation registry’s per-cycle bookkeeping, and the removal of faulty tasks and of tasks a change of the EVM gas config no longer admits.
Each uses the EIP-1559 (type 0x2) envelope with v, r and s all 0, and a real from:
the automation task’s sender for an automated transaction, the node’s system-account address for
the other three. Block-metadata and automation records carry the to and input executed; a
settlement credit’s to is the recipient and its input is empty. Each carries a top-level
supraTxKind field, "blockMetadata", "settlement", "automated" or "automationRecord",
absent on user transactions. A block’s gasUsed includes them, and its gasLimit includes the gas
its block-metadata, automated transactions and automation records used; see
The block gas budget. GASLIMIT does not include that
gas; see GASLIMIT.
A settlement credit’s receipt describes its EVM leg only, and carries one log naming the crossing’s settlement id (the credit log); the rest of the crossing is traced as in Tracing Cross-VM Transfers.
Why a transaction failed
The receipt of a transaction whose status is 0x0, from eth_getTransactionReceipt or
eth_getBlockReceipts, carries fields beside the standard ones:
error:execution revertedfor a revert, the reason for a halt (out of gas,invalid opcode, …), or the rejection message, which begins with geth’s string where geth reports the same rejection.revertReason: for a revert, the decodedError(string),Panic(uint256)or UTF-8 reason. Absent when none decodes or it is empty.output: for a revert, the raw returndata as hex, from which a custom error is decoded.outputTruncated,revertReasonTruncated:truewhen the field holds the first 4096 bytes of a longer value.
A successful receipt carries none of them. Replaying a mined transaction with eth_call at its
block does not work here, since eth_call answers from the head.
WebSocket subscriptions
The WebSocket endpoint is at /rpc/v1/eth, reached with a GET upgrade, text frames only; on
Devnet it is wss://rpc-devnet.supra.com/rpc/v1/eth. It serves every method the HTTP endpoint
serves, and its answers carry no HTTP status.
eth_subscribe ["newHeads"]: the EVM block header of each executed block.eth_subscribe ["logs", <filter>]: logs matching anaddressandtopicsfilter; all logs if it is omitted.eth_subscribe ["supra_executedTransactions", {"hashesOnly": <bool>}]: each executed block’s EVM transactions in block order, pseudo-transactions included. The default,false, delivers{"transaction": {…}, "tx_output_info": {…}}.eth_unsubscribe ["<subscription-id>"]: answerstrueorfalse.
A subscription id is a UUID string, not a hex quantity. eth_subscribe ["syncing"] is not
supported.
Notifications are eth_subscription messages whose params hold subscription and result.
Connection and subscription caps are in
Devnet.
Error codes
| Code | Meaning | Raised for |
|---|---|---|
3 | Execution reverted | A reverting eth_call or eth_estimateGas; data holds the returndata. |
-32601 | Method not found | A method not served; debug_traceCall on the wallet-integration endpoint. |
-32602 | Invalid parameters | A malformed or refused parameter; newPendingTransactions. |
-32002 | Resource unavailable | A height below the retention floor, with data.oldestBlock; a node still starting, without data. |
-32005 | Limit exceeded | An eth_getLogs range or result set, or a debug_traceCall frame count, over the node’s bound. |
-39001 | Unknown block | A height or earliest sent to a method that reads current state; an eth_feeHistory newestBlock above the tip, with data.latestBlock; an eth_getLogs blockHash the node holds no block for. |
-32000 | Server error | A transaction refused at submission, with the reason in the message; an eth_call or eth_estimateGas that halts rather than reverts. |
-32001 | Resource not found | A named resource that does not exist, or a block in an epoch in which SupraEVM was not active. |
-32603 | Internal error | A fault on the node. |
-32700 | Parse error | A request body that is not JSON. |
-32600 | Invalid request | A JSON body that is not a JSON-RPC request. |