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_chainIdreturned0x120on every passing URL in every round of our probe, andnet_versiononmainnet.boba.networkreturned"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.networkas its RPC andhttps://testnet.bobascan.comas 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(orBoba Mainnet) - Chain ID:
288(or0x120if 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:
| Endpoint | Transport | Notes |
|---|---|---|
https://mainnet.boba.network | HTTPS | The 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.co | HTTPS | Listed in Boba's docs as a Tenderly public endpoint, IP rate-limited |
https://gateway.tenderly.co/public/boba-ethereum | HTTPS | Second Tenderly public path from Boba's docs |
https://boba-eth.drpc.org | HTTPS | Answered without a key |
https://1rpc.io/boba/eth | HTTPS | Answered without a key |
https://public.1rpc.io/boba/eth | HTTPS | Answered without a key |
https://288.rpc.thirdweb.com | HTTPS | Answered 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/288returned0x120in 6 of 8 rounds, but everyeth_getBalanceandeth_blockNumbercall 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.comand 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.networkreturned HTTP 400 with JSON-RPC error-32600,service "boba" is not configured, on every call.wss://boba.api.pocket.networkreturned HTTP 400 to the WebSocket handshake in every round.https://replica.boba.networkclosed 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
baseFeePerGaswas0xfc(252 wei), andeth_feeHistoryover 5 blocks showed the same value in every block. eth_gasPricereturned0xf433c(1,000,252 wei, about 0.001 gwei).eth_maxPriorityFeePerGasreturned0xf4240(1,000,000 wei, 0.001 gwei), while the 50th percentile tip ineth_feeHistorywas 0 in all 5 blocks.eth_estimateGasfor a plain ETH transfer between two ordinary addresses returned0x5208(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_feeHistoryor 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 behindlatest, with a timestamp 1,286 seconds (about 21 minutes) older.eth_getBlockByNumber("finalized")returned a block 2,120 blocks behindlatest, with a timestamp 4,240 seconds (about 71 minutes) older.
For a wallet:
latestis 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_chainIdreturned0x120(288) on every passing URL in the table above.- Boba's network page lists chain ID 288,
https://mainnet.boba.networkas the RPC andhttps://bobascan.comas 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
- BOBA as the currency symbol: gas is paid in ETH. BOBA is a token, so show it as a token balance.
- ETH symbol on several networks: Ethereum, Boba and Boba Sepolia all show ETH. Show the network name next to the balance.
- A fee that rounds to zero: about 0.000000021 ETH of L2 execution fee needs more precision than most balance formatters use.
- Waiting on
finalized: it trailedlatestby about 71 minutes in our check. - 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.
- 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_chainIdandeth_blockNumberprobes - 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_getLogsranges 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:
eth_chainIdreturns0x120.- The latest block advances when you poll twice 2 seconds apart, and its timestamp is within a few seconds of wall-clock time.
- A plain transfer
eth_estimateGasreturns0x5208(21,000). eth_getBalanceon an address you care about returns a value, not a rate-limit or method error.- You know how far
safeandfinalizedtraillateston that URL, and your confirmation logic accounts for it. - 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
latestright away, and if you wait forsafeorfinalized, say so in the UI. - Backend / indexer: a dedicated or keyed endpoint with the
eth_getLogsrange 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.