1. Working with Finality

1.1 Three Presets

PresetUse-caseHow to code itTypical delay
FASTUI refresh, analyticsprovider.getBlock("latest")~1 s
SAFEMost user actionsawait tx.wait(7)~7-8 s
FINALTreasury, bridge, NFT mintprovider.getBlock("finalized")~15-20 s
Golden rule: a latest block is optimistic; a finalized block is forever.

1.2 Decision matrix

  • FAST (0 confirms, ~1 s) – Great for real-time UI updates and analytics. Roll back if a reorg shows up.
  • SAFE (~7 authored blocks, ~7-8 s) – Default for ordinary user actions (token transfers, approvals, simple swaps). Rarely reorgs yet still snappy.
  • FINAL (relay-chain finalized, ~15-20 s) – Use for anything that must be absolutely irreversible: treasury moves, bridge deposits, high-value NFT mints, etc.

2. Quick‑Start Checklist

  1. RPC & chain‑ID
    • Mainnet RPC https://quicknode1.peaq.xyz ID 3338
    • Testnet RPC https://peaq‑agung.api.onfinality.io/public ID 9990
  2. Pin EVM version to london
    solidity: {
      version: "0.8.21",
      settings: { evmVersion: "london" }
    }
    
  3. Estimate gas then add a ×2 buffer
    const gas = await provider.estimateGas(tx);
    tx.gasLimit = gas.mul(2);
    
  4. Deploy as usual npx hardhat run scripts/deploy.js --network peaq

3. Handling Reorgs & Using Finalized Blocks

What is a Reorg? When two blocks land at almost the same time the chain briefly forks; the shorter fork is later dropped, so its last few blocks - and any transactions inside - vanish and must be re-included. Why does using Finalized block help in that case? Extra votes lock a block in permanently; once finalized, that block (and all earlier ones) can never be dropped, so reorgs can only touch the unfixed tip of the chain.
// Latest for optimistic UI
const latest = await provider.getBlock("latest");

// Finalized for deterministic reads
const finalized = await provider.send(
  "eth_getBlockByNumber",
  ["finalized", false]
);
When monitoring blocks:
let lastHash;
provider.on("block", async (n) => {
  const blk = await provider.getBlock(n);
  if (lastHash && blk.parentHash !== lastHash) {
    // reorg detected – revert optimistic state
  }
  lastHash = blk.hash;
});

4. peaq‑Specific Nuances

TopicWhat’s differentWhat to do
block.difficulty / prevrandaoAlways 0Use Chainlink VRF or for low stakesrandomnessCollectiveFlip queried at finalized height.
Gas scheduleMostly London‑equivalent; storage a bit pricierAlways run eth_estimateGas, never hard‑code.
Account abstraction (ERC‑4337)Not yet liveWait for roadmap.
Deep tracesdebug_* RPCs only on tracing‑enabled nodesRun a node with --ethapi=debug,trace,txpool & --features evm-tracing.

5. Tracing & Debugging

Enable in node startup:
./peaq-node \
  --ethapi=debug,trace,txpool \
  --rpc-methods=Unsafe \
  --state-pruning archive \
  --wasm-runtime-overrides=parachain-peaq \
  --features evm-tracing
Then:
curl -X POST -H "Content-Type: application/json" -d \
 '{"jsonrpc":"2.0","id":1,"method":"debug_traceTransaction","params":["<txHash>",{"tracer":"callTracer"}]}' \
 https://evm.yourevmnode.xyz

6. Frequently Asked Questions

How many confirmations are really “safe”? Waiting for the finalized tag is bullet‑proof; seven authored blocks (≈ 7‑8 s) is the community standard for ordinary user actions. Can a finalized block revert? Only if ≥ ⅓ of stake is slashed — an economically irrational scenario. My tx failed – how do I debug? Simulate with provider.call(tx) first; for deep dives use debug_traceTransaction on a tracing node.

7. Resources

Happy building – and welcome to peaq!