Ethereum

Ethereum

Block Confirmations

"Is this transaction final?" is the question every exchange, bridge, and payment flow has to answer before it moves money. The instinct carried over from Bitcoin is to count confirmations — how many blocks have piled on top. Post-Merge Ethereum gives you something stronger and more honest: Casper FFG finality. Validators justify and then finalize checkpoints, and once a block is finalized it cannot be reverted unless a third of all staked ETH is slashed. That's a cryptoeconomic guarantee, not a probability that improves block by block.

This guide shows how to verify transactions safely on chain 1 the way the protocol actually works: reading the finalized and safe block tags rather than tallying raw confirmations, sizing your safety bar to the value at risk, and handling the short head reorgs that can still invalidate a transaction before it finalizes. By the end you'll know which tag to trust for which kind of action and how to wire it into a verification flow.

Understanding Confirmations

  • What a confirmation is. A confirmation is one block built on top of the block containing your transaction. You count it as currentBlock - txBlockNumber. Each new 12-second slot adds one. But on Ethereum that count is only a proxy for the real thing — finality, which the consensus layer tracks explicitly via the safe and finalized tags.
  • Why it matters. Until a transaction's block is at least justified, the head can reorg and your transaction can be reordered or dropped. Acting on an unconfirmed inclusion is how double-spends and inconsistent state happen. Finality is the line past which that risk disappears.
  • What to wait for, by value. For small or reversible actions, the safe tag (a justified checkpoint) is usually enough. For settlement, withdrawals, or anything you can't claw back, wait for finalized — reached after about two epochs (~12.8 minutes), and irreversible short of a third of staked ETH being slashed. The higher the value, the stronger the guarantee you should demand.
  • Mainnet vs testnets. The same Casper FFG mechanism runs on Sepolia (chainId 11155111) and Holesky (17000), so the finalized/safe tags work identically there. The difference is economic weight: testnet ETH has no real value, so a finalized testnet block carries none of the slashing-backed security of a finalized mainnet block. Test the logic on Sepolia, but don't read its finality as equivalent to chain 1's.

Implementation Examples

// Check number of confirmations
const getConfirmations = async (txHash) => {
const tx = await web3.eth.getTransaction(txHash);
const currentBlock = await web3.eth.getBlockNumber();
return tx.blockNumber ? currentBlock - tx.blockNumber : 0;
};
// Wait for specific number of confirmations
const waitForConfirmations = async (txHash, confirmations = 6) => {
while ((await getConfirmations(txHash)) < confirmations) {
await new Promise((resolve) => setTimeout(resolve, 1000));
}
return true;
};

Security Considerations

  • Set thresholds by what's at stake. Tie the bar to consequence, not a fixed number: a UI status update can trust latest, a moderate transfer can trust safe, and an irreversible payout should wait for finalized. The cleanest rule is to read the block by tag and confirm your transaction's block number is at or below the finalized height before you commit.
  • Handle a reorg that undoes a "confirmed" transaction. Before finality, a transaction you counted as confirmed can be reorged out. When you detect that the block holding it is no longer canonical (its hash changed at that height), mark the transaction unconfirmed again, roll back any state you derived from it, and re-check whether it landed in the new canonical chain or needs resubmitting.
  • Account for Ethereum-specific factors. Finality timing depends on epoch progression, not block count, so under poor participation the gap between latest and finalized can widen beyond the usual ~2 epochs. Network congestion and a high base fee can also delay your transaction's inclusion in the first place. Watch the finalized tag itself rather than assuming a fixed minute count.
  • Monitor progress in production. Subscribe to newHeads over the WebSocket endpoint and, on each block, recompute how far your pending transaction is from the current finalized height. Surface that distance to users as a progress indicator, and alert internally if the finalized tag stops advancing — that stall is itself a signal worth catching.

See also

Ready to call this in production?

Free tier covers personal projects. Pay-as-you-go scales without a card.