Cronos RPC: A Developer's Guide

By John Sullivan · September 23, 2026 · 7 min read · #cronos #rpc #developer guide #evm #cosmos

Cronos is Crypto.com's EVM chain: Solidity contracts, eth_* methods, MetaMask, viem and ethers all work unchanged. Underneath, it is a Cosmos SDK chain with an EVM module, and that shows up in exactly the places where Ethereum habits break: how fast blocks arrive, how much history a node keeps, and what the error messages look like when you ask for something it has already thrown away.

Plenty of documentation still describes Cronos as a 5–6 second chain. Our own chain page said so until this post. The chain I measured today produces a block roughly every 0.42 seconds, which changes how you should poll, index and cache.

Everything below was measured on 2026-09-23 through https://rpc.swiftnodes.io/rpc/cronos. Re-run any of it.

The essentials

Chain ID 25 (0x19); net_version also returns 25
Native token CRO, 18 decimals
Block time ~0.42 s: 0.410 s over 100 blocks, 0.422 over 1,000, 0.419 over 10,000, 0.421 over 100,000, 0.428 over 1,000,000
Head at time of writing 95,687,161 (2026-09-23 14:03:29 UTC)
Finality latest = safe = finalized, in every batched read
Block gas limit 60,000,000
Base fee 375 gwei, flat across the last 11 blocks; eth_maxPriorityFeePerGas 3.75 gwei
eth_getLogs range 10,000 blocks (about 70 minutes of chain time), and an address is required
Historical state ~100 blocks (under a minute)
debug_* / trace_* Not available (-32601)
WebSocket eth_subscribe("newHeads") works
RPC https://rpc.swiftnodes.io/rpc/cronos?key=YOUR_API_KEY

Connecting

Any EVM client works. viem does not need a custom chain definition, because it ships cronos:

import { createPublicClient, http, webSocket } from "viem";
import { cronos } from "viem/chains";

const client = createPublicClient({
  chain: cronos,
  transport: http("https://rpc.swiftnodes.io/rpc/cronos?key=YOUR_API_KEY"),
});

console.log(await client.getChainId());      // 25
console.log(await client.getBlockNumber());  // 95687161n at time of writing
curl -s -X POST "https://rpc.swiftnodes.io/rpc/cronos?key=YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'

The two token contracts most integrations touch first, both read back with eth_call today:

Token Address decimals()
WCRO 0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23 18
USDC 0xc21223249CA28397B4B6541dfFaEcC539BfF0c59 6

USDC's 6 decimals is the usual trap for code that assumes 18 on an EVM chain.

0.42-second blocks change your polling math

At ~0.42 s per block, Cronos produces roughly 205,000 blocks per day. A million blocks is under five days. Three consequences:

  • Polling eth_blockNumber every second skips blocks. Each poll sees the head move by two or three. That's fine if you only need the tip. If you process every block, fetch ranges (fromBlocktoBlock), not "the next one".
  • Block-count thresholds from Ethereum are far too short here. "Wait 12 blocks" is five seconds on Cronos. If you express staleness, cache TTLs or confirmation UX in blocks, convert them from seconds first.
  • Subscriptions beat polling. Over WebSocket, newHeads delivered 10 consecutive heads in 4.4 seconds after subscribing, the first one 675 ms in:
const ws = createPublicClient({
  chain: cronos,
  transport: webSocket("wss://rpc.swiftnodes.io/ws/cronos?key=YOUR_API_KEY"),
});

ws.watchBlocks({
  onBlock: (b) => console.log(b.number, b.transactions.length),
});

Handle reconnects without losing events. At this block rate, a 30-second disconnect is about 70 blocks. The pattern is in WebSocket reconnects without losing events.

Finality: there is nothing to wait for

Cronos uses CometBFT-style consensus, so a committed block is final. I read latest, safe and finalized in a single JSON-RPC batch three times, so all three came from the same instant. They returned the same height every time (95,687,363, then 95,687,365, then 95,687,367).

You can drop reorg handling written for probabilistic chains. Keep a sanity check anyway — the reasoning is in handling chain reorgs in an indexer — but you do not need a confirmation depth.

Gas: flat base fee, near-empty blocks

Over the last 10 blocks, eth_feeHistory returned a base fee of exactly 375 gwei for every block. The highest gasUsedRatio was 0.0083 (0.83% of the 60M gas limit), and several blocks were empty. eth_gasPrice returned 378.75 gwei, which is the base fee plus the 3.75 gwei suggested tip.

Blocks are this empty, so the tip is not buying you anything. A real type-2 transaction I pulled from the chain paid an effective gas price of 375,000,000,001 wei: the base fee plus a 1-wei tip. Basic cost figures:

Operation Gas (measured) Cost at 375 gwei
Plain CRO transfer 21,000 (eth_estimateGas0x5208) 0.007875 CRO
Sample contract call (from chain) 127,908 ~0.048 CRO

If you hard-code gas prices from Ethereum-mainnet habits (a few gwei), your transactions will never be included, because the base fee here is 375 gwei. For the general method, see estimating gas with eth_estimateGas and EIP-1559.

eth_getLogs: 10,000 blocks, address required

I queried USDC Transfer events over growing ranges:

Range (blocks) Result
100 4 events, 158 ms
1,000 41 events, 359 ms
5,000 217 events, 369 ms
10,000 413 events, 1,016 ms
50,000 maximum [from, to] blocks distance: 10000
100,000 -32701 exceed maximum block range: 50000

