Monad is an EVM Layer 1 with the native MON token for gas. Blocks arrive about every 0.3 seconds and execution runs a few blocks behind consensus. The JSON-RPC surface looks like Geth, but Monad charges gas on the gas limit you sign, not the gas you use, and full nodes do not keep old state. Wallet builders who copy Ethereum defaults for gas padding, history reads, or pending transactions will overcharge users or show results that change a moment later.
This is not a ranking of providers. Use the Monad Mainnet hub to compare endpoints and paid rows, then run the checks below on the URL you configure. The Monad Mainnet providers page lists the keyed options side by side.
Chain ID 143 is mainnet, 10143 is testnet
- Monad mainnet: chain ID 143, hex
0x8f.eth_chainIdreturned0x8fon every URL that answered during our probe, andnet_versionreturned"143". Monad's network information page lists the same chain ID. - Monad testnet: chain ID 10143, hex
0x279f. Chainlist (chainid.network) lists it as "Monad Testnet" with the sameMONsymbol. A wallet that shows MON without the network name can make a testnet balance look like real funds. - Ethereum mainnet: chain ID 1. Monad is its own Layer 1, not a rollup, so it needs its own network entry.
Wallet-add fields for mainnet, matching Monad's published network information:
- Network name:
Monad Mainnet(Chainlist usesMonad) - Chain ID:
143(or0x8fif the form wants hex) - Currency symbol:
MON - RPC URL: a JSON-RPC HTTPS endpoint you have already probed, such as
https://rpc1.monad.xyz - Block explorer:
https://monadscan.comorhttps://monadvision.com
Native gas is MON with 18 decimals. Call eth_chainId on the exact RPC URL you will ship and expect 0x8f. A gateway that returns 0x279f is testnet. A timeout, an HTML page, an API-key error, or a rate-limit body is not Monad mainnet for that transport.
Public endpoints that answered eth_chainId
We probed every public Monad mainnet URL on the hub 8 times, about 55 seconds apart, on 2026-10-12 between 02:12 and 02:19 UTC. Each round called eth_chainId, eth_getBlockByNumber("latest"), eth_getBalance on the Wrapped MON contract, and an eth_call for Wrapped MON's totalSupply(), with a curl User-Agent on every request. The hub lists 19 HTTPS and 2 WSS transports. These passed all four calls in 8 of 8 rounds. On every one, the latest block's timestamp was within 1.5 seconds of our clock (Monad block timestamps are whole seconds):
| Endpoint | Transport | Notes |
|---|---|---|
https://rpc1.monad.xyz | HTTPS | Monad docs list it as run by Alchemy, 15 requests per second, debug_ and trace_ disabled |
https://rpc2.monad.xyz | HTTPS | Monad docs list it as run by Goldsky Edge, 300 requests per 10 seconds, historical eth_call supported |
https://rpc3.monad.xyz | HTTPS | Monad docs list it as run by Ankr, 300 requests per 10 seconds, debug_ disabled |
https://rpc4.monad.xyz | HTTPS | Not in the public RPC table on Monad's network information page |
https://rpc-mainnet.monadinfra.com | HTTPS | Monad Foundation. Docs list 20 requests per second, batch limit 1, historical eth_call supported |
https://monad-rpc.huginn.tech / wss://wss.monad-rpc.huginn.tech | HTTPS, WSS | Both transports passed all four calls |
https://gm.monad.at.htw.tech | HTTPS | The WSS URL on the same host failed (see below) |
https://infra.originstake.com/monad/evm | HTTPS | |
https://monad-mainnet.rpc.sentio.xyz / https://rpc.sentio.xyz/monad-mainnet | HTTPS | Two URLs for the same provider; both passed |
https://monad-mainnet-rpc.spidernode.net | HTTPS | |
https://rpc.swiftnodes.io/rpc/monad | HTTPS |
Some rows answered with caveats and stay listed:
https://monad-mainnet.drpc.orgpassedeth_chainId, the latest block andeth_getBalancein 8 of 8 rounds. Oureth_callsent nogasfield and returned-32000"user-specified gas exceeds provider limit" every time. A second 8-round run from 02:20 to 02:27 UTC withgasset to 10,000,000 passed all four calls in every round. Set an explicit gas value oneth_callagainst this URL.https://monad-mainnet.gateway.tatum.iopassed the first three calls in 8 of 8 rounds.eth_callreturned-16401"available for paid plans only" every time, so it cannot read token balances without a plan.https://monad-mainnet.api.onfinality.io/publicpassed 4 of 8 rounds. The other rounds returned HTTP 429 with a request to use an API key.https://rpc.monad.xyz(QuickNode, the first URL in Monad's docs) returned0x8fand current blocks when it answered, but 19 of 32 requests from our probe host failed the TLS handshake after 10 seconds. A second run from 02:20 to 02:27 UTC failed the same way on 19 of 32 requests, while short manual checks in between all succeeded. We could not rule out our own network path, so it stays listed. Test it from your own servers before you rely on it.
The hub's Dwellir row is a keyed URL: https://api-monad-mainnet-full.n.dwellir.com/ followed by an API key. Without a key it returned HTTP 403 "API key does not exist" on every call, as expected for a keyed endpoint, so it is not in the table above.
Three rows failed all 8 rounds, and the directory now hides them:
https://lb.routeme.sh/rpc/evm/143returned HTTP 429, JSON-RPC-32029"public rate limit exceeded", in every round.https://monad.rpc.blxrbdn.comdoes not resolve in DNS (NXDOMAIN).wss://gm.monad.at.htw.techaccepted the WebSocket connection but answered-32601"Method not found" to every call, includingeth_chainId.
A row on a directory page is a starting point, not proof it serves Monad mainnet today.
What the Monad JSON-RPC does differently
Monad's JSON-RPC overview lists where it departs from Geth. The ones a wallet hits:
- No pending transactions.
eth_getTransactionByHashreturnsnulluntil the transaction is in a block. Do not treatnullright after a send as "dropped". - Deferred validation on send.
eth_sendRawTransactioncan accept a transaction with a nonce gap or too little MON, because the RPC node may not have the latest state yet. Check the receipt, not the send response. - No arbitrary historic state.
eth_calloreth_getBalanceat an old block number can fail on full nodes. Monad's docs listrpc2.monad.xyzandrpc-mainnet.monadinfra.comas supporting historical state lookups. - Small
eth_getLogsranges. Monad's docs list 100 blocks per call onrpc.monad.xyzandrpc-mainnet.monadinfra.com, and 1,000 onrpc1andrpc3. At 0.3 seconds per block, 100 blocks is about 30 seconds of chain time, so activity history needs many calls or an indexer. - No blob transactions. Type 3 (EIP-4844) transactions are rejected.
- WebSocket:
newHeadsandlogsfire on proposed blocks.newPendingTransactionsis not supported. Monad addsmonadNewHeadsandmonadLogs, which report each block's commit state as it advances.
web3_clientVersion on rpc1.monad.xyz returned Monad/0.16.4 during the test.
Fees: charged on the gas limit, not gas used
On rpc1.monad.xyz at 02:20 UTC:
- The latest block's
baseFeePerGaswas0x174876e800(100 gwei), the minimum base fee in Monad's gas pricing docs. eth_gasPricereturned0x17bfac7c00(102 gwei).eth_maxPriorityFeePerGasreturned0x77359400(2 gwei). Monad's docs say this is a hardcoded suggestion for now.eth_feeHistoryover 5 blocks showed a base fee of 100 gwei in every block and median tips of 2 to 10 gwei.eth_estimateGasfor a plain MON transfer returned0x5208(21,000).- The block gas limit was
0x8f0d180(150,000,000).
A plain transfer at 102 gwei costs 21,000 × 102 gwei, or 0.002142 MON. What makes Monad different is the charge: the sender pays gas_limit × price_per_gas, whatever the transaction actually uses. Monad's docs say this protects the network under asynchronous execution.
What that means for a wallet:
- Do not pad the gas limit on transfers. A native MON transfer always uses exactly 21,000 gas. A 20% buffer on Ethereum costs nothing extra. On Monad it costs the user 20% more.
- Keep buffers on contract calls small, and set known limits explicitly. Every unit of headroom is paid for. Monad's docs recommend that dapps set the gas limit themselves when it is known in advance.
- Watch for reverted estimates. Monad's docs warn that some wallets, MetaMask included, set a very high gas limit when
eth_estimateGasreverts. On Monad the user pays for that whole limit. Show the revert to the user instead of sending. - Show the fee as limit × price. There is no refund for unused gas, so the gas limit, not a usage estimate, sets what the user pays.
The 10 MON reserve balance
Because consensus runs ahead of execution, Monad keeps a reserve balance of 10 MON per account (reserve balance docs). Most users never notice it. A wallet does notice in two cases:
- Quick sends from a small balance. An undelegated account can drop below 10 MON once in any 3-block window. A second send from the same account inside that window can revert, or not be included at all, if it would take the balance below 10 MON. Space back-to-back sends from low balances, or let the first one confirm.
- EIP-7702 delegated accounts cannot drop below 10 MON at all. A transaction that would take them lower reverts but still pays gas.
Finality: latest, safe, finalized
In a single batch request to rpc3.monad.xyz and rpc2.monad.xyz, safe was 0 to 1 block behind latest, and finalized was 1 to 2 blocks behind. Across the last 10,000 blocks, timestamps spanned 3,019 seconds, about 0.30 seconds per block. That matches the 300 ms block time in Monad's docs.
Monad maps the tags to its block states:
latestis a proposed block, speculatively executed with no consensus vote yet. Data atlatestcan change on the next identical request.safeis a voted block.finalizedis finalized and cannot be reverted without a hard fork.
For a wallet, latest is fine for balances on screen. For "payment received", deposits, or anything you credit, wait until the receipt's block number is at or below finalized. At these speeds that is under a second of extra wait.
Add Monad to MetaMask or Rabby
These are the values we checked on 2026-10-12, not values copied from a list:
eth_chainIdreturned0x8f(143) on every passing URL in the table above.- Chainlist's entry for chain 143 is named "Monad", with
MONand 18 decimals, and listshttps://monadscan.comandhttps://monadvision.comas explorers. Monad's own docs list the same two explorers. - Both explorers returned HTTP 200 to a request with a browser User-Agent.
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 whether Monad already appears in Rabby's network list before you add a custom entry. If you add it by hand, enter chain ID 143 and an RPC URL that returned 0x8f in your own probe.
Dapps: for wallet_addEthereumChain, send chainId: "0x8f", chainName: "Monad Mainnet", nativeCurrency: { name: "Monad", symbol: "MON", decimals: 18 }, rpcUrls with your probed HTTPS endpoint, and blockExplorerUrls: ["https://monadscan.com"]. For wallet_switchEthereumChain, send only { chainId: "0x8f" }, and call wallet_addEthereumChain if MetaMask returns error 4902.
Wallet-add gotchas that show up in QA
- Testnet chain ID 10143 under a "Monad" label: balances look real but are testnet MON.
- Ethereum-style gas padding: every padded unit is charged on Monad.
- Huge gas limit after a reverted estimate: the user pays the full limit for a transaction that was going to fail.
- "Dropped" after send:
eth_getTransactionByHashreturnsnulluntil inclusion, which on Monad is a fraction of a second later. - Credited too early: a
latestresult can change. Credit atfinalized. - History screens that call
eth_getLogsover wide ranges: 100 or 1,000 block caps on the public RPCs. eth_callwith no gas field against DRPC's public URL:-32000until you set one.
Public vs dedicated for wallet traffic
Monad's docs describe the public endpoints as rate-limited but enough for basic usage, and point to RPC providers for higher limits.
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 historical state or wide
eth_getLogsranges - Depend on WebSocket subscriptions at volume
- Cannot absorb shared-node rate limits during a launch, airdrop, or market spike
Probe the candidate URL before you call it ready:
eth_chainIdreturns0x8f.- The latest block advances when you poll twice a second apart, and its timestamp is within a couple of seconds of wall-clock time.
- A plain transfer
eth_estimateGasreturns0x5208(21,000). - An
eth_callon a token contract you care about returns data, not a paid-plan or gas-limit error. finalizedreturns a block one or two behindlatest.- 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 paid rows on the same hub for method coverage, archive access, and quota. At the time of writing those include Alchemy, Chainstack, DRPC, Infura, and Dwellir. Dwellir's row is a keyed Monad mainnet endpoint. 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 Monad network row: chain ID 143 /
0x8f, MON symbol with the network name shown, Monadscan or MonadVision, an RPC you probed today. - Testnet row, if you need it: chain ID 10143 /
0x279f, a separate config key, never reused as the mainnet RPC. - Fee estimation:
eth_gasPriceor base fee plus the 2 gwei tip, no padding on transfers, tight limits on contract calls, fee shown as limit × price. - Confirmations: show
latestright away, credit atfinalized. - Backend / indexer: a dedicated or paid endpoint with historical state and the
eth_getLogsrange you need. Do not share the browser wallet's public URL.
Ship the hub comparison and the probe first. A network called "Monad" in a dropdown does not replace eth_chainId returning 0x8f.