Skip to content
New guideAgent Cookbook 12 copy-ready prompts for AI coding agents.See recipes
All blog posts
Exchange Deposit Detection Across Chains: Confirmations, Reorgs and Finality per Chain, Measured on Live Endpoints

Exchange Deposit Detection Across Chains: Confirmations, Reorgs and Finality per Chain, Measured on Live Endpoints

By Ben Chatwin25min read

An exchange that credits an Ethereum deposit after one block is exposed for about 15 minutes, which is how long Ethereum takes to finalize. An exchange that makes customers wait 15 minutes on Arc is holding their money for about 1,800 blocks that could never have been reversed. Both mistakes come from using one confirmation rule for every chain.

The right rule differs by chain in kind as well as in number. Some chains hand you a finalized tag backed by slashable stake. Tron gives you a solidified block from a committee of 27 producers. Base and other rollups inherit finality from Ethereum through a batch that Ethereum then takes a quarter of an hour to finalize, and Bitcoin gives you nothing but probability.

This page puts the per-chain answers in one table, measured on 5 November 2026 against Dwellir's production endpoints, then shows a detection pipeline that survives a reorg on any of them. The finality and reorg explainers cover the underlying concepts. This post turns them into a deposit policy.

Three questions every deposit policy must answer

For every chain you accept deposits on, you need to know:

  1. Which signal means settled. A block tag, a solidified height, a finalized head, or a confirmation count.
  2. How long that signal takes behind the chain head, so you can set customer expectations and size your pending state.
  3. What the chain does when it changes its mind, and how your RPC layer tells you. On EVM chains that is the removed field on logs and a broken parentHash chain.

The answers give you a ladder of states rather than a single threshold:

Deposit stateWhat the customer can doSignal to reach it
SeenSee it as pending in the UITransaction in latest
Credited for tradingTrade against it, no withdrawalBlock at or below safe, or the chain's equivalent
SettledWithdraw, including to another chainBlock at or below finalized, or N confirmations on probabilistic chains

The table below gives the signals and the measured distances for each chain.

The per-chain confirmation table

Every block number below comes from Dwellir endpoints between 19:55:53 and 19:56:56 UTC on 5 November 2026, read with eth_getBlockByNumber for the latest, safe and finalized tags or the chain's native equivalent. Lag is the block distance between latest and the tag at that instant, converted to time using the block time over the preceding 100 blocks. Lag moves within each chain's finality cycle, so treat each figure as one sample rather than a constant. The three tags were read one after another, so a chain with sub-second blocks can show a one-block skew between them, which is why HyperEVM shows 0 to 1 block. Base was read under two hours after its Denim upgrade activated on mainnet at 18:00 UTC, so its block time is 0.2 seconds, not the 2 seconds older guides assume.

