guide10 min read

Boba Mainnet RPC for Wallet Builders

Boba Network RPC checks for wallets: chain ID 288 / 0x120, ETH gas near 0.001 gwei, safe and finalized lag, and 7 public endpoints that passed 8 probes.

By RPC Directory•
#Boba#Boba Network#ETH#RPC#Wallet#Chain ID#MetaMask#Rabby#EVM#OP Stack
$boba-mainnet-rpc.md

Boba Network is an Ethereum Layer 2 built on the OP Stack, with ETH as the gas token. Blocks arrive every 2 seconds. The JSON-RPC surface is standard Ethereum, so wallet code written for Ethereum works, but wallet builders still trip on three things: a BOBA token that is not the gas token, a gas price far below Ethereum's, and safe and finalized tags that trail latest by many minutes.

This is not a ranking of providers. Use the Boba Mainnet hub to compare endpoints, then run the checks below on the URL you configure. The Boba Mainnet providers page lists the keyed options side by side.

Chain ID 288 is mainnet, 28882 is Sepolia testnet

  • Boba mainnet: chain ID 288, hex 0x120. eth_chainId returned 0x120 on every passing URL in every round of our probe, and net_version on mainnet.boba.network returned "288". Boba's network page lists the same chain ID.
  • Boba Sepolia testnet: chain ID 28882, per the same docs page, with https://sepolia.boba.network as its RPC and https://testnet.bobascan.com as its explorer.
  • Ethereum mainnet: chain ID 1. ETH on Boba is bridged ETH on a separate chain, so it needs its own network entry.

Wallet-add fields for mainnet, matching Boba's network page:

  • Network name: Boba Network (or Boba Mainnet)
  • Chain ID: 288 (or 0x120 if the form wants hex)
  • Currency symbol: ETH
  • RPC URL: a JSON-RPC HTTPS endpoint you have already probed, such as https://mainnet.boba.network
  • Block explorer: https://bobascan.com

Native gas is ETH with 18 decimals. BOBA is a token on the network, not the gas token, so do not put BOBA in the currency symbol field. Call eth_chainId on the exact RPC URL you will ship and expect 0x120. A gateway that returns 0x70d2 (28882) is Sepolia. A timeout, an HTML page, an API-key error, or a "not configured" body is not Boba mainnet.

Public endpoints that passed 8 of 8 rounds

We probed every Boba mainnet URL on the hub 8 times, about 55 seconds apart, on 2026-10-16 between 02:02 and 02:10 UTC. Each round called eth_chainId, eth_getBalance and eth_blockNumber, with a curl User-Agent on every request. Hosts ran one after another, never in parallel, at no more than 2 requests per second. These seven HTTPS URLs passed all three calls in 8 of 8 rounds, and the block number they returned moved forward in every round:

EndpointTransportNotes
https://mainnet.boba.networkHTTPSThe endpoint in Boba's docs, which describe it as rate-limited and not for production. web3_clientVersion returned Tenderly/1.0
https://boba-ethereum.gateway.tenderly.coHTTPSListed in Boba's docs as a Tenderly public endpoint, IP rate-limited
https://gateway.tenderly.co/public/boba-ethereumHTTPSSecond Tenderly public path from Boba's docs
https://boba-eth.drpc.orgHTTPSAnswered without a key
https://1rpc.io/boba/ethHTTPSAnswered without a key
https://public.1rpc.io/boba/ethHTTPSAnswered without a key
https://288.rpc.thirdweb.comHTTPSAnswered without a key

The hub also lists WebSocket rows. We ran the same three calls over one WSS connection per URL, hosts in sequence at no more than 2 requests per second, 8 rounds about 55 seconds apart, between 02:26 and 02:34 UTC. wss://boba-eth.drpc.org, wss://boba-ethereum.gateway.tenderly.co and wss://gateway.tenderly.co/public/boba-ethereum passed all three calls in 8 of 8 rounds.

Some rows answered with caveats and stay listed:

  • https://lb.routeme.sh/rpc/evm/288 returned 0x120 in 6 of 8 rounds, but every eth_getBalance and eth_blockNumber call returned HTTP 429, JSON-RPC -32029 "public rate limit exceeded". Treat it as low-rate only.
  • The Dwellir rows, https://api-boba-mainnet.n.dwellir.com and its WSS twin, need an API key. Without one the HTTPS URL returned HTTP 403, "API key does not exist", on every call, and the WSS handshake returned 403 in every round. That is a key problem, not a dead host, so they stay listed as a keyed option.

Three rows failed every call in all 8 rounds, and the directory now hides them:

  • https://boba.api.pocket.network returned HTTP 400 with JSON-RPC error -32600, service "boba" is not configured, on every call.
  • wss://boba.api.pocket.network returned HTTP 400 to the WebSocket handshake in every round.
  • https://replica.boba.network closed the TLS connection before any HTTP response on every call, and a public DNS lookup (dns.google) returned NXDOMAIN for the hostname.

A row on a directory page is a starting point, not proof it serves Boba mainnet today.

Fees: about 0.001 gwei, priced in ETH

On mainnet.boba.network at about 02:10 UTC:

  • The latest block's baseFeePerGas was 0xfc (252 wei), and eth_feeHistory over 5 blocks showed the same value in every block.
  • eth_gasPrice returned 0xf433c (1,000,252 wei, about 0.001 gwei).
  • eth_maxPriorityFeePerGas returned 0xf4240 (1,000,000 wei, 0.001 gwei), while the 50th percentile tip in eth_feeHistory was 0 in all 5 blocks.
  • eth_estimateGas for a plain ETH transfer between two ordinary addresses returned 0x5208 (21,000).
  • The block gas limit was 30,000,000, and each of the 5 blocks used under 0.2 percent of it.

