Docs

eth_getTransactionCount - Celo RPC Method

Get the number of transactions sent from an address (nonce) on Celo. Essential for nonce management, transaction signing, and detecting stuck transactions.

Returns the number of transactions sent from an address on Celo, commonly known as the nonce. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

Why Celo? Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

When to Use This Method

eth_getTransactionCount is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

  • Transaction Signing — Get the correct nonce before building and signing a new transaction on Celo
  • Nonce Gap Detection — Compare latest and pending nonces to identify stuck or dropped transactions in the mempool
  • Account Activity Analysis — Track the total number of outgoing transactions from any address on mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
  • Batch Transaction Sequencing — Assign sequential nonces when submitting multiple transactions from the same address

Code Examples

Common Use Cases

1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Celo:

JavaScript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}

2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

JavaScript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x471EcE3750Da237f93B8E339c536989b8978a438');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}

3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

JavaScript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);

Error Handling

Common errors and solutions:

Error CodeDescriptionSolution
-32602Invalid paramsVerify the address is a valid 20-byte hex string and the block parameter is valid
-32603Internal errorRetry with exponential backoff
-32000Block not foundThe requested block may be pruned — use latest or pending
-32005Rate limit exceededImplement caching for nonce lookups
JavaScript
async function safeGetNonce(provider, address, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await provider.getTransactionCount(address, 'pending');
    } catch (error) {
      if (error.code === -32005) {
        await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
        continue;
      }
      if (i === maxRetries - 1) throw error;
      await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
    }
  }
}