Skip to main content

Overview

Understanding transaction statuses helps you build reliable applications on Paxeer Network. This guide explains the lifecycle and finality of transactions.

Transaction Lifecycle

1

Pending

Transaction is in the mempool, waiting to be included in a block.
const tx = await signer.sendTransaction(txData);
console.log('Transaction hash:', tx.hash);
// Status: Pending
2

Mined

Transaction has been included in a block.
const receipt = await tx.wait(1); // Wait for 1 confirmation
console.log('Block number:', receipt.blockNumber);
// Status: Mined (1 confirmation)
3

Confirmed

Transaction has received multiple block confirmations.
const receipt = await tx.wait(3); // Wait for 3 confirmations
// Status: Confirmed (3 confirmations)
4

Finalized

Transaction is considered final and irreversible.
const receipt = await tx.wait(12); // Wait for 12 confirmations
// Status: Finalized

Checking Transaction Status

Using Transaction Hash

import { ethers } from 'ethers';

const provider = new ethers.JsonRpcProvider('https://public-rpc.paxeer.app/rpc');

async function getTransactionStatus(txHash) {
  // Get transaction data
  const tx = await provider.getTransaction(txHash);
  
  if (!tx) {
    return { status: 'not_found' };
  }
  
  // Get transaction receipt
  const receipt = await provider.getTransactionReceipt(txHash);
  
  if (!receipt) {
    return { 
      status: 'pending',
      nonce: tx.nonce,
    };
  }
  
  // Get current block number
  const currentBlock = await provider.getBlockNumber();
  const confirmations = currentBlock - receipt.blockNumber + 1;
  
  return {
    status: receipt.status === 1 ? 'success' : 'failed',
    blockNumber: receipt.blockNumber,
    confirmations: confirmations,
    gasUsed: receipt.gasUsed.toString(),
    effectiveGasPrice: receipt.gasPrice.toString(),
  };
}

// Usage
const status = await getTransactionStatus('0x...');
console.log('Transaction status:', status);

Finality Levels

Paxeer Network has different finality levels based on block confirmations:
LevelConfirmationsTimeUse Case
Unsafe0ImmediateUI updates only
Safe1-2~4 secondsMost dApps
Confirmed3-11~6-22 secondsImportant operations
Finalized12+~24+ secondsCritical/irreversible actions
For high-value or critical operations, wait for at least 12 confirmations before considering the transaction finalized.

Monitoring Transactions

Real-time Status Updates

useTransactionStatus.ts
import { useState, useEffect } from 'react';
import { usePublicClient, useWaitForTransactionReceipt } from 'wagmi';

export function useTransactionStatus(hash?: `0x${string}`) {
  const [status, setStatus] = useState<'pending' | 'success' | 'failed'>('pending');
  const [confirmations, setConfirmations] = useState(0);
  
  const { data: receipt, isLoading } = useWaitForTransactionReceipt({
    hash,
  });
  
  const client = usePublicClient();

  useEffect(() => {
    if (!receipt || !client) return;

    setStatus(receipt.status === 'success' ? 'success' : 'failed');

    // Update confirmations periodically
    const interval = setInterval(async () => {
      const currentBlock = await client.getBlockNumber();
      const confs = currentBlock - receipt.blockNumber + 1n;
      setConfirmations(Number(confs));
    }, 2000);

    return () => clearInterval(interval);
  }, [receipt, client]);

  return { status, confirmations, receipt, isLoading };
}

Usage in React Component

function TransactionTracker({ txHash }) {
  const { status, confirmations, receipt } = useTransactionStatus(txHash);

  return (
    <div>
      <p>Status: {status}</p>
      <p>Confirmations: {confirmations}</p>
      
      {status === 'success' && confirmations >= 12 && (
        <p className="text-green-600">Transaction Finalized</p>
      )}
      
      {status === 'failed' && (
        <p className="text-red-600">Transaction Failed</p>
      )}
    </div>
  );
}

Transaction Receipt Details

async function getDetailedReceipt(txHash) {
  const receipt = await provider.getTransactionReceipt(txHash);
  
  return {
    // Status
    status: receipt.status, // 1 = success, 0 = failed
    
    // Block information
    blockNumber: receipt.blockNumber,
    blockHash: receipt.blockHash,
    
    // Gas usage
    gasUsed: receipt.gasUsed.toString(),
    gasPrice: receipt.gasPrice.toString(),
    effectiveGasPrice: receipt.gasPrice.toString(),
    
    // Fee calculation
    totalFee: (receipt.gasUsed * receipt.gasPrice).toString(),
    
    // Addresses
    from: receipt.from,
    to: receipt.to,
    contractAddress: receipt.contractAddress, // If contract creation
    
    // Transaction details
    transactionHash: receipt.hash,
    transactionIndex: receipt.index,
    
    // Logs (events)
    logs: receipt.logs,
  };
}

Best Practices

Different use cases need different confirmation levels:
// UI update only - show immediately
const receipt = await tx.wait(0);

// Standard dApp - wait for 1 confirmation
const receipt = await tx.wait(1);

// Financial operation - wait for 3+ confirmations
const receipt = await tx.wait(3);

// Critical operation - wait for finality
const receipt = await tx.wait(12);
Although rare, block reorganizations can happen:
async function waitForSafeConfirmation(txHash) {
  let previousBlockHash = null;
  
  while (true) {
    const receipt = await provider.getTransactionReceipt(txHash);
    
    if (receipt && receipt.confirmations >= 3) {
      const block = await provider.getBlock(receipt.blockNumber);
      
      if (previousBlockHash && block.hash !== previousBlockHash) {
        console.warn('Reorg detected! Waiting more...');
        previousBlockHash = block.hash;
        continue;
      }
      
      if (!previousBlockHash) {
        previousBlockHash = block.hash;
      }
      
      // No reorg detected
      return receipt;
    }
    
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
}
Don’t wait indefinitely:
async function waitWithTimeout(txPromise, timeoutMs = 60000) {
  return Promise.race([
    txPromise,
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error('Transaction timeout')), timeoutMs)
    ),
  ]);
}

// Usage
try {
  const receipt = await waitWithTimeout(tx.wait());
  console.log('Success:', receipt.hash);
} catch (error) {
  if (error.message === 'Transaction timeout') {
    console.log('Transaction taking too long, check status manually');
  }
}

Event Monitoring

Watch for transaction events in real-time:
// Listen for pending transactions
provider.on('pending', (txHash) => {
  console.log('New pending transaction:', txHash);
});

// Listen for mined blocks
provider.on('block', async (blockNumber) => {
  console.log('New block mined:', blockNumber);
  
  const block = await provider.getBlock(blockNumber);
  console.log('Transactions in block:', block.transactions.length);
});

// Clean up listeners
provider.removeAllListeners('pending');
provider.removeAllListeners('block');

Resources

Next Steps