Mantle is an OP Stack based Layer 2 on Ethereum, not "Ethereum with a different RPC URL." Gas is paid in MNT, not ETH, and since the Arsia upgrade the total fee is split into parts that eth_estimateGas alone does not cover. Wallet builders who paste chain ID 1, reuse the Sepolia key, label the fee in ETH, or compute "send max" from gas limit times gas price will ship the wrong network or transactions that fail on the last few cents of balance. Before you wire MetaMask, Rabby, Rainbow, or your own wallet_addEthereumChain flow, prove chain ID 5000, price fees the way Mantle charges them, and probe the URL you intend to ship.
This is not a ranking of providers. Use the Mantle Mainnet hub to compare endpoints and paid rows, then run the checks below on the URL you configure. If you only need the network in a browser wallet, the add Mantle to MetaMask, add Mantle to Rabby, and add Mantle to Rainbow pages have the fields prefilled.
Chain ID 5000 is not Ethereum and not Mantle Sepolia
- Mantle mainnet: chain ID 5000, hex
0x1388. This is what wallets,eth_chainId, and EIP-155 signatures use. - Mantle Sepolia testnet: chain ID 5003, hex
0x138b, RPChttps://rpc.sepolia.mantle.xyz. - Ethereum mainnet: chain ID 1. A wallet that already has Ethereum added still needs a separate Mantle network entry.
Wallet-add fields for mainnet, matching the parameters Mantle publishes for its own add-network snippet:
- Network name:
Mantle - Chain ID:
5000(or0x1388if the form wants hex) - Currency symbol:
MNT - RPC URL: a JSON-RPC HTTPS endpoint you have already probed, such as the official
https://rpc.mantle.xyz - Block explorer:
https://mantlescan.xyz(the olderhttps://explorer.mantle.xyz, which is the explorer link on the hub, redirects there)
Native gas is MNT with 18 decimals, so 1 MNT = 10^18 wei and parseEther("1") means 1 MNT. MNT is a native balance on Mantle, read with eth_getBalance, not an ERC-20 contract call. Wrapped MNT (WMNT) lives at 0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8 if your swap or approval flows need the ERC-20 form. ETH on Mantle is an ERC-20 token at the predeploy 0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111 (its symbol() returns WETH), not the gas token, so a wallet that shows "ETH" next to the fee is showing the wrong unit and needs a token balance call to show ETH holdings.
Call eth_chainId on the exact RPC URL you will ship. Expect 0x1388. A gateway that returns 0x138b is Sepolia. A gateway that returns 0x1 is Ethereum. A timeout, an HTML page, or a "paid plan required" body is not Mantle mainnet for that transport. Run the check after any load balancer or fallback so you are testing the backend production actually hits.
Public endpoints that answered eth_chainId
Each URL below returned 0x1388, a head block within about 10 seconds of wall-clock time, and 0x5208 (21,000) for eth_estimateGas on a plain MNT transfer when this guide was written (2026-09-30, 02:15 UTC):
| Endpoint | Transport | Notes |
|---|---|---|
https://rpc.mantle.xyz | HTTPS | Official, rate limited. Head ran 3 to 4 blocks behind other endpoints during the test |
wss://wss.mantle.xyz | WebSocket | Official WSS that answered. wss://rpc.mantle.xyz, the URL in Mantle's quick-access table, returned HTTP 404 on upgrade |
https://mantle-rpc.publicnode.com / wss://mantle-rpc.publicnode.com | HTTPS, WSS | |
https://mantle.drpc.org / wss://mantle.drpc.org | HTTPS, WSS | eth_estimateTotalFee returned "method is not available" |
https://mantle.api.pocket.network | HTTPS | WSS upgrade on the same host returned HTTP 400 |
https://rpc.swiftnodes.io/rpc/mantle | HTTPS |
Several other rows on the hub failed the same probe at that time. Some returned a discontinued-service error, a paid-plan-required message, a public rate-limit error, an unsupported-chain error, an origin mismatch, or an origin-down error, and one did not respond. A few more answered eth_chainId but refused a follow-up block read, balance read, or eth_estimateGas without an account. A row on a directory page is a starting point, not proof that it serves Mantle mainnet today. Re-run the probe before you ship any URL, including the ones above.
Mantle's own docs state that the official RPC is rate limited and point frequent callers at third-party providers. Treat the table as a probe list for development and QA, not as a production recommendation.
MNT fees after Arsia: estimateGas is not the whole fee
The Arsia upgrade activated on Mantle mainnet on 2026-04-22 and changed how fees work. After Arsia, a transaction pays three parts:
- L2 execution fee,
gasUsed * gasPrice.eth_estimateGasnow returns pure EVM execution gas, so a plain MNT transfer estimates exactly 21,000. - L1 data fee, the cost of posting the transaction to Ethereum, converted to MNT. It does not consume gas limit. It is deducted directly from the sender's balance.
- Operator fee, a small constant plus a gas-proportional amount.
What that means for a wallet:
- Use
eth_estimateTotalFeefor the fee you show. Mantle added this RPC method with Arsia. It takes the same transaction object aseth_estimateGasand returns the total in wei of MNT. In the test above, a plain transfer returned about 0.00138 MNT total, while21,000 * gasPricealone came to about 0.00105 MNT. The difference is the L1 data fee and the operator fee. - "Send max" needs the total. A wallet that subtracts only
gasLimit * maxFeePerGasfrom the balance leaves nothing for the L1 data fee, and the transaction fails for insufficient funds. - Not every endpoint serves the new method.
eth_estimateTotalFeeanswered on the official RPC, PublicNode, Pocket, and Swiftnodes, and returned "method is not available" on DRPC. If your fee UI depends on it, add it to the probe. The fallback isgetL1FeeandgetOperatorFeeon theGasPriceOraclepredeploy (0x420000000000000000000000000000000000000F) plus the execution fee. - Gas prices are MNT-denominated. The base fee is now dynamic EIP-1559. It read 50 gwei during the test. That is a price in MNT, so do not compare it against ETH-denominated L2 gas prices or cap it with an ETH-L2 default.
- Do not reuse pre-Arsia gas limits. Before Arsia,
eth_estimateGasfolded L1 cost into the gas figure and could vary with L1 prices. Hardcoded limits or cached estimates from that era are wrong now.
OP Stack quirks that matter for wallets
- Three block tags, three heights. Blocks arrive every 2 seconds. During the test,
safetrailedlatestby about 180 blocks (6 minutes) andfinalizedby about 840 blocks (28 minutes). Show alatestreceipt as included, and reserve "final" for UI that actually needs L1-backed finality. - Canonical bridge withdrawals take 12 hours. Mantle moved to ZK validity proofs (OP Succinct) in September 2025 and cut canonical bridge withdrawals from 7 days to 12 hours. On Ethereum, the output oracle that Mantle's
OptimismPortalreads returnsfinalizationPeriodSeconds= 43,200 (12 hours). After that window the user still sends an L1 transaction to claim. Wallets that still show a 7-day countdown for Mantle withdrawals are out of date. Third-party bridges have their own timing. - Address aliasing on L1 to L2 messages. For deposits and other L1-initiated transactions,
msg.senderandtx.originon L2 are the aliased L1 address, the same as upstream OP Stack. This matters to contract wallets and allowlists, not to ordinary EOAs. - Standard JSON-RPC otherwise. Mantle documents its API as the Ethereum JSON-RPC API with almost no differences, plus the
eth_estimateTotalFeeaddition.eth_getBlockRangeis deprecated.
MetaMask, Rabby, and Rainbow
All three accept Mantle as an EVM network with the fields above. What to expect:
- MetaMask: the add-network form takes the five fields directly. Mantle's docs publish a one-click
wallet_addEthereumChainsnippet for MetaMask. When a dapp callswallet_switchEthereumChainfor a chain MetaMask does not know, it returns error4902. Handle that by callingwallet_addEthereumChain. - Rabby: check whether Mantle already appears in Rabby's network list before adding a custom entry, so you do not end up with two Mantle 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 Mantle with the fields above and confirm the explorer URL is
mantlescan.xyz.
For wallet_addEthereumChain, send a full EIP-3085 payload: chainId: "0x1388", chainName: "Mantle", nativeCurrency: { name: "MNT", symbol: "MNT", decimals: 18 }, rpcUrls with your probed HTTPS endpoint, and blockExplorerUrls: ["https://mantlescan.xyz"]. For wallet_switchEthereumChain, send only { chainId: "0x1388" }. Prefer one primary RPC in the wallet payload and keep failover in your own client.
A browser wallet computes its own fee display. If your product shows its own fee estimate or a max-send button next to the wallet, that is where eth_estimateTotalFee belongs.
Wallet-add gotchas that show up in QA
- Chain ID 1 in the Mantle row - the network name says Mantle but signatures target Ethereum.
- Sepolia mix-up -
5003/0x138bpasted into a mainnet config, or a Sepolia RPC behind a mainnet label. - ETH as the gas symbol - the native token is MNT. Show the network name and symbol, not "ETH."
- Fee shown from estimateGas only - understates the total by the L1 data fee and operator fee.
- Docs WSS URL used without a probe -
wss://rpc.mantle.xyzreturned 404 during testing,wss://wss.mantle.xyzanswered. - One shared "mantle" 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 historical state, wide
eth_getLogs, or sustained WebSocket traffic - Cannot absorb shared-node brownouts during a mint, airdrop, or market spike
Probe the candidate URL before you call it ready:
eth_chainIdreturns0x1388.- 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_estimateGasand, if you use it,eth_estimateTotalFeeboth answer for a plain MNT transfer.- 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. - One historical
eth_getBalanceat an old block if you need archive, and oneeth_getLogsfilter in the range your indexer uses.
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 or historical access if you need it, and quota. At the time of writing those are DRPC, Chainstack, Infura, Alchemy, and Dwellir. Dwellir's row is a keyed Mantle mainnet endpoint over HTTPS and WSS, billed as one response credit per call on every method, which keeps a mix of cheap reads and heavier fee or trace calls easy to budget. 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 before assuming a wide filter will pass on every URL.
Practical split for a wallet stack
- User-facing Mantle network row - chain ID 5000 /
0x1388, MNT symbol, Mantlescan, RPC you probed today. - Mantle Sepolia row - chain ID 5003 /
0x138b, separate config key, never reused as the mainnet RPC. - Fee estimation -
eth_estimateTotalFeeon an endpoint that serves it, with theGasPriceOraclefallback documented next to it. - Backend / indexer - dedicated or paid endpoint with explicit method and archive needs; do not share the browser wallet's public URL.
- Receipt policy -
latestfor "included,"safeorfinalizedonly where the product needs it, and a 12-hour window plus an L1 claim for canonical bridge withdrawals.
Ship the hub comparison and the probe first. A network called "Mantle" in a dropdown does not replace eth_chainId returning 0x1388.