ChainBlock timeFinality mechanismSettled signalMeasured lag: safeMeasured lag: finalizedReorg exposure before the signal
Ethereum12 sCasper FFG checkpointsfinalized tag41 blocks, about 8 min73 blocks, about 15 minHead reorgs happen; 7 blocks on 25 May 2022
Base0.2 s (Denim)L1 batch finalitysafe to credit, finalized to settle137 blocks, about 27 s4,458 blocks, about 15 minSequencer can reorg latest; safe only via an L1 reorg
Optimism2 sL1 batch finalitysafe to credit, finalized to settle91 blocks, about 3 min762 blocks, about 25 minAs Base
Arbitrum One0.25 sL1 batch finalityfinalized tag2,055 blocks, about 8.6 min3,501 blocks, about 14.6 minlatest is a sequencer promise
Robinhood Chain0.1 sL1 batch finality (Arbitrum Orbit)finalized tag5,235 blocks, about 8.7 min8,811 blocks, about 14.7 minAs Arbitrum
Polygon PoSabout 2 sHeimdall v2 milestonesfinalized tagnot supported, returns null2 blocks, about 4 s157-block reorg on 22 Feb 2023, before milestones
BNB Smart Chain0.75 sBEP-126 fast finalityfinalized tag1 block1 block, under 1 sFalls back to probabilistic if fast finality stalls
Avalanche C-Chain0.8 sSnowman, final on acceptancefinalized tag6 blocks, about 5 s6 blocks, about 5 sNone by design
Tron3 sDPoS, 19 of 27 producerswalletsolidity/* or JSON-RPC finalizednot supported18 blocks, 54 sHead can be replaced until solidified
HyperEVMabout 1 sHyperBFTfinalized tag0 to 1 block0 to 1 blockNone by design
HyperCoreno blocks; 0.2 s median latencyHyperBFTuserNonFundingLedgerUpdatesimmediateimmediateNone by design
Polkadot6 sGRANDPAchain_getFinalizedHeadnot applicable4 blocks, about 24 sBest head can be reverted until GRANDPA finalizes it
Arc0.51 sMalachite BFTfinalized tag0 blocks0 blocksNone by design
Stable0.7 sStableBFT on CometBFTfinalized tag0 blocks0 blocksNone by design
Plasma1.0 sPlasmaBFTfinalized tag2 blocks2 blocks, about 2 sNone after commit
Tempo0.54 sSimplexfinalized tag0 blocks0 blocksNone by design
Bitcoinabout 10 minProof of workN confirmations, 6 is standardnot applicable6 blocks, about 60 minProbabilistic; 2-block reorg on 23 Mar 2026
Suiabout 0.4 sMysticetiCheckpointed transaction via gRPC or GraphQLnot applicableunder 1 sNone by design
Bar chart of how far the finalized tag sat behind the head on 5 November 2026: Optimism 25 minutes, Base, Robinhood Chain, Ethereum and Arbitrum One about 15 minutes, Tron 54 seconds, Polkadot 24 seconds, Avalanche 5 seconds, Polygon PoS 4 seconds, Plasma 2 seconds, BNB Chain under a second, HyperEVM 0 to 1 second, Arc, Stable and Tempo 0 seconds.

Three things stand out. The Ethereum family lands between 15 and 25 minutes on the same finalized tag, on L1 and on every rollup in the table, because all of them wait for the same Casper checkpoints; the rollups differ in what safe means and in a few minutes of batching and derivation, not in kind. The BFT chains (Arc, Stable, Tempo, HyperEVM, Avalanche, Plasma, BNB) return the same or nearly the same block for all three tags, so a confirmation counter adds latency and nothing else. And Polygon and Tron, which most deposit systems treat as EVM chains, return null for safe, which will crash a pipeline that assumes the tag always exists.

Ethereum: what safe means now depends on the beacon node

Ethereum's finalized tag is unambiguous. A block is finalized when two consecutive checkpoints have been justified by two thirds of staked ETH, and reverting one would cost at least a third of all stake. The gap behind the head cycles between about 64 and 95 blocks. That is why a single reading showed 73 blocks, and why a fixed "wait 64 blocks" rule is sometimes too early.

The safe tag used to be nearly as predictable: the last justified checkpoint, about one epoch behind the head. That changed in 2026. Lighthouse 8.3.0 (19 October 2026) ships the Fast Confirmation Rule behind a flag, and Lodestar is further along. With it enabled, safe advances every slot, about one slot or 12 seconds behind the head, assuming 75% of stake is honest and attestations arrive on time.

No slashing stands behind a fast-confirmed block. The 41-block reading shows Dwellir's Ethereum pool was still serving the classic checkpoint safe. A different provider, or the same provider after a client upgrade, may return a height 40 blocks newer under the same tag.

For a deposit pipeline that means two rules. Use safe for trading credit only if your risk team accepts that its meaning is provider-configured, and measure the lag yourself. Use finalized for anything you cannot reverse. The safe block and Fast Confirmation explainer covers the mechanism, and the FastConfirm rollout checklist shows how to verify what your endpoint returns.

OP Stack and Arbitrum: when finalized waits for Ethereum

On Base, Optimism, Arbitrum One and Robinhood Chain the sequencer orders transactions in under a second, but the chain is only as final as its data on Ethereum. That gives three levels, which all four chains expose through the same tags, with one difference in what safe means:

LevelTagWhat it meansMeasured on 5 Nov 2026
Sequencer confirmedlatestThe sequencer has included the transaction and promised the orderOne block time, 0.1 to 2 s, behind real time
Batch postedsafeOP Stack: the batch is in an Ethereum block and the node has derived it. Arbitrum: the Ethereum block holding the batch is itself safe. Either way only an Ethereum reorg can undo itBase 27 s, Optimism 3 min, Arbitrum 8.6 min, Robinhood 8.7 min
L1 finalizedfinalizedThe batch is in a finalized Ethereum blockBase 15 min, Optimism 25 min, Arbitrum 14.6 min, Robinhood 14.7 min

The readings sit close to Ethereum's own 15 minutes because that is what every rollup waits for. An OP Stack block is final when the Ethereum block holding its batch is final, so the lag depends on how long the batch waited to be posted, how long Ethereum took to finalize it, and how far behind the node's derivation runs. Optimism's docs give 15 to 30 minutes as typical and 12 hours, the sequencing window, as the worst case; Arbitrum's equivalent is the 24-hour window after which a delayed-inbox message can be force-included. Circle's CCTP documentation puts the standard wait at about 65 Ethereum blocks after the batch posts.

All four rollup readings sit at or just under the low end of that range, and the ceiling is what matters for policy: a batch can legally wait up to 12 hours, so you cannot promise a rollup customer a settlement time from one reading. Measure the lag on your own endpoint over a day before you write a number into a help page.

Base changed shape the day of the reading. Its Denim upgrade activated on mainnet at 18:00 UTC on 5 November 2026 and replaced Flashblocks and the pending tag with canonical blocks every 200 ms, which is why Base's safe lag is 137 blocks but only 27 seconds. A deposit now appears in latest within about a fifth of a second, as sequencer-confirmed only, never as evidence for credit. A pipeline that still reads pending needs the Base Denim migration guide; the Flashblocks guide documents the state table Denim retired.

Arbitrum's documentation gives exchanges five rules that apply to every rollup here: settle deposits at finalized, with safe for revocable trading credit as your own risk call; do not use fixed block counts; detect reorgs by checking parentHash continuity; never rewind below finalized; and do not index against the sequencer's fast feed. Robinhood Chain inherits all of this as an Arbitrum Orbit chain, and its measured 0.1-second block time makes any block-count rule meaningless. Its safe and finalized lag in minutes matched Arbitrum One's almost exactly.

Chains where finality is a few blocks away

On the BFT and fast-finality chains, the three tags collapse. Arc, Stable and Tempo returned identical numbers for latest, safe and finalized, and HyperEVM was within one block. Plasma's finalized was 2 blocks behind, Polygon's 2, BNB Chain's 1 and Avalanche's 6 on Dwellir's pool. The deposit rule is the same on all of them: one receipt whose block number is at or below finalized is settled.

The chain-specific details:

  • Polygon PoS finalizes through Heimdall v2 milestones, live since July 2025, in 2 to 5 seconds. Before milestones it suffered a 157-block reorg on 22 February 2023, which is why older deposit systems still wait 128 or 256 blocks. That wait is now pure latency. safe returns null; use finalized.
  • BNB Smart Chain documents finality of about 2 seconds under BEP-126 after the Maxwell upgrade, and the endpoint reading showed finalized one block behind the head. BNB Chain tells exchanges to use finalized. If fast finality stalls, the chain falls back to probabilistic finality, so your pipeline should alert when the finalized height stops advancing.
  • Avalanche C-Chain is final on acceptance, so the 6-block gap in the reading, about 5 seconds, is not a settlement window. It is most likely which node in the pool answered each of the three reads, the same read artefact that puts HyperEVM at 0 to 1 block. Treat finalized as the signal and ignore the count.
  • Hyperliquid settles HyperCore and HyperEVM in the same HyperBFT consensus, with a median end-to-end latency of 0.2 seconds. HyperEVM deposits use standard eth_* calls. HyperCore deposits (USDC bridged in, spot transfers, internal sends) show up in the /info endpoint's userNonFundingLedgerUpdates, and the same name is a WebSocket channel. The HyperEVM developer guide covers how the two sides fit together.
  • Polkadot separates block production (BABE, 6-second slots) from finality (GRANDPA). Credit on chain_getFinalizedHead, or subscribe to chain_subscribeFinalizedHeads, never on the best head. The reading had finality 4 blocks behind, about 24 seconds.
  • Arc, Stable, Plasma and Tempo are the new stablecoin settlement chains, and all four run BFT consensus with a permissioned or small validator set. Tempo's docs tell you to query eth_getBlockByNumber("finalized"). The settlement guarantee rests on more than two thirds of a named validator set staying honest, rather than on elapsed time or burned stake. Handle that with per-chain deposit limits. A confirmation count the protocol does not need adds nothing.

Tron: use the solidity endpoints

Tron produces a block every 3 seconds from 27 elected Super Representatives. A block is solidified once 19 of the 27 producers have produced a block at or after it, its own producer included, which is Tron's SOLIDIFIED_THRESHOLD of 70% and why the reading below shows 18 blocks rather than 19, and the solidified height never rolls back. Tron's documentation tells you to read confirmation state from a solidity node, which Dwellir exposes as the walletsolidity/* HTTP paths next to the wallet/* head paths:

Bash
# Head block, can still be replaced
curl -sS -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getnowblock \
  -H 'content-type: application/json' -d '{}'

# Latest solidified block, cannot roll back
curl -sS -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/walletsolidity/getnowblock \
  -H 'content-type: application/json' -d '{}'

At the time of reading the head was block 87,744,961 and the solidified block was 87,744,943, 18 blocks and 54 seconds behind. The JSON-RPC finalized tag on the /jsonrpc path returned the same solidified height, so an EVM-style pipeline can use it. safe returns null. OKX's deposit help page, updated 10 September 2026, requires 19 confirmations for TRC-20 USDT, which is the solidification rule expressed as a count. For USDT specifically, the Tron energy and USDT transfer guide explains the fee side of the same flow.

Bitcoin: confirmations are the only signal

Bitcoin has no finality tag. The probability that a transaction is reversed falls with each block built on top of it, and 6 confirmations, about 60 minutes, is the long-standing standard because it drives an attacker with 10% of hashrate below a 0.1% success chance. Kraken's deposit page, updated 22 October 2026, waits 3 confirmations for BTC. The 2-block reorg at height 941,880 on 23 March 2026, involving three large pools, shows that one or two confirmations is a UI signal rather than a settlement one.

The usual answer is value tiers: credit small deposits at 1 to 3 confirmations and large ones at 6 or more, with thresholds tied to what a reversal would cost you rather than to a fixed number.

What Circle and the exchanges wait for

Few exchanges publish confirmation requirements; most show them only inside the deposit screen. Two public sources work as a benchmark. Circle's CCTP waits for these before attesting a USDC transfer, and its "standard" column is the one to read as settled:

ChainCCTP standard finalityAverage timeCCTP fast finality
Ethereumabout 65 blocks15 to 19 min2 blocks, about 20 s
Arbitrum, Base, OP Mainnetabout 65 ETH blocks after the batch15 to 19 min1 block, about 8 s
Polygon PoS2 to 3 blocksabout 8 s
Avalanche1 blockabout 8 s
BNB Smart Chain3 blocksabout 2 s
HyperEVM1 blockabout 5 s
Plasma3 blocksabout 1 s
Arc1 blockabout 0.5 s
Sui1 blockabout 0.5 s

The block counts and times are Circle's published figures, which include its own observation and attestation delay, so they do not reduce to the block times measured above.

OKX publishes two numbers: 32 confirmations for ERC-20 USDT and 19 for TRC-20 USDT. Both line up with protocol boundaries, one Ethereum epoch and Tron's solidification, rather than with round numbers. The pattern to copy is the alignment, not the counts: 32 Ethereum blocks is a justified checkpoint, short of the 64 to 95 blocks finality takes, so read the tags and, if a help page needs a count, derive it from the boundary you actually wait for.

A deposit pipeline that survives a reorg

The signals differ per chain. The pipeline around them does not. Six steps cover every EVM chain in the table. Tron fits the same path through its /jsonrpc endpoint. On Polkadot, Sui, HyperCore and Bitcoin the shape holds but the signals change: chain_subscribeFinalizedHeads, checkpoints, ledger updates that are final on arrival, and block height with hash in place of the tags, and the chain's own canonical-hash check in place of removed: true and eth_getLogs.

1. Watch heads and logs over WebSocket. Subscribe to newHeads for the chain tip and to logs filtered to your deposit addresses or to the ERC-20 Transfer topic. Polling eth_getBlockByNumber every block works on slow chains and gets expensive on 0.1-second ones. The WebSockets guide covers subscription types and limits.

2. Record every observation with its ancestry. Key deposits on (chain_id, tx_hash, log_index) and store block_number, block_hash and parent_hash for every block you process. Before processing block N, check that its parentHash equals the hash you stored for N-1. A mismatch is a reorg, and the stored hashes tell you how deep.

3. Promote state by comparing block numbers, not by counting. A transaction has no confirmation status of its own. Once per new head, read safe and finalized and promote every pending deposit whose block number is at or below them, after checking that the block at the deposit's height still carries the hash you stored, since a reorg can replace the block and let the height finalize anyway:

TypeScript
type Tag = "latest" | "safe" | "finalized";
type Block = { number: string; hash: string };

async function getBlock(rpc: string, at: Tag | number): Promise<Block | null> {
  const res = await fetch(rpc, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      jsonrpc: "2.0", id: 1, method: "eth_getBlockByNumber",
      params: [typeof at === "number" ? "0x" + at.toString(16) : at, false],
    }),
  });
  const { result } = await res.json();
  return result ?? null; // null on Polygon and Tron for "safe"
}

const height = (b: Block | null) => (b ? parseInt(b.number, 16) : null);

export async function depositState(rpc: string, deposit: { block: number; blockHash: string }) {
  const [safe, finalized, canonical] = await Promise.all([
    getBlock(rpc, "safe"),
    getBlock(rpc, "finalized"),
    getBlock(rpc, deposit.block),
  ]);
  // A reorg can replace the deposit's block and let the height finalize anyway.
  // A null here is a lagging node or an RPC error, not a reorg: stay at "seen" and retry.
  if (!canonical) return "seen";
  if (canonical.hash !== deposit.blockHash) return "reverted";
  const f = height(finalized), s = height(safe);
  if (f !== null && deposit.block <= f) return "settled";
  if (s !== null && deposit.block <= s) return "credited";
  return "seen";
}

Chains without a safe tag skip straight from seen to settled, which is the right behaviour on Polygon and Tron. On chains where all three tags are equal, a deposit is settled on its first evaluation.

4. Treat removed: true as a rollback, not a delete. After a reorg, log subscriptions re-send the logs of orphaned blocks with removed: true, then emit the new branch's logs. Mark the deposit reverted, keep the record, and let the new branch's log re-credit it if the chain included the transaction again. The same transaction can arrive three times; idempotent writes keyed as in step 2 make that harmless.

5. On reconnect, resubscribe first, then back-fill with an overlap. Persist the last processed block durably, including its hash. After a disconnect, open the new subscriptions before recovery so nothing falls between them. Then run eth_getLogs from a few blocks before your last durable block to the current head, dedupe against step 2, and check hash continuity across the gap, never rewinding below finalized. The eth_subscribe reconnect guide covers backoff, buffering and what the recovery costs per provider.

6. Alert when finality stops moving. On every chain, store the finalized height per poll and alert if it has not advanced within a few multiples of the expected lag. A stalled finalized height tells you about a BNB fast-finality fallback, a Polygon milestone incident like the one on 10 September 2025, or a provider node that has fallen behind, before it reaches your ledger.

Six cards summarising the pipeline: watch heads and logs over WebSocket, record every observation with its block hash and parent hash, promote deposits by comparing block numbers to the safe and finalized tags, treat removed true logs as rollbacks, resubscribe before back-filling with eth_getLogs, and alert when the finalized height stops advancing.

Running this across chains on one provider

The pipeline above makes one safe and one finalized read per new head on every chain, plus a log subscription and occasional eth_getLogs back-fills. On a compute-unit provider each method carries a different weight, and the back-fills are the expensive part. Dwellir bills one credit per response on every method, including eth_getLogs, so a reorg-safe pipeline costs its request count and nothing else.

One Dwellir account serves every chain in the table: Ethereum, Base, Optimism, Arbitrum, Robinhood Chain, Polygon, BNB Chain, Avalanche, Tron with both wallet and walletsolidity paths, Hyperliquid on both sides, Polkadot, Arc, Stable, Plasma, Tempo, Bitcoin and Sui, with WebSocket endpoints on the EVM and Substrate chains. The public RPC endpoints hub lists each URL and chain ID. The multi-network wallet backend guide covers the other half of a custody stack, including checking eth_chainId before you trust any endpoint's answer. That check matters as much for a deposit pipeline as for a wallet.

If you are building or re-platforming exchange deposit infrastructure and want to talk through confirmation policy or dedicated capacity per chain, contact the Dwellir team. To start measuring the lags on your own chains, create an API key and run the three-tag read above.

Frequently asked questions

How many confirmations does an exchange need for an Ethereum deposit?

Stop counting blocks and read the finalized tag. On 5 November 2026 Dwellir's Ethereum endpoint reported finalized 73 blocks behind the head, about 15 minutes, and that gap swings between roughly 64 and 95 blocks within every finality cycle. OKX waits 32 confirmations for ERC-20 USDT, one epoch, and Circle's CCTP waits about 65 blocks, two epochs. Both are protocol boundaries expressed as counts, not round numbers.

Is the safe block tag enough to credit a deposit?

Only for credit you can take back, such as trading balance with withdrawals held. What safe means now depends on the provider's beacon node. With the classic rule it trails the head by about an epoch, 41 blocks in Dwellir's reading. With the Fast Confirmation Rule enabled in Lighthouse 8.3 or Lodestar it advances every slot, with no slashing behind it. Withdrawals and payouts should wait for finalized on every chain.

Why is finalized on Base and Optimism minutes behind the head?

Because an OP Stack chain is only final once the Ethereum block holding its batch is final, and that depends on when the batch was posted, when Ethereum finalized it and when the node derived it. On 5 November 2026 Base's finalized block was 4,458 blocks behind latest, about 15 minutes at Denim's 0.2-second block time, and Optimism's was 762 blocks, about 25 minutes. Optimism's docs give 15 to 30 minutes as typical and 12 hours, the sequencing window, as the worst case, so measure your own endpoint before promising a settlement time. safe, which means the batch has been posted, is the usual middle ground for crediting.

How do I detect a chain reorg over RPC?

Store the hash and parentHash of every block you process and check that each new block's parentHash equals the hash you stored for the previous height. A mismatch means a reorg. On log subscriptions, logs from orphaned blocks are re-sent with removed set to true. Rewind to the common ancestor, never below finalized, mark the affected deposits as reverted and re-scan.

Do chains with instant finality still need a confirmation count?

No. On Arc, Stable and Tempo the latest, safe and finalized tags returned the same block in Dwellir's readings, and HyperEVM, BNB Chain, Plasma and Polygon PoS were within one to two blocks. One receipt in a finalized block is enough. The trust you are placing is in a validator set rather than in elapsed time, so set deposit limits per chain with that in mind.

Sources

Block tag readings, Tron head and solidified blocks, Polkadot best and finalized heads, and 100-block timing samples were taken from Dwellir's production endpoints between 19:55:53 and 19:56:56 UTC on 5 November 2026. Third-party pages were checked the same day.

Start free.1 response = 1 credit.

100,000 responses a day at 20 per second, on 170+ networks. Upgrade when you need more.