guide8 min read

Avalanche C-Chain RPC for Builders: Gas and API Traps vs Ethereum

What breaks when you treat Avalanche C-Chain like Ethereum: chain ID 43114 vs net_version 1, AVAX gas, Coreth fee methods, accepted finality, and /ext/bc/C/rpc.

By RPC Directory•
#Avalanche#C-Chain#AVAX#RPC#Chain ID 43114#Coreth#Gas#Finality
$avalanche-c-chain-rpc.md

Avalanche C-Chain speaks JSON-RPC that looks like Geth. That is the trap. Builders who reuse an Ethereum gas oracle, trust net_version the way they do on mainnet, wait "twelve confirmations," or point a bare host root at Avalanche will mis-price fees, mis-label the network, or talk to the wrong path. Before you ship an indexer, keeper, wallet, or bridge worker, prove chain ID 43114, treat AVAX as native gas, and probe the Avalanche-specific fee and acceptance surfaces on the exact URL you will use.

This is not a ranking of providers. Use the Avalanche Mainnet hub to compare public endpoints and paid rows, then run the checks below. That hub is the C-Chain mainnet row for this directory. It is not the X-Chain or P-Chain.

Chain ID 43114 is not net_version 1

C-Chain mainnet EVM chain ID is 43114, hex 0xa86a. Fuji testnet is 43113 (0xa869). Ethereum mainnet is 1.

Avalanche documents a second, easy-to-confuse value: the C-Chain's internal networkID is 1 on both mainnet and Fuji. That is what net_version returns. It is not the EIP-155 chain ID and has no relationship to Avalanche's own Primary Network IDs. If your health check only calls net_version and treats "1" as "Ethereum-compatible, good enough," you have not proven C-Chain mainnet. Call eth_chainId. Expect 0xa86a on mainnet.

Do this on the transport you will ship, after any load balancer or fallback. An SDK chain object that says 43114 while the HTTP client still points at another host is a funds bug waiting for a send.

Native gas is AVAX with 18 decimals. Explorer for C-Chain mainnet tx hashes is Snowtrace. Pointing users or ops runbooks at etherscan.io for C-Chain hashes is a support bug.

The path is /ext/bc/C/rpc, not a bare Ethereum URL

Official and many public C-Chain HTTP endpoints use a path such as /ext/bc/C/rpc (WebSocket: /ext/bc/C/ws). A hostname that answers on / with Ethereum-shaped errors is not proof you are on C-Chain. Paste the full URL you intend to configure, including the path, into the probe.

