Docs

chain_getFinalizedHead - Bridge Hub RPC Method

Get the finalized block hash on Bridge Hub. Essential for confirmed state queries, exchange integrations, and applications requiring irreversible finality on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum.

Returns the hash of the last finalized block on Bridge Hub. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

Why Bridge Hub? Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

When to Use This Method

chain_getFinalizedHead is critical for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

  • Exchange Deposits — Only credit user funds after the block has been finalized on Bridge Hub
  • Transaction Confirmation — Verify transactions have achieved irreversible finality for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
  • Safe Checkpoints — Use finalized blocks as safe anchors for indexing and state queries
  • Bridge Operations — Confirm source-chain finality before executing cross-chain transfers

Code Examples

Common Use Cases

1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Bridge Hub:

JavaScript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}

2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

JavaScript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}

3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

JavaScript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}

Error Handling

Error CodeDescriptionSolution
-32603Internal errorNode may be syncing or GRANDPA not running — retry with backoff
-32601Method not foundVerify the node supports this RPC method
-32005Rate limit exceededImplement client-side rate limiting