Skip to main content
Stable is EVM-compatible, so the standard Ethereum libraries work against a Stable node without modification. The differences are in the chain configuration and in a handful of methods the client does not implement.

Chain configuration

Two different USDT0 decimal counts on one chain. The native gas currency carries 18 decimals, so gas balances are wei-denominated exactly as on Ethereum and formatEther and from_wei(..., "ether") are the correct helpers.The USDT0 ERC-20 token at 0x779Ded0c9e1022225f8E0630b35a9b54bE713736 reports 6 decimals. Format that one with formatUnits(value, 6), not formatEther.Both are called USDT0, so the mistake is easy to make and puts you out by a factor of 1012 in whichever direction you got it wrong.
See Stable methods for per-method availability and Debug and trace APIs for the tracing namespaces.

MetaMask

Add Stable Mainnet as a custom network. On Chainstack, get your Stable endpoint, then in MetaMask select Add a custom network and fill in:
  • Network name — Stable
  • Default RPC URL — your Chainstack Stable endpoint
  • Chain ID — 988
  • Currency symbol — USDT0
  • Block explorer URL — https://stablescan.xyz

ethers.js

Install ethers.js:

viem

Stable ships in viem’s bundled chain list as stable, so you do not need defineChain:
Pass your Chainstack endpoint to http() as above. The bundled chain definition carries a public RPC URL, and http() with no argument would use that instead of your node.

web3.py

Install web3.py:
web3.py rejects lowercase addresses with InvalidAddress. Wrap any address you did not get from the library itself in Web3.to_checksum_address(), as above.

Stable behaviors that affect tooling

No trace_* namespace. All nine Parity-style trace methods return -32601. Any library helper or indexer that reaches for trace_block or trace_transaction will fail. Use debug_traceBlockByNumber and debug_traceTransaction with the callTracer instead — see Stable methods for the full swap table. The transaction pool responds but is always empty. txpool_status, txpool_content, txpool_contentFrom, and txpool_inspect all return successfully and report nothing pending. Pending-transaction subscriptions and filters behave the same way: they hand back an ID and then deliver no transactions. Do not build a pending-transaction feed on Stable. See What gives you mempool access. Three methods behave unlike Geth. eth_getProof returns a Cosmos IAVL proof rather than an Ethereum Merkle-Patricia proof, and needs an explicit block number — passing latest returns -32000 proof queries at height <= 2 are not supported. eth_createAccessList returns -32603 method handler crashed; since Stable charges a flat base fee, an access list buys you nothing here anyway. eth_simulateV1 is not implemented. eth_getLogs is capped at 10,000 blocks. Exceeding it returns -32000 maximum [from, to] blocks distance: 10000, and a query that matches too much returns -32000 query returned more than 10000 results. Paginate on both. See EVM range limits. Filters are node-local. A Global Node endpoint is load balanced across backends, and a filter created by eth_newFilter or eth_newBlockFilter lives on the backend that created it. A follow-up eth_getFilterChanges that lands elsewhere returns -32000 filter not found. Poll eth_getLogs over an explicit block range instead, or hold a WSS subscription, which keeps one connection to one backend for its lifetime.
Last modified on August 5, 2026