Etherlink RPC: A Developer's Guide (Chain ID 42793)
Etherlink is an EVM rollup that settles on Tezos. You write Solidity, use viem or ethers, and pay gas in XTZ. The node software is not Geth: it is octez-evm-node, written in OCaml by the Tezos core developers. It answers the usual eth_ methods, but a few answers differ from what Ethereum tooling expects. The biggest difference is gas: a plain value transfer uses about 621,000 gas, not 21,000.
Everything below was measured against the live chain on October 20, 2026. We used the SwiftNodes endpoint, the official public node node.mainnet.etherlink.com, and dRPC.
The endpoint
https://rpc.swiftnodes.io/rpc/etherlink?key=YOUR_API_KEY
wss://rpc.swiftnodes.io/ws/etherlink?key=YOUR_API_KEY
import { createPublicClient, http, defineChain } from "viem";
const etherlink = defineChain({
id: 42793,
name: "Etherlink",
nativeCurrency: { name: "Tez", symbol: "XTZ", decimals: 18 },
rpcUrls: { default: { http: ["https://rpc.swiftnodes.io/rpc/etherlink?key=YOUR_API_KEY"] } },
});
const client = createPublicClient({ chain: etherlink, transport: http() });
viem also ships etherlink in viem/chains, so you can import it and only override the RPC URL. XTZ has 18 decimals on Etherlink, so formatEther gives you XTZ.
What we measured
| Property | Value |
|---|---|
| Chain ID | 42793 (0xa729) |
| Client | octez-evm-node 0.67 |
| Block 1 | May 2, 2024 |
| Average block interval | 1.09 s over 100,000 blocks, 1.52 s over the last 1,000 |
| Transactions per block | 1.7 on average; no empty blocks in 300 |
| Block gas limit | 1,125,899,906,842,624 (2^50) |
| Base fee | 1 gwei in every block sampled |
eth_maxPriorityFeePerGas |
0 |
eth_gasPrice |
1 gwei |
| Plain XTZ transfer | 621,000 gas used, 0.000621 XTZ |
finalized tag |
15 to 28 blocks behind the head |
safe tag |
rejected |
eth_getLogs range |
500 blocks |
| Historical state | full history, back to the first blocks |
The 2^50 gas limit is a placeholder, not a real capacity figure. Etherlink limits throughput in ticks, its own unit of execution work, and not in block gas. Do not size batches from gasLimit.
Block timestamps have one-second resolution. In 300 consecutive blocks, 71 pairs had the same timestamp. If you compute rates from timestamp differences, average over many blocks.
A transfer is not 21,000 gas
This catches the most code. Etherlink charges two fees for every transaction:
- The execution fee pays for running the transaction. It is gas used multiplied by the base fee, and it is burned.
- The inclusion fee pays for writing the transaction to Tezos layer 1. It goes to the sequencer, and it grows with the size of the transaction.
The inclusion fee is collected as extra gas, so it shows up in gasUsed. We asked eth_estimateGas about the same transfer with more and more calldata:
| Transaction | eth_estimateGas |
|---|---|
| Plain transfer, no data | 623,828 |
| Transfer + 64 bytes of data | 882,378 |
| Transfer + 1 KB of data | 4,761,546 |
That is about 4,000 gas for each byte of calldata, on top of the execution cost. Four plain transfers we sampled from the chain each used exactly 621,000 gas.
The rule is simple: call eth_estimateGas for every transaction, and never hardcode 21,000. A transfer capped at gas: 21000 runs out of gas: even eth_estimateGas with that cap answers -32005 The transaction failed: Halt { reason: OutOfGas(...) }. The estimate moved between our runs (624,852 in the morning, 623,828 later) because the inclusion fee follows the cost of data on layer 1. Estimate close to sending, and add a small margin.
const gas = await client.estimateGas({ account, to, value });
const gasLimit = (gas * 110n) / 100n; // 10% margin for inclusion-fee drift
Etherlink refunds unused gas, so a margin costs you nothing. More on the general pattern in estimating gas with eth_estimateGas.
Tips are ignored
The base fee was 1 gwei in all 20 blocks we sampled across the last 100,000. eth_maxPriorityFeePerGas returns 0, and Etherlink's documentation says the chain ignores maxPriorityFeePerGas and deducts only the execution and inclusion fees. A higher tip does not buy faster inclusion. The sequencer orders transactions as they arrive.
The fee can rise when demand for execution is high, so read eth_gasPrice rather than assuming 1 gwei forever. eth_feeHistory works, but it needs blockCount as a hex string:
eth_feeHistory(5, "latest", [25, 75]) -> Json_encoding.Cannot_destruct ... Unexpected number instead of string
eth_feeHistory("0x5", "latest", [25, 75]) -> ok, baseFeePerGas all 0x3b9aca00
viem and ethers already send hex, so this only affects hand-written requests. The gasUsedRatio values are around 0.000000002, because of the 2^50 placeholder limit. Any fee logic that reacts to block fullness sees an empty chain.
finalized works, safe does not
eth_getBlockByNumber("finalized") -> a block 15 to 28 behind the head
eth_getBlockByNumber("safe") -> Json_encoding.Cannot_destruct ... Unexpected string instead of finalized
The error text lists the tags the node accepts: earliest, latest, pending and finalized. Code written for Ethereum that asks for safe gets a JSON decoding error, not a block. If your library defaults to safe, switch it to finalized.
finalized trailed the head by 15 to 28 blocks, 17 to 30 seconds, in our samples. That means the block's contents are final on Tezos layer 1. Withdrawals from Etherlink to Tezos are a different thing. A standard withdrawal waits out the rollup's challenge period, about two weeks. Etherlink is one of the chains in our survey of the finalized block tag across 62 chains.
Logs: 500 blocks at a time
Both public endpoints cap eth_getLogs at exactly 500 blocks. A 500-block range works and a 501-block range fails. The two endpoints fail with different errors:
| Endpoint | Error at 501 blocks |
|---|---|
node.mainnet.etherlink.com |
-32062 Block range is too large |
| dRPC | -32603 Error: Cannot request logs over more than 500 blocks |
Adding an address filter does not lift the cap. A 5,000-block query for one contract fails the same way. If your error handling matches on message text, match both. Better, page at 500 blocks from the start:
const STEP = 500n;
for (let from = start; from <= end; from += STEP) {
const to = from + STEP - 1n > end ? end : from + STEP - 1n;
const logs = await client.getLogs({ address, fromBlock: from, toBlock: to });
// handle logs
}
At about 1.1 seconds per block, 500 blocks is about 9 minutes of chain time, so a day of history is about 160 requests. Unfiltered, the chain emitted about 0.8 logs per block in our sample (414 logs in 500 blocks). See eth_getLogs range caps by provider for how other chains compare.
For live data, WebSocket newHeads works. The official node's WebSocket delivered a header every 0.7 seconds in our test, and the SwiftNodes WebSocket every 1.2 seconds.
Tracing: one endpoint has it, one does not
| Method | Official node | SwiftNodes |
|---|---|---|
eth_getBlockReceipts |
works | works |
eth_feeHistory |
works (hex count) | works (hex count) |
debug_traceTransaction (callTracer) |
refused | works |
debug_traceBlockByNumber |
refused | works |
debug_traceCall |
refused | works |
trace_block, trace_transaction |
refused | not available |
txpool_status |
disabled | disabled |
eth_getProof, eth_createAccessList |
not supported | not supported |
The official node refuses debug_ and trace_ with -32053 API key is not allowed to access method, even though you never sent a key. That message comes from Etherlink's node. It does not mean your SwiftNodes key lacks access. On SwiftNodes, debug_ calls go to an upstream that serves them, so callTracer works on paid plans. trace_ methods are not served by any Etherlink upstream we found.
txpool_status answers Method disabled, reason: restricted by blockchain schema. Etherlink has a central sequencer, so there is no public mempool to inspect.
Historical state is there
The official node keeps full history. We read contract code of Wrapped XTZ (0xc9B5…3EAb) at block 1,000,000, 5,000,000 and 20,000,000, and balances at old heights. Every call worked, and state before the contract existed came back empty, as expected. You do not need archive=1 on Etherlink for historical reads, but it works if your code always sends it. More on why this varies by chain in full node vs archive node.
Activity is concentrated. In 300 blocks, one contract (0x3d54…a3ab) received 384 of 512 transactions. If your app reads a chain-wide average, it mostly measures that contract.
Summary
- EVM rollup on Tezos, chain ID 42793, gas in XTZ with 18 decimals, about one block per second.
- A plain transfer uses about 621,000 gas, because the layer 1 data fee is charged as gas. Always estimate, add a margin, never hardcode 21,000.
- Base fee 1 gwei, tips ignored. A transfer cost 0.000621 XTZ.
finalizedworks and trails by 17 to 30 seconds.safereturns a decoding error.eth_getLogsis capped at 500 blocks on every endpoint, with two different error messages.debug_tracing is refused by the official node and works through SwiftNodes. Notrace_anywhere.
Etherlink endpoints and method support are on our Etherlink RPC page, with 126 other chains on the same key. Start free: the free tier needs no card.
John Sullivan covers RPC infrastructure, node operations, and multi-chain development at SwiftNodes — what it actually takes to keep endpoints fast, fresh, and reliable across EVM and non-EVM networks.
Related posts
- Abstract RPC: A Developer's Guide (Chain ID 2741)
Abstract is a ZK Stack rollup where most transactions come from smart accounts. Measured: 0.58 s blocks, a flat 0.045 gwei gas price, transfers using ~95k gas, a 10,000-log result cap, ~3.8 h to finalized, and full history from block 1.
- MegaETH RPC: A Developer's Guide (Chain ID 4326)
MegaETH runs 1 s EVM blocks over ~10 ms mini-blocks. Measured: a 10-billion gas limit, transfers estimating 63,349 gas, a bogus eth_feeHistory oldestBlock, ~32 min to finalized, and what works over standard RPC.
- Ronin RPC After the Move to Ethereum L2: A Developer's Guide (Chain ID 2020)
Ronin became an OP Stack layer 2 in May 2026. Measured: 2 s blocks, a fixed 20 gwei base fee, a 200-block getLogs cap, ~23 min to finalized, and no pre-migration history.