0G RPC: A Developer's Guide (Chain ID 16661)

By John Sullivan · October 21, 2026 · 8 min read · #0g #0g rpc #ai blockchain #layer 1 #developer guide

0G is the execution layer of an AI-focused stack: storage for datasets and model artefacts, a data-availability layer, and a compute marketplace. The pitch suggests exotic infrastructure, but the chain itself is ordinary EVM. Solidity contracts, ABI encoding, and viem or ethers code work unchanged.

The differences are in the details. On 0G the base fee is 7 wei but the tip floor is 4 gwei, the default RPC route can land on a pruned node, eth_getLogs is capped by results rather than blocks, and two precompiles have no bytecode at all. Each of those can break code that was written for Ethereum and never tested here.

Everything below was measured on October 21, 2026, through the SwiftNodes endpoint and the chain's public backends.

The endpoint

https://rpc.swiftnodes.io/rpc/0g?key=YOUR_API_KEY
wss://rpc.swiftnodes.io/ws/0g?key=YOUR_API_KEY

The chain slug is 0g, not zerog, and the gas token is 0G with 18 decimals. If your library does not ship a preset, define it with id 16661, native currency 0G and the HTTP URL above.

What we measured

Property Value
Chain ID 16661 (0x4115)
Client reth/v1.8.1 (official), Geth/v1.15.11 (publicnode), Geth/v10.0.0/drpc
First block 2025-08-23 01:19:05 UTC
Average block interval 0.8402 s over 100,000 blocks; 0.8361 s over 300
Transactions per block 0.233 in the sample; 246 of 300 blocks were empty
Block gas limit 36,000,000
Base fee 7 wei in every block sampled
eth_maxPriorityFeePerGas 4 gwei
eth_gasPrice 4.000000007 gwei
Plain 0G transfer 21,000 gas, 0.000084 0G
eth_getLogs cap 20,000 results per query
finalized tag 1 to 28 blocks behind, depending on the backend
Archive official keeps it; publicnode is pruned
0G precompiles 0x…1000 DASigners, 0x…1002 WrappedOGBase

The mix matters: these backends differ on archive depth, log filters and finality tags.

The fee market is a 4 gwei floor

0G's fee market is closer to a fixed fee than an auction. The base fee was 7 wei in every block we sampled. eth_maxPriorityFeePerGas returned 4 gwei, and eth_gasPrice returned 4.000000007 gwei, which is the priority fee plus the base fee.

A type-2 transaction shows the same numbers: maxPriorityFeePerGas 4 gwei, maxFeePerGas 4.000000009 gwei, effectiveGasPrice 4.000000007 gwei. A legacy type-0 transaction paid the same effective price.

So a plain transfer at 21,000 gas costs 0.000084 0G, and the 410,742-gas 0G Storage transaction we sampled cost 0.00164 0G. The base fee can rise with demand, but at current usage it is noise next to the tip.

Do not send a zero tip because the base fee is 7 wei, and do not hardcode 1 gwei from an Ethereum example. Read eth_gasPrice or eth_maxPriorityFeePerGas, then estimate. More on the general pattern in estimating gas with eth_estimateGas.

Fast blocks, thin traffic

0G produces a block every 0.84 seconds, and most of them are empty. In a 300-block sample there were 70 transactions, or 0.23 per block; 246 blocks had none. The blocks used 0.19% of their 36 million gas limit. 64 transactions were legacy type 0 and 6 were type 2, sent by 22 addresses to 20 recipients. 18 different block producers signed the blocks.

The busiest contract was the 0G Storage Mine contract at 0xcd01c5Cd953971CE4C2c9bFb95610236a7F414fe, with 24 of the 70 transactions. The sample transaction 0xb6e902d2… carried 10.8 KB of calldata to that contract, used 410,742 gas and emitted three logs. A prestate trace showed it touching the Storage Flow, Mine and Reward contracts. That is what most 0G activity looks like: storage proofs and mining, not token swaps.

So a one-second polling loop will mostly fetch empty blocks. Use WebSocket newHeads, or batch reads with Multicall3. Do not infer congestion from gasUsed; the chain is fast and mostly idle.

Two precompiles that are not contracts

0G adds two precompiles beyond the Ethereum set:

Address Name What it does
0x0000000000000000000000000000000000001000 DASigners Queries the data-availability signer and quorum state
0x0000000000000000000000000000000000001002 WrappedOGBase Mints and burns the backing for W0G

Both return 0x from eth_getCode. There is no bytecode to inspect, but calls to them work, so the common "zero code means EOA" check gives the wrong answer.

The calls are easy to verify. Calling getWA0GI() on 0x…1002 returns the W0G token address, 0x1Cd0690fF9a693f5EF2dD976660a8dAFc81A109c.

params() on the DASigners precompile returned 30 tokens per vote, 6,400 maximum votes per signer, 10 maximum quorums, 1,800 blocks per epoch (about 25 minutes at 0.84 s blocks) and 3,072 encoded slices per DA blob.

W0G is the ERC-20 form of the native token. At 0x1Cd0690fF9a693f5EF2dD976660a8dAFc81A109c it reports the name Wrapped 0G, the symbol W0G, 18 decimals and a total supply of 33,436,632.685882665. Its native 0G balance equalled that supply exactly at the time of measurement, which is the on-chain backing.

Do not call 0x…1002 directly to wrap or unwrap; the precompile is for the W0G contract. If your app bridges, check which W0G contract the venue expects; the CCIP and older LayerZero deployments are different.

Finality tags depend on the backend

