Sonic is an EVM Layer 1 with the native S token for fees, staking, and governance. Docs describe about 400,000 TPS and sub-second finality, with no rollbacks or reorganizations. Gas is paid in S, not ETH and not FTM. Wallet builders who paste Fantom Opera chain ID 250, reuse an Opera RPC, or show S balances without the network name will ship the wrong chain or confuse users who still hold FTM.
This is not a ranking of providers. Use the Sonic Mainnet hub to compare endpoints and paid rows, then run the checks below on the URL you configure. The Sonic Mainnet providers page lists the keyed options side by side.
Chain ID 146 is not Fantom Opera and not Ethereum
- Sonic mainnet: chain ID 146, hex
0x92. This is what wallets,eth_chainId, and EIP-155 signatures use.eth_getRuleson the official RPC returnsNetworkID146. - Fantom Opera (legacy): chain ID 250, hex
0xfa. Sonic Labs documents Sonic as a migration from the Fantom chain and FTM token. Opera continues to run, but development focus moved to Sonic after the 18 December 2024 launch. FTM holders upgrade to S through the published upgrade flow. - Ethereum mainnet: chain ID 1. A wallet that already has Ethereum or Opera added still needs a separate Sonic network entry.
Wallet-add fields for mainnet, matching Sonic's published network information:
- Network name:
Sonic - Chain ID:
146(or0x92if the form wants hex) - Currency symbol:
S - RPC URL: a JSON-RPC HTTPS endpoint you have already probed, such as the official
https://rpc.soniclabs.com - Block explorer:
https://sonicscan.org
Native gas is S with 18 decimals. The symbol is unique, so the main mix-up is Opera vs Sonic, not L1 ETH vs L2 ETH. Show the network name next to every balance and fee. Call eth_chainId on the exact RPC URL you will ship. Expect 0x92. A gateway that returns 0xfa is Opera. A gateway that returns 0x1 is Ethereum. A timeout, an HTML page, a keyed-only error, or a rate-limit body is not Sonic mainnet for that transport.
Public endpoints that answered eth_chainId
We probed every public Sonic mainnet URL on the hub 8 times, about 55 seconds apart, on 2026-10-07 between 02:11 and 02:19 UTC. Each round called eth_chainId, eth_getBlockByNumber("latest"), and eth_getBalance on the zero address, with a curl User-Agent on every request. The URLs below passed all three calls in 8 of 8 rounds (OnFinality noted separately):
| Endpoint | Transport | Notes |
|---|---|---|
https://rpc.soniclabs.com | HTTPS | Official. Head was 12 to 19 seconds old during the test, 4 to 26 blocks behind the freshest public URL |
https://sonic.drpc.org / wss://sonic.drpc.org | HTTPS, WSS | Head 12 to 15 seconds old |
https://sonic-rpc.publicnode.com / wss://sonic-rpc.publicnode.com | HTTPS, WSS | Head 9 to 15 seconds old |
https://rpc.sentio.xyz/sonic-mainnet / https://sonic-mainnet.rpc.sentio.xyz | HTTPS | Head 7 to 11 seconds old |
https://rpc.swiftnodes.io/rpc/sonic | HTTPS | Head 5 to 10 seconds old |
https://sonic-json-rpc.stakely.io | HTTPS | Head 5 to 13 seconds old |
https://sonic-mainnet.gateway.tatum.io | HTTPS | Head 4 to 7 seconds old |
https://sonic.api.pocket.network | HTTPS | Head 2 to 4 seconds old, freshest in every round |
https://rpc.nodeflare.app/sonic/public | HTTPS | 8 of 8 with a curl User-Agent, head 8 to 11 seconds 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, node-fetch, requests, and httpx worked |
https://sonic.api.onfinality.io/public passed 6 of 8 rounds. Two rounds returned HTTP 504 from the gateway. It stays listed with that caveat.
Four other rows failed all 8 rounds with a curl User-Agent, and the directory now hides them: Ankr's public Sonic URL requires an API key, lb.routeme.sh/rpc/evm/146 returned a public rate-limit error on every try, sonic.therpc.io never answered, and wss://sonic.callstaticrpc.com failed the TLS handshake. A row on a directory page is a starting point, not proof it serves Sonic mainnet today.
Fees on Sonic: 50 gwei MinBaseFee, use the ~55 gwei RPC suggestion
Sonic uses an EIP-1559-style base fee plus priority fee. Unlike Ethereum, Sonic docs state the base fee is not burned. 90% of fees go to the FeeM treasury for app developers and 10% to validators.
During the test on the official RPC:
eth_gasPricereturned0xcce416600(55 gwei). Sonic docs say this is the 50 gwei minimum base fee plus a 10% buffer.eth_feeHistorybase fees were0xcce416600across the sampled window, with priority rewards of 1 wei.eth_maxPriorityFeePerGasreturned0x1(1 wei). Sonic docs say that is the normal minimum tip when the network is not congested.eth_estimateGasfor a plain S transfer returned0x5244(21,060).
What that means for a wallet:
- Do not apply Ethereum L1 tip defaults. A priority fee of 1 wei is expected here. An L1-style 1 gwei tip overpays by orders of magnitude when the mempool is quiet.
- Do not cap fees at the raw 50 gwei MinBaseFee. Sonic's transaction pool needs more than a 5% buffer above the base fee. Use
eth_gasPriceoreth_feeHistory(both return about 55 gwei, a 10% buffer) or add at least 6 to 10% yourself. SettingmaxFeePerGasto exactly 50 gwei plus a 1 wei tip is rejected as underpriced. - Add a buffer on complex estimates. Sonic docs warn that
eth_estimateGascan under-estimate state-dependent calls and suggest a 20 to 30% gas-limit buffer. Unused gas is refunded. - No L1 data fee. Sonic is an L1, so total fee is
gasUsed * effectiveGasPrice. "Send max" does not need an OP Stack L1 fee subtraction.
Finality and block timing that matter for wallets
Across 20 consecutive blocks on PublicNode during the test, timestamps spanned 16 seconds (about 0.84 seconds per block). In the same read, latest, safe, and finalized all returned the same block height. That matches Sonic's claim of sub-second finality with no reorg risk: a latest receipt is already final for practical wallet UI.
Sonic Gateway bridges assets between Ethereum and Sonic. Docs describe deposits that take about 15 minutes on Ethereum to finalize, about 1 second on Sonic, then a heartbeat that batches assets every about 10 minutes. Withdrawals and bridge UX are separate from ordinary Sonic sends. Do not treat Gateway timing as Sonic block finality.
web3_clientVersion on the official RPC returned Sonic/v2.2.4-... during the test, so a client-version health check works here (unlike some OP Stack public RPCs that 403 that method).
MetaMask, Rabby, and Rainbow
Sonic's docs list MetaMask, Rabby, OKX, Trust, Bitget, and 1inch among user wallets, plus Safe and institutional options. All three of MetaMask, Rabby, and Rainbow accept Sonic as an EVM network with the fields above.
- 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 Sonic already appears in Rabby's network list before adding a custom entry.
- Rainbow: accepts the same EIP-3085 add request. Confirm the explorer URL is
sonicscan.org.
For wallet_addEthereumChain, send a full EIP-3085 payload: chainId: "0x92", chainName: "Sonic", nativeCurrency: { name: "Sonic", symbol: "S", decimals: 18 }, rpcUrls with your probed HTTPS endpoint, and blockExplorerUrls: ["https://sonicscan.org"]. For wallet_switchEthereumChain, send only { chainId: "0x92" }. Prefer one primary RPC in the wallet payload and keep failover in your own client.
Wallet-add gotchas that show up in QA
- Chain ID 250 in the Sonic row: the network name says Sonic but signatures target Fantom Opera.
- Opera RPC behind a Sonic label:
eth_chainIdreturns0xfa, balances and nonces are Opera state. - FTM symbol on a Sonic network entry: users think they still hold FTM on Opera.
- Ethereum-style priority fees: overpays when Sonic returns a 1 wei tip estimate.
- Underpriced at the raw 50 gwei base fee: transactions rejected unless you add the buffer Sonic docs require (use the ~55 gwei RPC suggestion).
- One shared "fantom" or "sonic" key for Opera and Sonic: separate config keys so a fallback cannot silently swap networks.
- Server-side client with no User-Agent against Nodeflare: HTTP 403 even though browsers and curl succeed.
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 historical state, wide
eth_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_chainIdreturns0x92.- The latest block advances when you poll twice a few seconds apart, and its timestamp is within a few seconds of wall-clock time.
- A plain transfer
eth_estimateGasreturns a value near 21,000. - 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. - If you call from Node, Python, or Go without a library User-Agent, confirm the URL still answers (or set one).
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, archive access, and quota. At the time of writing those include Alchemy, Chainstack, DRPC, and Dwellir. Dwellir's row is a keyed Sonic mainnet archive endpoint over HTTPS and WSS. 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 Sonic network row: chain ID 146 /
0x92, S symbol with the network name shown, SonicScan, RPC you probed today. - Opera row, if you still need it: chain ID 250 /
0xfa, separate config key, never reused as the Sonic RPC. - Fee estimation: use
eth_gasPriceoreth_feeHistory(~55 gwei, already buffered above the 50 gwei MinBaseFee), tip often 1 wei, gas-limit buffer on complex calls, 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 "Sonic" in a dropdown does not replace eth_chainId returning 0x92.