At that gas price, the L2 execution part of a plain transfer is 21,000 × 1,000,252 wei, about 0.000000021 ETH. As on other OP Stack chains, the total fee can also include an L1 data fee, so read the full fee your wallet library reports rather than computing it by hand. What that means for a wallet:

  • Do not show "0" for the fee. Rounding to four or six decimals of ETH hides the real number. Show it in gwei or with enough precision.
  • Do not add a fixed Ethereum-sized tip. The node suggested a tip of 0.001 gwei, and a hardcoded 1 or 2 gwei tip would cost about 1,000 times that.
  • Read the price, do not hardcode it. Take the base fee from eth_feeHistory or the latest block rather than a constant.

Finality: safe trails by about 21 minutes, finalized by about 71

During the check, timestamps across the last 10,000 blocks spanned 20,000 seconds, exactly 2 seconds per block. The latest block's timestamp was 5 seconds older than our clock.

At about 02:10 UTC, on mainnet.boba.network:

  • eth_getBlockByNumber("safe") returned a block 643 blocks behind latest, with a timestamp 1,286 seconds (about 21 minutes) older.
  • eth_getBlockByNumber("finalized") returned a block 2,120 blocks behind latest, with a timestamp 4,240 seconds (about 71 minutes) older.

For a wallet:

  • latest is fine for balances on screen.
  • If you wait for safe, expect about 20 minutes, not a few seconds.
  • If you credit deposits only at finalized, tell users the wait is over an hour, and show the pending state in the meantime.

Add Boba to MetaMask or Rabby

These are the values we checked on 2026-10-16, not values copied from a list:

  • eth_chainId returned 0x120 (288) on every passing URL in the table above.
  • Boba's network page lists chain ID 288, https://mainnet.boba.network as the RPC and https://bobascan.com as the explorer.

MetaMask: follow the MetaMask custom RPC guide. Check 'Additional networks' first. To add it by hand, open 'Networks', choose 'Add a custom network', and enter the five fields from the chain ID section with a URL from the passed table. MetaMask does not verify that a custom network is what it claims to be, so the probe is your check.

Rabby: follow the Rabby custom network guide. Check the network list before you add a custom entry. If you add it by hand, enter chain ID 288 and an RPC URL that returned 0x120 in your own probe.

Dapps: for wallet_addEthereumChain, send chainId: "0x120", chainName: "Boba Network", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, rpcUrls with your probed HTTPS endpoint, and blockExplorerUrls: ["https://bobascan.com"]. For wallet_switchEthereumChain, send only { chainId: "0x120" }, and call wallet_addEthereumChain if MetaMask returns error 4902.

Wallet-add gotchas that show up in QA

  1. BOBA as the currency symbol: gas is paid in ETH. BOBA is a token, so show it as a token balance.
  2. ETH symbol on several networks: Ethereum, Boba and Boba Sepolia all show ETH. Show the network name next to the balance.
  3. A fee that rounds to zero: about 0.000000021 ETH of L2 execution fee needs more precision than most balance formatters use.
  4. Waiting on finalized: it trailed latest by about 71 minutes in our check.
  5. Rows that no longer serve Boba: two Pocket rows said the service is not configured or refused the handshake, and another hostname had no public DNS record. Probe the URL you ship.
  6. Shared public URLs under load: Boba's docs say the public RPC is rate-limited and not for production, and that the Tenderly public endpoints are IP rate-limited.

Public vs dedicated for wallet traffic

Public endpoints are fine for:

  • Local development and wallet QA
  • Low-volume eth_chainId and eth_blockNumber probes
  • One-off scripts and docs examples

They are a poor primary path when you:

  • Run production wallet RPC for many users (balance, nonce, fee estimate, send, receipt polls)
  • Need wide eth_getLogs ranges or historical state
  • Depend on WebSocket subscriptions
  • Cannot absorb shared-node rate limits during a token launch or market spike

Probe the candidate URL before you call it ready:

  1. eth_chainId returns 0x120.
  2. The latest block advances when you poll twice 2 seconds apart, and its timestamp is within a few seconds of wall-clock time.
  3. A plain transfer eth_estimateGas returns 0x5208 (21,000).
  4. eth_getBalance on an address you care about returns a value, not a rate-limit or method error.
  5. You know how far safe and finalized trail latest on that URL, and your confirmation logic accounts for it.
  6. A burst of 20 to 50 quick requests does not return HTTP 429 or a JSON-RPC rate-limit error at the volume you expect per client.

For production wallet traffic, compare the rows on the same hub for method coverage, archive access, and quota. The providers page lists the keyed options for Boba mainnet, Dwellir among them.

A cheaper URL that fails the probe above is not a savings. The public vs paid guide covers when a shared endpoint stops being enough, and the pricing calculator estimates monthly cost for a given request mix. Log-heavy indexers should also read the eth_getLogs caps guide, and the dead public endpoints guide explains why listed URLs stop answering.

Practical split for a wallet stack

  • User-facing Boba network row: chain ID 288 / 0x120, ETH symbol with the network name shown, an explorer you opened, an RPC you probed today.
  • Testnet row, if you need it: Boba Sepolia, chain ID 28882, a separate config key, never reused as the mainnet RPC.
  • Fee estimation: EIP-1559 fields from the RPC plus the L1 data fee, no fixed Ethereum-sized tip, shown with enough precision.
  • Confirmations: show latest right away, and if you wait for safe or finalized, say so in the UI.
  • Backend / indexer: a dedicated or keyed endpoint with the eth_getLogs range and archive depth you need. Do not share the browser wallet's public URL.

Ship the hub comparison and the probe first. A network called "Boba" in a dropdown does not replace eth_chainId returning 0x120.