The Avalanche Mainnet hub lists current public rows (including Avalanche's own https://api.avax.network/ext/bc/C/rpc and third-party gateways). Treat published URLs as starting points. Re-probe before baking one into a release. Fuji and other EVM instances use different paths or hosts; do not reuse a Fuji URL on a mainnet network row.

C-Chain is the Contract Chain. X-Chain and P-Chain are different APIs and different address formats. Atomic / cross-chain flows that need UTXOs or P-Chain staking talk to /ext/bc/C/avax (and other Avalanche APIs), not only eth_*. If your product only needs EVM contract calls, stay on /ext/bc/C/rpc and keep atomic tooling out of the same client config key.

Gas: do not import an Ethereum fee oracle

C-Chain uses an EIP-1559-style fee market in AVAX, implemented in Coreth, not Ethereum's blob-era fee machinery. Copying a mainnet ETH gas UI, a fixed "20 gwei" heuristic, or an Ethereum-only fee history sampler will overpay, underpay, or stall inclusion when C-Chain base fee moves.

Probe fees on the candidate URL:

  1. eth_gasPrice — legacy suggestion. Fine as a sanity check; not your only signal for EIP-1559 wallets.
  2. eth_baseFee — Avalanche extension: base fee for the next block (hex). Official C-Chain docs expose this on the same /ext/bc/C/rpc endpoint.
  3. eth_maxPriorityFeePerGas — tip suggestion for inclusion.
  4. Where supported, eth_suggestPriceOptions — slow / normal / fast bundles of maxFeePerGas and maxPriorityFeePerGas aimed at wallets (Coreth). Method-not-found means that node build does not offer it; fall back to base fee + tip, do not invent Ethereum mainnet defaults.

Practical rules:

  • Build EIP-1559 txs with AVAX denominations. Do not label the fee UI "gwei ETH."
  • Re-estimate before send when the mempool is busy. C-Chain target gas and base-fee dynamics differ from Ethereum; a stale quote from an ETH oracle is wrong twice.
  • If eth_baseFee or eth_maxPriorityFeePerGas errors on a URL that otherwise serves eth_blockNumber, you are not on a full C-Chain surface — or a proxy is stripping extensions. Decide whether your wallet can live on legacy eth_gasPrice alone before you ship.

Public API nodes also document a batch size limit of 40 on the Avalanche public API. Ethereum habits that batch hundreds of eth_calls will fail here. Split batches and back off on 413/batch errors.

Acceptance is not "wait N Ethereum blocks"

Snowman-style acceptance on C-Chain is not Ethereum's probabilistic reorg ladder. Avalanche operator docs are explicit: waiting for more block depth does not increase finality confidence the way it does on chains that reorg. Nodes that expose only accepted state (the common production default) already hide unfinalized tips unless allow-unfinalized-queries is enabled.

What that means for builders:

  • Do not port an Ethereum "wait 12 blocks" receipt policy onto 43114 and call it safer. Extra depth is not Avalanche's confirmation model.
  • Prefer reading accepted / finalized heads from the node you use. If you need push on acceptance, Avalanche documents eth_newAcceptedTransactions (WebSocket) as a C-Chain-specific subscription that fires when a transaction is accepted — not available on vanilla Ethereum.
  • latest / safe / finalized tags may still appear on Coreth builds. Log what your endpoint returns. Do not assume Ethereum post-Merge semantics. If your app needs "will not unwind under this node's acceptance rules," measure acceptance (or the Avalanche-specific subscription), not an imported block-count from an ETH runbook.

Cross-chain workers: one confirmation policy per chain ID, stored next to each RPC URL. An Ethereum worker and a C-Chain worker should not share a single CONFIRMATIONS=12 constant.

API surface: Geth-shaped, not Geth-identical

Avalanche states the C-Chain JSON-RPC is Geth-like for web3_, net_, eth_, personal_, txpool_, and debug_ — with important exceptions:

  • debug_* is off on the public API node. Do not design a production tracer that assumes public Avalanche endpoints expose debug.
  • eth_getProof behavior differs from Geth (from Coreth v0.12.2+): archival nodes can reject proofs older than a configured window (default on the order of 24 hours before last accepted); pruned nodes reject proofs outside a short window after last accepted. An Ethereum archive assumption ("proof at any historical block") will fail on many C-Chain URLs.
  • Extra methods already noted: eth_baseFee, eth_maxPriorityFeePerGas, eth_getChainConfig, and (on current docs) helpers such as eth_callDetailed / eth_suggestPriceOptions. Probe what you need; method-not-found is a product constraint, not a transient 500.

Full vs archive still follows the call, not the marketing label. Historical eth_call / eth_getBalance, traces, and deep eth_getLogs need a node that retains that state. The eth_getLogs caps guide covers filter limits across EVMs, including Avalanche C-Chain's ~2s block time when you size ranges.

Probe the endpoint you will ship, then look at paid rows

Run this set once against the candidate URL and save the responses:

  1. eth_chainId returns 0xa86a. Do not stop at net_version returning "1".
  2. Confirm the URL path is the C-Chain RPC you intend (/ext/bc/C/rpc or your provider's documented equivalent).
  3. eth_blockNumber moves when you poll twice a few seconds apart.
  4. eth_baseFee and eth_maxPriorityFeePerGas succeed if your fee logic depends on them; optionally eth_suggestPriceOptions.
  5. One balance or receipt read against a known C-Chain mainnet address (not Ethereum, not Fuji).
  6. One historical eth_call / eth_getBalance at an old block if you need archive; one eth_getLogs in your real range.
  7. If you need push: wss path that survives disconnect; optionally eth_newAcceptedTransactions if acceptance push is part of the design.

Public endpoints on the hub are shared and rate-limited. Use them for the probe and for development. For production, compare the paid rows on the same hub for archive, WebSocket, method coverage, and quota. Dwellir is one of those rows: a flat response-credit model that is easier to budget when the mix of eth_call, logs, and fee polls is not stable. 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. The pricing calculator is there for the rest.

Practical split for a C-Chain stack

  • User-facing / wallet path — chain ID 43114 / 0xa86a, AVAX symbol, Snowtrace, RPC URL with the real C-Chain path, fee logic from C-Chain base fee / tip (not an ETH oracle).
  • Backend / indexer — dedicated or paid endpoint; explicit archive and eth_getLogs needs; batch size within public limits if you still use a shared gateway.
  • Acceptance policy — document whether "confirmed" means accepted tip, an Avalanche acceptance subscription, or a tag you have measured on this node — not CONFIRMATIONS=12 copied from Ethereum.
  • Atomic / X/P-Chain path — separate clients and keys; never point EVM eth_* traffic at those APIs or the reverse.
  • Fuji — separate config key (43113); never reused as the mainnet RPC.

Ship the hub comparison and the probe first. "EVM compatible" does not mean net_version === "1" is sufficient, and it does not mean Ethereum gas and confirmation habits are safe on C-Chain.