TLDR

  • Agave replaces the original Solana node client and deprecates several outdated calls by October 21, 2024.
  • Most newly recommended methods (e.g., getSignatureStatuses) are already standard, so your existing workflows likely remain unaffected.
  • The code examples illustrate how to switch from confirmTransaction to getSignatureStatuses in both JavaScript and Python.

In brief

Agave is the Rust-based Solana node client that is also a fork of the original Solana Labs client.

The primary purpose of Agave replacing the original Solana Labs client is make the network multi-client. The multi-client part mostly means the introduction of another node client — the C-based Firedancer.

Nodes are expected to upgrade to Agave v2.0 by October 21, 2024.

For you as a developer, this means there are a few methods that will be deprecated with other methods replacing them. The methods that are getting the deprecation have already been outdated for quite a bit of time and all of the replacement methods (except for isBlockhashValid) aren’t new. So the chances are you won’t be significantly affected.

See:

Methods: deprecated and replaced

Deprecated callReplacement call
confirmTransactiongetSignatureStatuses
getSignatureStatusgetSignatureStatuses
getSignatureConfirmationgetSignatureStatuses
getConfirmedSignaturesForAddressgetSignaturesForAddress
getConfirmedBlockgetBlock
getConfirmedBlocksgetBlocks
getConfirmedBlocksWithLimitgetBlocksWithLimit
getConfirmedTransactiongetTransaction
getConfirmedSignaturesForAddress2getSignaturesForAddress
getRecentBlockhashgetLatestBlockhash
getFeesgetFeeForMessage
getFeeCalculatorForBlockhashisBlockhashValid or getFeeForMessage
getFeeRateGovernorgetFeeForMessage
getSnapshotSlotgetHighestSnapshotSlot
getStakeActivationgetAccountInfo | Solana (alternative approach)

Replacing confirmTransaction with getSignaturesStatuses

import { Connection, Transaction, SendOptions } from '@solana/web3.js';

async function sendAndConfirmTransaction(
  connection: Connection,
  transaction: Transaction,
  timeout: number = 30000, // 30 seconds default timeout
  options?: SendOptions
): Promise<string> {
  // Send the transaction
  const signature = await connection.sendTransaction(transaction, options?.signers || [], {
    ...options,
    skipPreflight: options?.skipPreflight || false
  });

  // Create a promise that will reject after the timeout
  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => {
      reject(new Error(`Transaction confirmation timeout after ${timeout}ms`));
    }, timeout);
  });

  // Create the confirmation promise
  const confirmationPromise = (async () => {
    let done = false;
    while (!done) {
      // Get the status of the transaction
      const response = await connection.getSignatureStatuses([signature]);
      const status = response.value[0];

      if (status) {
        if (status.err) {
          throw new Error(`Transaction failed: ${status.err.toString()}`);
        }

        // Check if we have enough confirmations
        if (status.confirmationStatus === 'finalized') {
          done = true;
          return signature;
        }
      }

      // Wait a bit before checking again
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  })();

  // Race between timeout and confirmation
  try {
    return await Promise.race([confirmationPromise, timeoutPromise]);
  } catch (error) {
    // If it's a timeout error, we should still return the signature
    if (error.message.includes('timeout')) {
      return signature;
    }
    throw error;
  }
}

// Example usage
async function example() {
  const connection = new Connection('CHAINSTACK_NODE');
  const transaction = new Transaction();
  // ... add your transaction instructions here ...

  try {
    const signature = await sendAndConfirmTransaction(connection, transaction, 60000, {
      skipPreflight: false,
      // ... other options
    });
    console.log('Transaction confirmed:', signature);
  } catch (error) {
    console.error('Transaction failed:', error);
  }
}