solana_kit_transaction_confirmation

pub package docs website CI coverage

Transaction confirmation tracking for the Solana Kit Dart SDK -- provides multiple strategies to confirm or detect expiry of Solana transactions.

This is the Dart port of @solana/transaction-confirmation from the Solana TypeScript SDK.

Installation

Install the package directly:

dart pub add solana_kit_transaction_confirmation

If your app uses several Solana Kit packages together, you can also depend on the umbrella package instead:

dart pub add solana_kit

Inside this monorepo, Dart workspace resolution uses the local package automatically.

Documentation

For architecture notes, getting-started guides, and cross-package examples, start with the workspace docs site and then drill down into the package README and API reference.

Usage

Strategy overview

This package provides five confirmation strategies that can be composed together:

  1. Recent Signature Confirmation -- Watches for a signature to reach a target commitment level.
  2. Block Height Exceedence -- Detects when the network has progressed past the last valid block height for a transaction.
  3. Nonce Invalidation -- Detects when a durable nonce has been advanced, meaning the transaction has expired.
  4. Timeout -- A simple timeout-based fallback.
  5. Strategy Racing -- Races multiple strategies against each other, resolving with the first to complete.

In addition to the low-level strategy primitives, the package now includes additive polling helpers for the common app flow of sending a signed transaction and waiting for confirmation without manually wiring each strategy yourself.

Sending and confirming a signed transaction

import 'package:solana_kit_rpc/solana_kit_rpc.dart';
import 'package:solana_kit_transaction_confirmation/solana_kit_transaction_confirmation.dart';
import 'package:solana_kit_transactions/solana_kit_transactions.dart';

Future<void> submitSignedTransaction(Transaction signedTransaction) async {
  final rpc = createSolanaRpc(url: 'https://api.devnet.solana.com');

  final signature = await sendAndConfirmTransaction(
    rpc: rpc,
    transaction: signedTransaction,
  );

  print('Confirmed signature: ${signature.value}');
}

Confirming an already-sent transaction

import 'package:solana_kit_keys/solana_kit_keys.dart';
import 'package:solana_kit_rpc/solana_kit_rpc.dart';
import 'package:solana_kit_transaction_confirmation/solana_kit_transaction_confirmation.dart';
import 'package:solana_kit_transactions/solana_kit_transactions.dart';

Future<void> confirmExistingSubmission({
  required Signature signature,
  required Transaction transaction,
}) async {
  final rpc = createSolanaRpc(url: 'https://api.devnet.solana.com');

  await waitForTransactionConfirmation(
    rpc: rpc,
    signature: signature,
    transaction: transaction,
  );
}

Confirming a recent transaction (block height strategy)

The recommended approach for confirming blockhash-based transactions is to race the signature confirmation against block height exceedence.

import 'package:solana_kit_rpc_subscriptions_channel_websocket/solana_kit_rpc_subscriptions_channel_websocket.dart';
import 'package:solana_kit_rpc_types/solana_kit_rpc_types.dart';
import 'package:solana_kit_transaction_confirmation/solana_kit_transaction_confirmation.dart';

Future<void> confirmTransaction(String signature) async {
  final controller = AbortController();

  // Create the signature confirmation factory.
  // This watches the RPC for signature status updates.
  final getRecentSignatureConfirmation =
      createRecentSignatureConfirmationPromiseFactory(
        RecentSignatureConfirmationConfig(
          getSignatureStatuses: (sigs, {required abortSignal}) async {
            // Call your RPC's getSignatureStatuses method.
            // Return a list of SignatureStatus? (null if not found).
            return [];
          },
          onSignatureNotification: (sig, {
            required abortSignal,
            required commitment,
            required onNotification,
          }) async {
            // Subscribe to signatureNotifications via WebSocket.
            // Call onNotification(err: null) when the signature is confirmed.
          },
        ),
      );

  // Create the block height exceedence factory.
  // This monitors the network's block height and rejects when it exceeds
  // the transaction's lastValidBlockHeight.
  final getBlockHeightExceedence =
      createBlockHeightExceedencePromiseFactory(
        BlockHeightExceedenceConfig(
          getEpochInfo: ({required abortSignal, commitment}) async {
            // Call your RPC's getEpochInfo method.
            return EpochInfo(
              absoluteSlot: BigInt.from(100),
              blockHeight: BigInt.from(90),
            );
          },
          onSlotNotification: ({
            required abortSignal,
            required onNotification,
          }) async {
            // Subscribe to slotNotifications via WebSocket.
          },
        ),
      );

  // Wait for confirmation, racing against block height expiry.
  await waitForRecentTransactionConfirmation(
    abortSignal: controller.signal,
    commitment: Commitment.confirmed,
    getBlockHeightExceedencePromise: getBlockHeightExceedence,
    getRecentSignatureConfirmationPromise: getRecentSignatureConfirmation,
    lastValidBlockHeight: BigInt.from(200),
    signature: signature,
  );

  print('Transaction confirmed!');
}

