opBNB RPC: A Developer's Guide (Chain ID 204)

By John Sullivan · September 29, 2026 · 5 min read · #opbnb #opbnb rpc #layer 2 #op stack #developer guide

opBNB is BNB Chain's layer 2. It runs the OP Stack, the same software as Optimism and Base, with one structural difference: its layer 1 is BNB Smart Chain, not Ethereum. That one change explains most of what you will see over RPC. Blocks arrive every 250 milliseconds, finalized trails the head by well under a minute, and the L1 data fee is paid to BSC.

We measured it through our endpoint on 2026-09-29, and found one trap on the way that is worth the whole post: a public endpoint reporting a finalized block nearly four hours old.

The essentials

opBNB mainnet
Chain ID 204 (0xcc)
Settles to BNB Smart Chain
Gas token BNB
Block time 250 ms (1,000 blocks in 250 s; 79 newHeads in 20 s)
Gas limit 100,000,000 per block
eth_gasPrice 0.001 gwei
safe / finalized about 30 to 50 s behind latest on healthy nodes
eth_getLogs range 50,000 blocks at most (exceed maximum block range: 50000)
Recent state about the last 100 blocks on full nodes
Tracing debug_traceBlockByNumber and eth_getBlockReceipts yes; trace_* no
Node client opBNB's op-geth (Geth/v0.5.9-stable)

It is EVM-equivalent. viem, ethers, Foundry and Hardhat work with the chain ID set to 204, and viem ships an opBNB chain definition.

Four blocks a second

At 250 ms per block, habits from Ethereum stop scaling:

  • Polling latest every block is 345,600 calls a day. Subscribe to newHeads or, better, to the logs you actually need. The eth_subscribe logs guide shows the pattern.
  • Block counts are not time. "Wait 12 confirmations" is 3 seconds. Use block tags or timestamps.
  • The 50,000-block eth_getLogs cap is about 3.5 hours. A one-day backfill is seven requests; a month is about 210. The error message states the limit, so a client can read it and adapt; eth_getLogs range caps covers chunking.

Finality, and the stale-head trap

Because BSC finalizes its own blocks within seconds, opBNB's finalized head moves quickly. On the official BNB Chain endpoint, dRPC and NodeReal, finalized trailed the newest block by 27 to 51 seconds across repeated checks.

One widely used public endpoint told a different story. On about half of our requests it returned a finalized block 13,631 seconds, about 3.8 hours, old, and a fresh one on the rest: a load-balanced pool with some backends stuck. Its WebSocket did the same, at 15,107 seconds. That endpoint was the primary opBNB upstream behind our own service, so we moved opBNB to the official endpoint and dRPC that morning; our endpoint now returns finalized 32 to 38 seconds behind on every request.

The lesson is general. A node that serves a stale finalized doesn't error. A deposit flow that waits for finalized just waits, for hours, and a load-balanced endpoint can even make finalized appear to jump backwards between two calls. Check the tag's timestamp, not just its number:

import { createPublicClient, http } from "viem";
import { opBNB } from "viem/chains";

const client = createPublicClient({
  chain: opBNB,
  transport: http("https://rpc.swiftnodes.io/rpc/opbnb?key=YOUR_API_KEY"),
});

const [latest, finalized] = await Promise.all([
  client.getBlock({ blockTag: "latest" }),
  client.getBlock({ blockTag: "finalized" }),
]);
const lagSeconds = Number(latest.timestamp - finalized.timestamp);
if (lagSeconds > 300) {
  // opBNB normally finalizes in under a minute: this node's view of BSC is stuck
  throw new Error(`finalized head is ${lagSeconds}s behind`);
}

The same idea for the head itself is in is your RPC node synced?.

Fees: the L1 part matters here

opBNB receipts carry the OP Stack L1 fee fields (l1Fee, l1GasPrice, l1GasUsed, l1BlobBaseFee and the scalars), and on opBNB they are not negligible. Across 12 recent user transactions:

Total
L2 execution fee (gasUsed × effectiveGasPrice) 289,556,149,631 wei
L1 data fee (l1Fee) 171,390,813,185 wei
L1 share of the total 37%

That is the opposite of Katana, where the L1 part was 0.2%. Both are tiny in absolute terms: the sample averaged about 0.00000004 BNB per transaction, a small fraction of a cent. But if you estimate cost as gasUsed × gasPrice alone, you will be about a third low. Use the receipt's l1Fee, or ask the GasPriceOracle predeploy at 0x420000000000000000000000000000000000000F with getL1Fee(bytes) before sending; for 100 bytes of calldata it returned 8,840,000,065 wei.

State and tracing

Full opBNB nodes keep very little history. Through our endpoint, eth_getBalance worked up to about 90 blocks back and failed with missing trie node beyond roughly 127 blocks: about 30 seconds of state. The official endpoint and dRPC also refused a state query 100,000 blocks back. If you need balances or contract state at older blocks, you need an archive node; plan for that before you build a backfill around eth_call at historical heights.

For execution detail, debug_traceBlockByNumber with callTracer works and eth_getBlockReceipts returns a block's receipts in one call. The trace_* namespace (trace_block, trace_filter) is not available, so tools built on trace_filter need to switch to debug_* tracing.

If you're coming from BSC or Optimism

  • From BSC: same token for gas (BNB) and much of the same ecosystem, but a separate chain with its own chain ID, 250 ms blocks instead of BSC's, and OP Stack L1 fees on top of execution. The BNB Smart Chain RPC guide covers the L1 side.
  • From Optimism or Base: the same predeploys at 0x4200…, the same deposit transactions (type 0x7e) at the start of each block, and the same safe/finalized semantics, but finality measured in seconds rather than the minutes an Ethereum-settled rollup takes. The sequencer's role is the same as described in what is a sequencer.

The short version

  • Chain ID 204, BNB for gas, OP Stack settling to BSC.
  • 250 ms blocks: subscribe, don't poll; count time, not blocks.
  • finalized should be under a minute old. If it's hours old, your node's view of BSC is stuck: check timestamps.
  • The L1 data fee was 37% of the total in our sample; include l1Fee in cost estimates.
  • eth_getLogs caps at 50,000 blocks, full nodes keep about 100 blocks of state, and debug_* works while trace_* doesn't.

opBNB HTTP and WebSocket endpoints are on our opBNB RPC page, with the live block height. The same key covers 83 chains, and SwiftNodes has a free tier to try it.

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

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 →