Two different limits came back from two different upstream nodes. Code to the smaller one: 10,000 blocks. On Cronos, that covers about 70 minutes, so backfilling a single day takes about 21 requests and a month about 620. The chunking loop from eth_getLogs range caps applies, with one change: chunk size in blocks has to be sized for a fast chain.

A query with only a topic and no address was refused three times out of three with -32701 and the message "Please specify an address in your request". Wide event scans ("every ERC-20 Transfer on the chain") are not something this endpoint will serve. Filter by contract.

History: plan for a node that forgets

This is the part that will break an Ethereum-shaped indexer. The Cosmos SDK nodes behind this endpoint prune aggressively.

State (balances, eth_call at a past block) lasts about 100 blocks. eth_getBalance at 20 and 50 blocks behind the head succeeded. At about 100 blocks behind, and at every depth from there out to 3,000,000, it failed with:

codespace sdk code 18: invalid request: failed to load state at height 91687369;
version mismatch on immutable IAVL tree; version does not exist.
Version has either been pruned, or is for a future block height

A hundred blocks is about 40 seconds. "Read the balance as of this morning" is not a query this endpoint can answer. If you need historical state, you derive it from events, or you run an archive node. We explain that trade-off in full node vs archive node.

Blocks and logs go back further, but the floor depends on which node answers. One upstream reported its lowest height as 90,850,001, and block 90,850,001 (2026-08-30) came back intact. Another reported 95,187,533, about 500,000 blocks or ~2.4 days behind the head. Design backfills around the shorter window, and treat "not available" as a per-node answer.

Pre-floor blocks return null, not an error. eth_getBlockByNumber for block 1, 1,000,000 and 50,000,000 returned result: null, and so did the earliest tag. Code that treats null as "block does not exist yet" will misreport pruned history as the future.

What works and what doesn't

Method Result
eth_call, eth_estimateGas, eth_feeHistory, eth_maxPriorityFeePerGas Works
eth_getBlockReceipts Works (all receipts for a block in one call)
eth_call with a state-override object Works (see state overrides)
txpool_status Works (pending / queued)
eth_createAccessList Works only with gas set; without it: gas must be set when using authorization list
debug_traceTransaction, debug_traceBlockByNumber, trace_transaction Not available: -32601 method does not exist/is not available
eth_subscribe("newHeads") over wss:// Works

The eth_createAccessList error is misleading: my call had no authorization list, and passing any gas value (I used 200,000) made it succeed. If your library calls it without gas, add one.

No tracing means no call trees for debugging reverts or tracking internal CRO transfers over RPC. To find out where a transaction failed, re-run it with eth_call at the latest block before state moves on — which, at ~100 blocks of state, is less than a minute.

What this means for your stack

Think in seconds, not blocks. Convert every Ethereum-tuned block count (confirmations, TTLs, backoff) to wall-clock time first. At 0.42 s, ported block numbers are about 30x too short.

Chunk eth_getLogs at 10,000 blocks and always pass an address.

Read state at the head, and derive history from events. A shared endpoint keeps about 40 seconds of state.

Handle null for pruned blocks and expect the floor to change with the node that answers.

Skip confirmation depth, keep a sanity check. Finality is single-block.

The short version

Cronos is EVM chain 25 with ~0.42-second blocks (stable from 100 to 1,000,000-block windows) and single-block finality (latest = safe = finalized). The base fee sits at a flat 375 gwei with blocks under 1% full. eth_getLogs is capped at 10,000 blocks (about 70 minutes) and needs an address. Historical state survives about 100 blocks, block history between ~2.4 and ~24 days depending on the node, and pruned blocks come back as null. There is no debug_/trace_ namespace, eth_createAccessList needs gas, and newHeads subscriptions deliver every block.

https://rpc.swiftnodes.io/rpc/cronos?key=YOUR_API_KEY
wss://rpc.swiftnodes.io/ws/cronos?key=YOUR_API_KEY

The Cronos RPC page shows the live status of these endpoints. One key covers all 86 chains, and the free tier is 2 requests per second — enough to re-run every probe in this post.

J
John Sullivan
Infrastructure Writer, SwiftNodes

John Sullivan covers RPC infrastructure, node operations, and multi-chain development at SwiftNodes — what it actually takes to keep endpoints fast, fresh, and reliable across EVM and non-EVM networks.

Related posts

  • Babylon RPC: A Developer's Guide

    How to query Babylon Genesis over RPC and LCD — CometBFT 0.38.22 on chain bbn-1, ~9.6 second blocks, 68 validators, blocks filled with finality signatures, why tx_search refuses ranges, and the pruning floor that gave three different answers in six calls.

  • Hyperliquid RPC: A Developer's Guide

    How to query HyperEVM over JSON-RPC — chain 999, ~1s blocks, a near-fixed 0.1 gwei base fee, a 1000-block and 1 MiB eth_getLogs cap, no WebSocket, and the one that will cost you money: state methods accept a block number and then ignore it, so historical reads silently return the latest state.

  • Neutron RPC: A Developer's Guide

    How to query Neutron over JSON-RPC — CometBFT 0.38 on chain neutron-1, why there is no numeric chain ID, the header fields that disappeared in 0.38, a tx_search that times out instead of answering, a pruning floor that differs between nodes, and a block time that measured 7s this week against a 2s baseline.

Try SwiftNodes free — multi-chain RPC across 86 networks, flat-rate pricing, pay by card or crypto, no KYC. Get an API key in 30 seconds →