Confirming a durable nonce transaction

For transactions using durable nonces, race signature confirmation against nonce invalidation.

import 'package:solana_kit_rpc_subscriptions_channel_websocket/solana_kit_rpc_subscriptions_channel_websocket.dart';
import 'package:solana_kit_rpc_types/solana_kit_rpc_types.dart';
import 'package:solana_kit_transaction_confirmation/solana_kit_transaction_confirmation.dart';

Future<void> confirmNonceTransaction({
  required String signature,
  required String nonceAccountAddress,
  required String nonceValue,
  required GetRecentSignatureConfirmationPromise getRecentSignatureConfirmation,
}) async {
  final controller = AbortController();

  // Create the nonce invalidation factory.
  // This monitors a nonce account and rejects when its value changes,
  // indicating the transaction has expired.
  final getNonceInvalidation =
      createNonceInvalidationPromiseFactory(
        NonceInvalidationConfig(
          getNonceAccount: (address, {
            required abortSignal,
            required commitment,
          }) async {
            // Fetch and parse the nonce account data.
            return NonceAccountInfo(nonceValue: 'current-nonce-value');
          },
          onAccountNotification: (address, {
            required abortSignal,
            required commitment,
            required onNotification,
          }) async {
            // Subscribe to accountNotifications for the nonce account.
          },
        ),
      );

  // Wait for confirmation, racing against nonce invalidation.
  await waitForDurableNonceTransactionConfirmation(
    abortSignal: controller.signal,
    commitment: Commitment.confirmed,
    getNonceInvalidationPromise: getNonceInvalidation,
    getRecentSignatureConfirmationPromise: getRecentSignatureConfirmation,
    nonceAccountAddress: nonceAccountAddress,
    nonceValue: nonceValue,
    signature: signature,
  );

  print('Durable nonce transaction confirmed!');
}

Comparing commitment levels

The commitmentComparator function (re-exported from solana_kit_rpc_types) enables comparing commitment levels.

import 'package:solana_kit_rpc_types/solana_kit_rpc_types.dart';
import 'package:solana_kit_transaction_confirmation/solana_kit_transaction_confirmation.dart';

void main() {
  // commitmentComparator returns:
  //   < 0 if c1 is lower than c2
  //   0 if c1 equals c2
  //   > 0 if c1 is higher than c2

  print(commitmentComparator(Commitment.finalized, Commitment.confirmed) > 0);
  // true -- finalized is higher than confirmed

  print(commitmentComparator(Commitment.processed, Commitment.confirmed) < 0);
  // true -- processed is lower than confirmed

  print(commitmentComparator(Commitment.confirmed, Commitment.confirmed) == 0);
  // true -- same level
}

Racing custom strategies

The raceStrategies function races a signature confirmation promise against a list of other strategy futures. The first to resolve or reject determines the outcome.

import 'package:solana_kit_rpc_subscriptions_channel_websocket/solana_kit_rpc_subscriptions_channel_websocket.dart';
import 'package:solana_kit_rpc_types/solana_kit_rpc_types.dart';
import 'package:solana_kit_transaction_confirmation/solana_kit_transaction_confirmation.dart';

