Unichain is an OP Stack Layer 2 on Ethereum built by Uniswap Labs, with 1-second blocks and Flashblocks preconfirmations. Gas is paid in ETH, so the fee symbol looks familiar, but the chain is not Ethereum mainnet and not Unichain Sepolia. Wallet builders who paste chain ID 1, reuse the Sepolia key, or read nonces from the wrong block tag will ship the wrong network or stuck transactions. Prove chain ID 130 and probe the URL first.
This is not a ranking of providers. Use the Unichain Mainnet hub to compare endpoints and paid rows, then run the checks below on the URL you configure. The Unichain Mainnet providers page lists the keyed options side by side.
Chain ID 130 is not Ethereum and not Unichain Sepolia
- Unichain mainnet: chain ID 130, hex
0x82. This is what wallets,eth_chainId, and EIP-155 signatures use.net_versionreturns130. - Unichain Sepolia testnet: chain ID 1301, hex
0x515, RPChttps://sepolia.unichain.org, explorerhttps://sepolia.uniscan.xyz. - Ethereum mainnet: chain ID 1. A wallet that already has Ethereum added still needs a separate Unichain network entry.
Wallet-add fields for mainnet, matching Unichain's published network information:
- Network name:
Unichain - Chain ID:
130(or0x82if the form wants hex) - Currency symbol:
ETH - RPC URL: a JSON-RPC HTTPS endpoint you have already probed, such as the official
https://mainnet.unichain.org - Block explorer:
https://uniscan.xyz
Native gas is ETH with 18 decimals, the same unit as on Ethereum, and the native balance is read with eth_getBalance. Because the symbol matches Ethereum, the network name is the only thing that tells a user which chain they are on. Show it next to every balance and fee, or users will assume the ETH they see is on L1. Wrapped ETH sits at the standard OP Stack predeploy 0x4200000000000000000000000000000000000006.
Call eth_chainId on the exact RPC URL you will ship. Expect 0x82. A gateway that returns 0x515 is Sepolia. A gateway that returns 0x1 is Ethereum. A timeout, an HTML page, a 404, or a rate-limit body is not Unichain mainnet for that transport. Run the check after any load balancer or fallback so you test the backend production actually hits.
Public endpoints that answered eth_chainId
We probed every public Unichain mainnet URL on the hub and in Unichain's docs 8 times, about 55 seconds apart, on 2026-10-06 between 02:12 and 02:19 UTC. Each round called eth_chainId, eth_getBlockByNumber("latest"), and eth_getBalance on the WETH predeploy. The URLs below passed all three calls in 8 of 8 rounds. Nodeflare passed 8 of 8 in a second run with a curl User-Agent, explained in its row:
| Endpoint | Transport | Notes |
|---|---|---|
https://mainnet.unichain.org | HTTPS | Official, rate limited. Head block was 3 to 4 seconds old, 2 to 3 blocks behind most other URLs |
https://unichain-rpc.publicnode.com / wss://unichain-rpc.publicnode.com | HTTPS, WSS | Head 0 to 1 seconds old |
https://unichain.drpc.org / wss://unichain.drpc.org | HTTPS, WSS | Head 0 to 1 seconds old |
https://130.rpc.thirdweb.com | HTTPS | Head 3 to 4 seconds old, same height as the official RPC in every round |
https://rpc.sentio.xyz/unichain-mainnet / https://unichain-mainnet.rpc.sentio.xyz | HTTPS | Head 0 to 1 seconds old |
https://rpc.swiftnodes.io/rpc/unichain | HTTPS | Head 0 to 1 seconds old |
https://unichain-mainnet.gateway.tatum.io | HTTPS | Head 0 to 1 seconds old |
https://unichain.api.onfinality.io/public | HTTPS | Head 0 to 1 seconds old. Returned HTTP 429 to a short burst of extra calls outside the probe |
https://rpc.nodeflare.app/unichain/public | HTTPS | 8 of 8 with a curl User-Agent (02:53 to 03:00 UTC), head under 1 second old. Returns HTTP 403 to some default User-Agents (Node's built-in fetch, Python urllib, Go net/http) and to requests with none, so set a User-Agent on server-side clients. Browsers, curl, ethers, axios, and python-requests worked |
Five other rows did not pass every round. Four failed all 8 with an HTTP 404 or a reset connection, also with a curl User-Agent, and the directory now hides them. lb.routeme.sh/rpc/evm/130 passed 3 of 8 rounds and returned a public rate-limit error on the rest, so it stays listed with that caveat. A row on a directory page is a starting point, not proof it serves Unichain mainnet today.
Unichain's docs state that https://mainnet.unichain.org and https://sepolia.unichain.org are rate limited and not intended for production. Treat the table as a probe list for development and QA, not as a production recommendation.
Flashblocks and the pending tag
Unichain produces a block every second. During the test, 100 consecutive blocks spanned exactly 100 seconds. Flashblocks add partial block updates about every 200 ms. Unichain's docs say apps read them with the pending tag on standard methods such as eth_getBlockByNumber, eth_getBalance, eth_call, and eth_getTransactionCount, and that the public RPC URLs are Flashblocks-aware.
The pending tag is where the endpoints disagreed most. In 10 samples per URL, 3 seconds apart, at 02:19 UTC:
mainnet.unichain.org:pendingreturned a block 3 to 5 ahead ofeth_blockNumberin 3 samples. In the other 7 it returned a block between 12,503 and 1,063,220 blocks old, roughly 3.5 hours to 12 days.130.rpc.thirdweb.com:pendingreturned an old block in 10 of 10 samples.unichain-rpc.publicnode.com:pendingwas 0 or 1 block ahead in 10 of 10 samples.
The same split showed up in nonces. For a busy sender address, eth_getTransactionCount(address, "pending") came back between about 88,000 and 7.4 million below the latest nonce in 8 of 12 reads on the official RPC and 12 of 12 on thirdweb. PublicNode never returned a pending nonce below latest.
For a wallet this matters more than head freshness. A nonce read from a stale pending block produces "nonce too low" errors, or a send queue that replays old nonces. Probe pending on your URL before relying on it. If results jump, read nonces from latest, track your own in-flight count, and use pending only where the endpoint has proved it serves Flashblocks state.
Fees on an OP Stack chain with 1-second blocks
During the test, eth_gasPrice returned 1,500,000 wei (0.0015 gwei), the base fee was 500,000 wei, and eth_maxPriorityFeePerGas returned 1,000,000 wei. eth_estimateGas for a plain ETH transfer returned 0x5208 (21,000) on both the official RPC and PublicNode.
Like other OP Stack chains, Unichain charges an L1 data fee on top of gasUsed * gasPrice. It does not consume gas limit and is deducted from the sender's balance. The GasPriceOracle predeploy at 0x420000000000000000000000000000000000000F returned an upper bound of 1,527,843,746 wei for a 110-byte transaction, about 5% of the 31,500,000,000 wei execution fee for a transfer at that gas price.
What that means for a wallet:
- "Send max" needs the L1 fee. Subtract the execution fee and the
getL1FeeorgetL1FeeUpperBoundresult, or leave a small buffer, so the transaction does not fail on the last few wei. - Do not cap fees with Ethereum L1 defaults. A gas price of a few thousandths of a gwei is normal here. An L1-style minimum priority fee overpays by orders of magnitude.
- Fee data moves fast. With 1-second blocks, refresh fee estimates per send, not once per session.
OP Stack quirks that matter for wallets
- Three block tags, three heights. In a single read across eight URLs at 02:19 UTC,
safetrailedlatestby 166 to 178 blocks (about 3 minutes) andfinalizedby 1,356 to 1,368 blocks (about 23 minutes). One earlier read from the official RPC putsafe558 blocks back, so tag heights also vary by backend. Show alatestreceipt as included, and reserve "final" for UI that needs L1-backed finality. - Canonical withdrawals are a multi-step L1 flow. Unichain is a Stage 1 rollup with permissionless fault proofs. Withdrawals through the standard bridge need a prove step, a challenge window, and a finalize transaction on Ethereum. Third-party bridges listed in Unichain's docs, such as Across and Relay, have their own timing.
- Address aliasing on L1 to L2 messages. For deposits and other L1-initiated transactions,
msg.senderon L2 is the aliased L1 address, as on upstream OP Stack. This matters to contract wallets and allowlists, not to ordinary EOAs. - Standard JSON-RPC otherwise. Unichain documents the usual Ethereum methods, including
eth_feeHistory,eth_getBlockReceipts, andeth_getProof. The official RPC returned HTTP 403 toweb3_clientVersion, so do not use that call as a health check.
MetaMask, Rabby, and Rainbow
All three accept Unichain as an EVM network with the fields above. What to expect:
- MetaMask: the add-network form takes the five fields directly. When a dapp calls
wallet_switchEthereumChainfor a chain MetaMask does not know, it returns error4902. Handle that by callingwallet_addEthereumChain. - Rabby: check whether Unichain already appears in Rabby's network list before adding a custom entry, so you do not end up with two Unichain rows pointing at different RPCs.
- Rainbow: accepts the same EIP-3085 add request from a dapp. If your dapp connects wallets with RainbowKit or wagmi, define Unichain with the fields above and confirm the explorer URL is
uniscan.xyz.
For wallet_addEthereumChain, send a full EIP-3085 payload: chainId: "0x82", chainName: "Unichain", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, rpcUrls with your probed HTTPS endpoint, and blockExplorerUrls: ["https://uniscan.xyz"]. For wallet_switchEthereumChain, send only { chainId: "0x82" }. Prefer one primary RPC in the wallet payload and keep failover in your own client.
A browser wallet computes its own fees and nonces from the RPC in its network entry. If that entry points at a URL with a stale pending tag, the wallet inherits the problem. That is one more reason to probe the URL you put in the add-network payload.
Wallet-add gotchas that show up in QA
- Chain ID 1 in the Unichain row: the network name says Unichain but signatures target Ethereum.
- Sepolia mix-up:
1301/0x515pasted into a mainnet config, or a Sepolia RPC behind a mainnet label. - ETH balances without a network label: users read the balance as L1 ETH.
- Nonce from a stale pending tag: "nonce too low" on send, or a queue that never clears.
- Fee shown from estimateGas only: understates the total by the L1 data fee.
- One shared "unichain" RPC key for mainnet and testnet: separate config keys so a fallback cannot silently swap networks.
Public vs dedicated for wallet traffic
Public endpoints are fine for:
- Local development and wallet QA
- Low-volume
eth_chainId/eth_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 predictable latency and a support channel when the gateway rate limits you
- Depend on Flashblocks
pendingstate, historical state, wideeth_getLogs, or sustained WebSocket traffic - Cannot absorb shared-node brownouts during a launch, airdrop, or market spike
Probe the candidate URL before you call it ready:
eth_chainIdreturns0x82.- The latest block advances when you poll twice a few seconds apart, and its timestamp is within a few seconds of wall-clock time.
eth_getBlockByNumber("pending")stays within a few blocks ofeth_blockNumberacross ten polls, if you use Flashblocks.eth_getTransactionCountwithpendingis never belowlatestfor an address you control.- 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.
- If you need push updates, a WebSocket
eth_subscribethat survives a disconnect.
Public rows on the hub are shared and rate-limited. Use them for the probe. For production wallet traffic, compare the paid rows on the same hub for method coverage, Flashblocks support, archive access, and quota. At the time of writing those are Alchemy, Chainstack, DRPC, Infura, and Dwellir. Dwellir's row is a keyed Unichain mainnet endpoint over HTTPS and WSS, billed as one response credit per call on every method. It is not the only option.
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 Unichain network row: chain ID 130 /
0x82, ETH symbol with the network name shown, Uniscan, RPC you probed today. - Unichain Sepolia row: chain ID 1301 /
0x515, separate config key, never reused as the mainnet RPC. - Nonce and Flashblocks reads:
pendingonly on an endpoint that passed the pending checks above, withlatestplus a local in-flight counter as the fallback. - Fee estimation: execution fee plus the
GasPriceOracleL1 fee, refreshed per send. - Backend / indexer: dedicated or paid endpoint with explicit method and archive needs. Do not share the browser wallet's public URL.
Ship the hub comparison and the probe first. A network called "Unichain" in a dropdown does not replace eth_chainId returning 0x82.