0G uses CometBFT, and the docs describe sub-second finality. The JSON-RPC tags are less consistent. In six samples through the load-balanced route, finalized trailed the head by 1 to 28 blocks, and safe sometimes trailed by more than finalized. The official reth node reported both 6 blocks behind; publicnode reported them at or near the head; dRPC had the widest spread.

That is a backend artifact, not a consensus change. An indexer that waits for finalized may wait 1 block on one request and 28 on the next, and the safe and finalized labels can invert. Pick one: wait a fixed 30 blocks (about 25 seconds), pin a single backend, or treat finalized as a hint rather than a cross-provider guarantee.

For how the tag behaves on other chains, see the finalized block tag across 62 chains and handling chain reorgs in an indexer.

The default route is pruned

0G's public backends do not all keep full history. The official node answered contract code at blocks 1,000,000 and 40,000,000; publicnode returned missing trie node for the same requests.

That is what a load-balanced route looks like without an archive flag: one request succeeds, the next fails. On SwiftNodes, add &archive=1 on a paid plan to restrict routing to archive nodes:

https://rpc.swiftnodes.io/rpc/0g?key=YOUR_API_KEY&archive=1

We verified code at blocks 1,000,000 and 40,000,000 through that route. W0G's native balance at block 40,000,000 was 14,605,412.38 0G; today it is 33.4 million. The free tier does not include archive routing, so a historical read without the flag is not deterministic.

For the general distinction, see full node vs archive node; the archive switch is documented in our API reference.

Logs: 20,000 results, not blocks

The official node caps eth_getLogs by result count. A 10,000-block query returned 4,930 logs. A 50,000-block query failed with:

query exceeds max results 20000, retry with the range 47768080-47814930

The error includes the range the node is willing to serve. Use it. The cap is on results, so a wide range with a narrow address filter can pass while a short range over a busy contract fails.

One public backend also refuses unfiltered queries:

Please specify an address in your request

Always pass an address or a topic filter on 0G. If you need every log in a range, page by blocks and shrink the step when the result cap is hit.

for (let from = start; from <= end; ) {
  const to = from + step - 1n > end ? end : from + step - 1n;
  try {
    await client.getLogs({ address, fromBlock: from, toBlock: to });
    from = to + 1n;
  } catch {
    step /= 2n; // the error names a range; halve until it fits
  }
}

The SwiftNodes free tier adds its own limit: 100 blocks per eth_getLogs request. Paid plans remove that block-span cap and leave the upstream result cap. For a comparison with other chains, see eth_getLogs range caps.

eth_getBlockReceipts and eth_getProof also work; see eth_getProof for the verification pattern.

Tracing and simulation

Method Result on 0G
eth_getBlockReceipts works
eth_getProof works
debug_traceTransaction works with a tracer; {} is rejected
debug_traceCall works with a tracer
debug_traceBlockByNumber works with a tracer
trace_block, trace_transaction not available
txpool_status not reliably available
eth_simulateV1 works
WebSocket newHeads works

The tracer requirement is the one that catches people. A standard geth node defaults to the struct logger when you pass {}. 0G's geth backend rejects an empty tracer object:

Tracer object with 'tracer' param is required for debug_traceTransaction

Pass one explicitly, for example {"tracer":"callTracer"}, as the second parameter. callTracer and prestateTracer both worked. The prestate tracer showed the Flow, Mine and Reward contracts on the storage transaction above.

Debug and trace calls need a paid plan on SwiftNodes. The trace_ namespace is not served by any 0G backend we tested, and txpool_status is missing or returns an empty object.

WebSocket newHeads is the reliable live feed. The socket opened in 18 ms and delivered a header immediately. The free tier serves newHeads only; a logs subscription is refused.

Summary

  • 0G is an EVM L1 with chain ID 16661, 0.84-second blocks, and 0G as an 18-decimal gas token.
  • The base fee is 7 wei, but the tip floor is 4 gwei. A plain transfer costs 0.000084 0G.
  • Most blocks are empty. The busiest contract in our sample was 0G Storage's Mine contract.
  • 0x…1000 and 0x…1002 are live precompiles with no bytecode. W0G lives at 0x1Cd0690fF9a693f5EF2dD976660a8dAFc81A109c.
  • finalized is backend-dependent, the default route is pruned, and eth_getLogs is capped at 20,000 results. Wait a fixed number of blocks, use &archive=1 for history, and filter logs by address.

0G endpoints and method support are on our 0G RPC page, alongside every other chain on the same key. Start free if you want to test the endpoint with your own key; no card is required.

J
John Sullivan
Infrastructure Writer, SwiftNodes

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

  • Etherlink RPC: A Developer's Guide (Chain ID 42793)

    Etherlink is the EVM rollup on Tezos. Measured: sub-second to 1.5 s blocks, a fixed 1 gwei base fee, plain transfers that use 621,000 gas because the data fee is charged as gas, a 500-block eth_getLogs cap, and no safe tag.

  • Bitlayer RPC: A Developer's Guide (Chain ID 200901)

    Bitlayer is an EVM chain that pays gas in BTC. Measured: 3-second blocks from 21 rotating validators, a hard 0.025 gwei minimum tip, a transfer that costs 52.5 satoshis, no safe or finalized tags, and a public RPC that keeps only recent state.

  • Tempo RPC: A Developer's Guide (Chain ID 4217)

    Tempo is a payments chain with no native token: fees are paid in USD stablecoins. Measured: 550 ms blocks, instant finality, an eth_getBalance that returns the same huge number for every address, the 0x76 transaction type, and a 20,000-result eth_getLogs cap.

Try SwiftNodes free — multi-chain RPC across 83 networks, flat-rate pricing, pay by card or crypto, no KYC. Get an API key in 30 seconds →