Future<void> confirmWithCustomStrategy({
  required String signature,
  required GetRecentSignatureConfirmationPromise confirmationFactory,
}) async {
  final controller = AbortController();

  // Race signature confirmation against both a timeout and a custom strategy.
  await raceStrategies(
    signature,
    BaseTransactionConfirmationStrategyConfig(
      abortSignal: controller.signal,
      commitment: Commitment.confirmed,
      getRecentSignatureConfirmationPromise: confirmationFactory,
    ),
    ({required AbortSignal abortSignal}) => [
      getTimeoutPromise(
        abortSignal: abortSignal,
        commitment: Commitment.confirmed,
      ),
    ],
  );

  print('Transaction confirmed before timeout!');
}

Timeout strategy

The getTimeoutPromise function provides a simple timeout-based fallback. It uses 30 seconds for processed commitment and 60 seconds otherwise.

import 'package:solana_kit_rpc_subscriptions_channel_websocket/solana_kit_rpc_subscriptions_channel_websocket.dart';
import 'package:solana_kit_rpc_types/solana_kit_rpc_types.dart';
import 'package:solana_kit_transaction_confirmation/solana_kit_transaction_confirmation.dart';

Future<void> main() async {
  final controller = AbortController();

  try {
    await getTimeoutPromise(
      abortSignal: controller.signal,
      commitment: Commitment.confirmed,
    );
  } on TimeoutException {
    print('Transaction timed out after 60 seconds');
  }
}

API Reference

Waiter functions

Function Description
waitForTransactionConfirmation({...}) Polling-based helper that confirms a transaction using its lifetime metadata.
waitForRecentTransactionConfirmation({...}) Races signature confirmation against block height exceedence.
waitForDurableNonceTransactionConfirmation({...}) Races signature confirmation against nonce invalidation.
waitForRecentTransactionConfirmationUntilTimeout({...}) (Deprecated) Races signature confirmation against a timeout.
sendAndConfirmTransaction({...}) Sends a fully signed transaction over RPC, then waits for confirmation.

Factory functions

Function Description
createRecentSignatureConfirmationPromiseFactory(config) Creates a function that resolves when a signature reaches a target commitment.
createBlockHeightExceedencePromiseFactory(config) Creates a function that rejects when block height exceeds the last valid height.
createNonceInvalidationPromiseFactory(config) Creates a function that rejects when a durable nonce has been advanced.

Strategy functions

Function Description
raceStrategies(signature, config, getStrategies) Races a signature confirmation against specific strategies.
getTimeoutPromise({abortSignal, commitment}) Returns a future that rejects after 30s (processed) or 60s (other).

Comparators

Function Description
commitmentComparator(c1, c2) Compares two Commitment levels. Returns negative, zero, or positive.

Configuration classes

Class Description
RpcTransactionConfirmationConfig Config for polling-based confirmation helpers: abortSignal, commitment, pollInterval, searchTransactionHistory.
SendAndConfirmTransactionConfig Extends polling config with send options such as maxRetries, minContextSlot, preflightCommitment, and skipPreflight.
RecentSignatureConfirmationConfig Config: getSignatureStatuses, onSignatureNotification.
BlockHeightExceedenceConfig Config: getEpochInfo, onSlotNotification.
NonceInvalidationConfig Config: getNonceAccount, onAccountNotification.
BaseTransactionConfirmationStrategyConfig Base config for raceStrategies: commitment, getRecentSignatureConfirmationPromise, abortSignal?.

Type aliases

Type Description
GetRecentSignatureConfirmationPromise Function type for signature confirmation: Future<void> Function({required AbortSignal abortSignal, required Commitment commitment, required String signature}).

Data classes

Class Description
SignatureStatus Status of a transaction signature: confirmationStatus, err.
EpochInfo Epoch info: absoluteSlot, blockHeight.
SlotNotification A slot notification: slot.
NonceAccountInfo Nonce account info: nonceValue.

Constants

Constant Description
defaultTransactionConfirmationPollInterval Default interval for polling confirmation helpers.

Example

Use example/main.dart as a runnable starting point for solana_kit_transaction_confirmation.

  • Import path: package:solana_kit_transaction_confirmation/solana_kit_transaction_confirmation.dart
  • This section is centrally maintained with mdt to keep package guidance aligned.
  • After updating shared docs templates, run docs:update from the repo root.

Maintenance

  • Validate docs in CI and locally with docs:check.
  • Keep examples focused on one workflow and reference package README sections for deeper API details.

Libraries

solana_kit_transaction_confirmation
Confirmation tracking for the Solana Kit Dart SDK.