This package contains utilities for confirming transactions and for building your own transaction confirmation strategies.
When a transaction's lifetime is tied to a blockhash, that transaction can be landed on the network until that blockhash expires. All blockhashes have a block height after which they are considered to have expired. A block height exceedence promise throws when the network progresses past that block height.
import { isSolanaError, SolanaError } from '@solana/errors';
import { createBlockHeightExceedencePromiseFactory } from '@solana/transaction-confirmation';
const getBlockHeightExceedencePromise = createBlockHeightExceedencePromiseFactory({
rpc,
rpcSubscriptions,
});
try {
await getBlockHeightExceedencePromise({ lastValidBlockHeight });
} catch (e) {
if (isSolanaError(e, SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED)) {
console.error(
`The block height of the network has exceeded ${e.context.lastValidBlockHeight}. ` +
`It is now ${e.context.currentBlockHeight}`,
);
// Re-sign and retry the transaction.
return;
}
throw e;
}
When a transaction's lifetime is tied to the value stored in a nonce account, that transaction can be landed on the network until the nonce is advanced to a new value. A nonce invalidation promise throws when the value stored in a nonce account is not the expected one.
import { isSolanaError, SolanaError } from '@solana/errors';
import { createNonceInvalidationPromiseFactory } from '@solana/transaction-confirmation';
const getNonceInvalidationPromise = createNonceInvalidationPromiseFactory({
rpc,
rpcSubscriptions,
});
try {
await getNonceInvalidationPromise({
currentNonceValue,
nonceAccountAddress,
});
} catch (e) {
if (isSolanaError(e, SOLANA_ERROR__NONCE_INVALID)) {
console.error(`The nonce has advanced to ${e.context.actualNonceValue}`);
// Re-sign and retry the transaction.
return;
} else if (isSolanaError(e, SOLANA_ERROR__NONCE_ACCOUNT_NOT_FOUND)) {
console.error(`No nonce account was found at ${nonceAccountAddress}`);
}
throw e;
}
The status of recently-landed transactions is available in the network's status cache. A recent signature confirmation promise resolves when a transaction achieves the target confirmation commitment, and throws when the transaction fails with an error.
import { createRecentSignatureConfirmationPromiseFactory } from '@solana/transaction-confirmation';
const getRecentSignatureConfirmationPromise = createRecentSignatureConfirmationPromiseFactory({
rpc,
rpcSubscriptions,
});
try {
await getRecentSignatureConfirmationPromise({
commitment,
signature,
});
console.log(`The transaction with signature \`${signature}\` has achieved a commitment level of \`${commitment}\``);
} catch (e) {
console.error(`The transaction with signature \`${signature}\` failed`, e.cause);
throw e;
}
When no other heuristic exists to infer that a transaction has expired, you can use this promise factory with a commitment level. It throws after 30 seconds when the commitment is processed
, and 60 seconds otherwise. You would typically race this with another confirmation strategy.
import { safeRace } from '@solana/promises';
import { getTimeoutPromise } from '@solana/transaction-confirmation';
try {
await safeRace([getCustomTransactionConfirmationPromise(/* ... */), getTimeoutPromise({ commitment })]);
} catch (e) {
if (e instanceof DOMException && e.name === 'TimeoutError') {
console.log('Could not confirm transaction after a timeout');
}
throw e;
}
Supply your own confirmation implementations to this function to create a custom nonce transaction confirmation strategy.
import { waitForDurableNonceTransactionConfirmation } from '@solana/transaction-confirmation';
try {
await waitForDurableNonceTransactionConfirmation({
getNonceInvalidationPromise({ abortSignal, commitment, currentNonceValue, nonceAccountAddress }) {
// Return a promise that rejects when a nonce becomes invalid.
},
getRecentSignatureConfirmationPromise({ abortSignal, commitment, signature }) {
// Return a promise that resolves when a transaction achieves confirmation
},
});
} catch (e) {
// Handle errors.
}
Supply your own confirmation implementations to this function to create a custom nonce transaction confirmation strategy.
import { waitForRecentTransactionConfirmation } from '@solana/transaction-confirmation';
try {
await waitForRecentTransactionConfirmation({
getBlockHeightExceedencePromise({ abortSignal, commitment, lastValidBlockHeight }) {
// Return a promise that rejects when the blockhash's block height has been exceeded
},
getRecentSignatureConfirmationPromise({ abortSignal, commitment, signature }) {
// Return a promise that resolves when a transaction achieves confirmation
},
});
} catch (e) {
// Handle errors.
}
Supply your own confirmation implementations to this function to create a custom nonce transaction confirmation strategy.
import { waitForRecentTransactionConfirmationUntilTimeout } from '@solana/transaction-confirmation';
try {
await waitForRecentTransactionConfirmationUntilTimeout({
getTimeoutPromise({ abortSignal, commitment }) {
// Return a promise that rejects after your chosen timeout
},
getRecentSignatureConfirmationPromise({ abortSignal, commitment, signature }) {
// Return a promise that resolves when a transaction achieves confirmation
},
});
} catch (e) {
// Handle errors.
}