learn.sol
Week 4 • Send Confirm Retry And Lifetime Management

Send, Confirm, Retry & Lifetime Management

Handle transaction delivery robustly with explicit confirmation strategy and retry policy.

Step 1: 0-to-1 Theory

Primitives

  • send: publish signed bytes to cluster
  • confirm: wait for chain commitment outcome
  • retry: controlled rebuild/resend policy

Mental Model

Sending a transaction is like dropping a letter into a mailbox. Confirmation is waiting for a receipt.

On Solana, confirmation depends on:

  • which commitment level you choose (processed, confirmed, finalized)
  • whether your transaction reached the leader and propagated
  • whether it expired (blockhash lifetime)

Invariants

  1. "Sent" is not "Confirmed".
  2. Retrying stale signed bytes is invalid.
  3. User rejection is non-retryable.

Quick Checks

  1. Which failures are retryable?
  2. Why should retries be policy-driven, not ad hoc?

Step 2: Real-World Implementation (Code Solution)

Create scripts/send-confirm.ts:

import {
  appendTransactionMessageInstructions,
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  createTransactionMessage,
  generateKeyPairSigner,
  getSignatureFromTransaction,
  lamports,
  pipe,
  sendAndConfirmTransactionFactory,
  setTransactionMessageFeePayerSigner,
  setTransactionMessageLifetimeUsingBlockhash,
  signTransactionMessageWithSigners,
} from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";

// Use local validator for predictable learning and quick iteration.
const RPC_URL = "http://127.0.0.1:8899";

async function buildAndSign() {
  const rpc = createSolanaRpc(RPC_URL);
  // Generate signers so the script is self-contained.
  const sender = await generateKeyPairSigner();
  const recipient = await generateKeyPairSigner();
  // Blockhash is the transaction lifetime. You must refresh it for retries.
  const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

  const ix = getTransferSolInstruction({
    source: sender,
    destination: recipient.address,
    amount: lamports(1_000_000n),
  });

  const msg = pipe(
    createTransactionMessage({ version: 0 }),
    (tx) => setTransactionMessageFeePayerSigner(sender, tx),
    (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
    (tx) => appendTransactionMessageInstructions([ix], tx),
  );

  return signTransactionMessageWithSigners(msg);
}

async function main() {
  const rpc = createSolanaRpc(RPC_URL);
  // Subscriptions typically use WebSocket. For local validator, ws is the same host/port.
  const subs = createSolanaRpcSubscriptions(RPC_URL.replace("http", "ws"));
  // This helper sends bytes and waits for confirmation.
  const sendAndConfirm = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions: subs });

  for (let attempt = 1; attempt <= 2; attempt++) {
    try {
      const signed = await buildAndSign();
      await sendAndConfirm(signed, { commitment: "confirmed" });
      console.log("confirmed", getSignatureFromTransaction(signed));
      return;
    } catch (e: any) {
      const msg = String(e?.message ?? e);
      // Keep a simple retry policy for beginners:
      // retry only on lifetime/timeouts, and rebuild with a fresh blockhash.
      const retryable = msg.includes("Blockhash") || msg.includes("timeout");
      if (!retryable || attempt === 2) throw e;
      console.log("retrying with fresh blockhash...");
    }
  }
}

main().catch((e) => {
  console.error("send/confirm failed", e);
  process.exit(1);
});

Run:

pnpm tsx scripts/send-confirm.ts

Expected result:

  • script prints confirmed signature or clear failure reason.

Step 3: Mastery Test

  • Easy: why do we rebuild transaction on retry?
  • Medium: what should UI show between send and confirm?
  • Hard: how would you avoid duplicate user actions during confirm wait?

Sources

Solana Assistant

AI-powered documentation helper

Welcome to Solana Assistant

Ask specific questions about Solana development:

Ask specific questions for better results400px
    Send, Confirm, Retry & Lifetime Management | learn.sol