@solana/transaction-confirmation
Version:
Helpers for confirming Solana transactions
1 lines • 37.9 kB
Source Map (JSON)
{"version":3,"sources":["../../event-target-impl/src/index.node.ts","../src/confirmation-strategy-blockheight.ts","../src/confirmation-strategy-nonce.ts","../src/confirmation-strategy-recent-signature.ts","../src/confirmation-strategy-timeout.ts","../src/confirmation-strategy-racer.ts","../src/waiters.ts"],"names":["AbortController","args","setMaxListeners","SolanaError","SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED","getBase58Decoder","getBase64Encoder","SOLANA_ERROR__INVALID_NONCE","SOLANA_ERROR__NONCE_ACCOUNT_NOT_FOUND","safeRace","getSolanaErrorFromTransactionError","commitmentComparator","e","getSignatureFromTransaction","getTimeoutPromise"],"mappings":"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","file":"index.node.cjs","sourcesContent":["import { setMaxListeners } from 'node:events';\n\nexport const AbortController = class extends globalThis.AbortController {\n constructor(...args: ConstructorParameters<typeof globalThis.AbortController>) {\n super(...args);\n setMaxListeners(Number.MAX_SAFE_INTEGER, this.signal);\n }\n};\n\nexport const EventTarget = class extends globalThis.EventTarget {\n constructor(...args: ConstructorParameters<typeof globalThis.EventTarget>) {\n super(...args);\n setMaxListeners(Number.MAX_SAFE_INTEGER, this);\n }\n};\n","import { SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED, SolanaError } from '@solana/errors';\nimport { AbortController } from '@solana/event-target-impl';\nimport type { GetEpochInfoApi, Rpc } from '@solana/rpc';\nimport type { RpcSubscriptions, SlotNotificationsApi } from '@solana/rpc-subscriptions';\nimport type { Commitment } from '@solana/rpc-types';\n\ntype GetBlockHeightExceedencePromiseFn = (config: {\n abortSignal: AbortSignal;\n /**\n * Fetch the block height as of the highest slot that has reached this level of commitment.\n *\n * @defaultValue Whichever default is applied by the underlying {@link RpcApi} in use. For\n * example, when using an API created by a `createSolanaRpc*()` helper, the default commitment\n * is `\"confirmed\"` unless configured otherwise. Unmitigated by an API layer on the client, the\n * default commitment applied by the server is `\"finalized\"`.\n */\n commitment?: Commitment;\n /** The block height after which to reject the promise */\n lastValidBlockHeight: bigint;\n}) => Promise<void>;\n\ntype CreateBlockHeightExceedencePromiseFactoryConfig<TCluster> = {\n rpc: Rpc<GetEpochInfoApi> & { '~cluster'?: TCluster };\n rpcSubscriptions: RpcSubscriptions<SlotNotificationsApi> & { '~cluster'?: TCluster };\n};\n\n/**\n * Creates a promise that throws when the network progresses past the block height after which the\n * supplied blockhash is considered expired for use as a transaction lifetime specifier.\n *\n * When a transaction's lifetime is tied to a blockhash, that transaction can be landed on the\n * network until that blockhash expires. All blockhashes have a block height after which they are\n * considered to have expired.\n *\n * @param config\n *\n * @example\n * ```ts\n * import { isSolanaError, SolanaError } from '@solana/errors';\n * import { createBlockHeightExceedencePromiseFactory } from '@solana/transaction-confirmation';\n *\n * const getBlockHeightExceedencePromise = createBlockHeightExceedencePromiseFactory({\n * rpc,\n * rpcSubscriptions,\n * });\n * try {\n * await getBlockHeightExceedencePromise({ lastValidBlockHeight });\n * } catch (e) {\n * if (isSolanaError(e, SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED)) {\n * console.error(\n * `The block height of the network has exceeded ${e.context.lastValidBlockHeight}. ` +\n * `It is now ${e.context.currentBlockHeight}`,\n * );\n * // Re-sign and retry the transaction.\n * return;\n * }\n * throw e;\n * }\n * ```\n */\nexport function createBlockHeightExceedencePromiseFactory({\n rpc,\n rpcSubscriptions,\n}: CreateBlockHeightExceedencePromiseFactoryConfig<'devnet'>): GetBlockHeightExceedencePromiseFn;\nexport function createBlockHeightExceedencePromiseFactory({\n rpc,\n rpcSubscriptions,\n}: CreateBlockHeightExceedencePromiseFactoryConfig<'testnet'>): GetBlockHeightExceedencePromiseFn;\nexport function createBlockHeightExceedencePromiseFactory({\n rpc,\n rpcSubscriptions,\n}: CreateBlockHeightExceedencePromiseFactoryConfig<'mainnet'>): GetBlockHeightExceedencePromiseFn;\nexport function createBlockHeightExceedencePromiseFactory<\n TCluster extends 'devnet' | 'mainnet' | 'testnet' | void = void,\n>({\n rpc,\n rpcSubscriptions,\n}: CreateBlockHeightExceedencePromiseFactoryConfig<TCluster>): GetBlockHeightExceedencePromiseFn {\n return async function getBlockHeightExceedencePromise({\n abortSignal: callerAbortSignal,\n commitment,\n lastValidBlockHeight,\n }): Promise<never> {\n callerAbortSignal.throwIfAborted();\n const abortController = new AbortController();\n const handleAbort = () => {\n abortController.abort();\n };\n callerAbortSignal.addEventListener('abort', handleAbort, { signal: abortController.signal });\n async function getBlockHeightAndDifferenceBetweenSlotHeightAndBlockHeight() {\n const { absoluteSlot, blockHeight } = await rpc\n .getEpochInfo({ commitment })\n .send({ abortSignal: abortController.signal });\n return {\n blockHeight,\n differenceBetweenSlotHeightAndBlockHeight: absoluteSlot - blockHeight,\n };\n }\n try {\n const [slotNotifications, { blockHeight: initialBlockHeight, differenceBetweenSlotHeightAndBlockHeight }] =\n await Promise.all([\n rpcSubscriptions.slotNotifications().subscribe({ abortSignal: abortController.signal }),\n getBlockHeightAndDifferenceBetweenSlotHeightAndBlockHeight(),\n ]);\n callerAbortSignal.throwIfAborted();\n let currentBlockHeight = initialBlockHeight;\n if (currentBlockHeight <= lastValidBlockHeight) {\n let lastKnownDifferenceBetweenSlotHeightAndBlockHeight = differenceBetweenSlotHeightAndBlockHeight;\n for await (const slotNotification of slotNotifications) {\n const { slot } = slotNotification;\n if (slot - lastKnownDifferenceBetweenSlotHeightAndBlockHeight > lastValidBlockHeight) {\n // Before making a final decision, recheck the actual block height.\n const {\n blockHeight: recheckedBlockHeight,\n differenceBetweenSlotHeightAndBlockHeight: currentDifferenceBetweenSlotHeightAndBlockHeight,\n } = await getBlockHeightAndDifferenceBetweenSlotHeightAndBlockHeight();\n currentBlockHeight = recheckedBlockHeight;\n if (currentBlockHeight > lastValidBlockHeight) {\n // Verified; the block height has been exceeded.\n break;\n } else {\n // The block height has not been exceeded, which implies that the\n // difference between the slot height and the block height has grown\n // (ie. some blocks have been skipped since we started). Recalibrate the\n // difference and keep waiting.\n lastKnownDifferenceBetweenSlotHeightAndBlockHeight =\n currentDifferenceBetweenSlotHeightAndBlockHeight;\n }\n }\n }\n }\n callerAbortSignal.throwIfAborted();\n throw new SolanaError(SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED, {\n currentBlockHeight,\n lastValidBlockHeight,\n });\n } finally {\n abortController.abort();\n }\n };\n}\n","import type { Address } from '@solana/addresses';\nimport { getBase58Decoder, getBase64Encoder } from '@solana/codecs-strings';\nimport { SOLANA_ERROR__INVALID_NONCE, SOLANA_ERROR__NONCE_ACCOUNT_NOT_FOUND, SolanaError } from '@solana/errors';\nimport { AbortController } from '@solana/event-target-impl';\nimport { safeRace } from '@solana/promises';\nimport type { GetAccountInfoApi, Rpc } from '@solana/rpc';\nimport type { AccountNotificationsApi, RpcSubscriptions } from '@solana/rpc-subscriptions';\nimport type { Base64EncodedDataResponse, Commitment } from '@solana/rpc-types';\nimport { Nonce } from '@solana/transaction-messages';\n\ntype GetNonceInvalidationPromiseFn = (config: {\n abortSignal: AbortSignal;\n /**\n * Fetch the nonce account details as of the highest slot that has reached this level of\n * commitment.\n */\n commitment: Commitment;\n /**\n * The value of the nonce that we would expect to see in the nonce account in order for any\n * transaction with that nonce-based lifetime to be considered valid.\n */\n currentNonceValue: Nonce;\n /** The address of the account in which the currently-valid nonce value is stored */\n nonceAccountAddress: Address;\n}) => Promise<void>;\n\ntype CreateNonceInvalidationPromiseFactoryConfig<TCluster> = {\n rpc: Rpc<GetAccountInfoApi> & { '~cluster'?: TCluster };\n rpcSubscriptions: RpcSubscriptions<AccountNotificationsApi> & { '~cluster'?: TCluster };\n};\n\nconst NONCE_VALUE_OFFSET =\n 4 + // version(u32)\n 4 + // state(u32)\n 32; // nonce authority(pubkey)\n// Then comes the nonce value.\n\n/**\n * Creates a promise that throws when the value stored in a nonce account is not the expected one.\n *\n * When a transaction's lifetime is tied to the value stored in a nonce account, that transaction\n * can be landed on the network until the nonce is advanced to a new value.\n *\n * @param config\n *\n * @example\n * ```ts\n * import { isSolanaError, SolanaError } from '@solana/errors';\n * import { createNonceInvalidationPromiseFactory } from '@solana/transaction-confirmation';\n *\n * const getNonceInvalidationPromise = createNonceInvalidationPromiseFactory({\n * rpc,\n * rpcSubscriptions,\n * });\n * try {\n * await getNonceInvalidationPromise({\n * currentNonceValue,\n * nonceAccountAddress,\n * });\n * } catch (e) {\n * if (isSolanaError(e, SOLANA_ERROR__NONCE_INVALID)) {\n * console.error(`The nonce has advanced to ${e.context.actualNonceValue}`);\n * // Re-sign and retry the transaction.\n * return;\n * } else if (isSolanaError(e, SOLANA_ERROR__NONCE_ACCOUNT_NOT_FOUND)) {\n * console.error(`No nonce account was found at ${nonceAccountAddress}`);\n * }\n * throw e;\n * }\n * ```\n */\nexport function createNonceInvalidationPromiseFactory({\n rpc,\n rpcSubscriptions,\n}: CreateNonceInvalidationPromiseFactoryConfig<'devnet'>): GetNonceInvalidationPromiseFn;\nexport function createNonceInvalidationPromiseFactory({\n rpc,\n rpcSubscriptions,\n}: CreateNonceInvalidationPromiseFactoryConfig<'testnet'>): GetNonceInvalidationPromiseFn;\nexport function createNonceInvalidationPromiseFactory({\n rpc,\n rpcSubscriptions,\n}: CreateNonceInvalidationPromiseFactoryConfig<'mainnet'>): GetNonceInvalidationPromiseFn;\nexport function createNonceInvalidationPromiseFactory<TCluster extends 'devnet' | 'mainnet' | 'testnet' | void = void>({\n rpc,\n rpcSubscriptions,\n}: CreateNonceInvalidationPromiseFactoryConfig<TCluster>): GetNonceInvalidationPromiseFn {\n return async function getNonceInvalidationPromise({\n abortSignal: callerAbortSignal,\n commitment,\n currentNonceValue: expectedNonceValue,\n nonceAccountAddress,\n }) {\n const abortController = new AbortController();\n function handleAbort() {\n abortController.abort();\n }\n callerAbortSignal.addEventListener('abort', handleAbort, { signal: abortController.signal });\n /**\n * STEP 1: Set up a subscription for nonce account changes.\n */\n const accountNotifications = await rpcSubscriptions\n .accountNotifications(nonceAccountAddress, { commitment, encoding: 'base64' })\n .subscribe({ abortSignal: abortController.signal });\n const base58Decoder = getBase58Decoder();\n const base64Encoder = getBase64Encoder();\n function getNonceFromAccountData([base64EncodedBytes]: Base64EncodedDataResponse): Nonce {\n const data = base64Encoder.encode(base64EncodedBytes);\n const nonceValueBytes = data.slice(NONCE_VALUE_OFFSET, NONCE_VALUE_OFFSET + 32);\n return base58Decoder.decode(nonceValueBytes) as Nonce;\n }\n const nonceAccountDidAdvancePromise = (async () => {\n for await (const accountNotification of accountNotifications) {\n const nonceValue = getNonceFromAccountData(accountNotification.value.data);\n if (nonceValue !== expectedNonceValue) {\n throw new SolanaError(SOLANA_ERROR__INVALID_NONCE, {\n actualNonceValue: nonceValue,\n expectedNonceValue,\n });\n }\n }\n })();\n /**\n * STEP 2: Having subscribed for updates, make a one-shot request for the current nonce\n * value to check if it has already been advanced.\n */\n const nonceIsAlreadyInvalidPromise = (async () => {\n const { value: nonceAccount } = await rpc\n .getAccountInfo(nonceAccountAddress, {\n commitment,\n dataSlice: { length: 32, offset: NONCE_VALUE_OFFSET },\n encoding: 'base58',\n })\n .send({ abortSignal: abortController.signal });\n if (!nonceAccount) {\n throw new SolanaError(SOLANA_ERROR__NONCE_ACCOUNT_NOT_FOUND, {\n nonceAccountAddress,\n });\n }\n const nonceValue =\n // This works because we asked for the exact slice of data representing the nonce\n // value, and furthermore asked for it in `base58` encoding.\n nonceAccount.data[0] as unknown as Nonce;\n if (nonceValue !== expectedNonceValue) {\n throw new SolanaError(SOLANA_ERROR__INVALID_NONCE, {\n actualNonceValue: nonceValue,\n expectedNonceValue,\n });\n } else {\n await new Promise(() => {\n /* never resolve */\n });\n }\n })();\n try {\n return await safeRace([nonceAccountDidAdvancePromise, nonceIsAlreadyInvalidPromise]);\n } finally {\n abortController.abort();\n }\n };\n}\n","import { getSolanaErrorFromTransactionError } from '@solana/errors';\nimport { AbortController } from '@solana/event-target-impl';\nimport type { Signature } from '@solana/keys';\nimport { safeRace } from '@solana/promises';\nimport type { GetSignatureStatusesApi, Rpc } from '@solana/rpc';\nimport type { RpcSubscriptions, SignatureNotificationsApi } from '@solana/rpc-subscriptions';\nimport { type Commitment, commitmentComparator } from '@solana/rpc-types';\n\ntype GetRecentSignatureConfirmationPromiseFn = (config: {\n abortSignal: AbortSignal;\n /**\n * The level of commitment the transaction must have achieved in order for the promise to\n * resolve.\n */\n commitment: Commitment;\n /**\n * A 64 byte Ed25519 signature, encoded as a base-58 string, that uniquely identifies a\n * transaction by virtue of being the first or only signature in its list of signatures.\n */\n signature: Signature;\n}) => Promise<void>;\n\ntype CreateRecentSignatureConfirmationPromiseFactoryConfig<TCluster> = {\n rpc: Rpc<GetSignatureStatusesApi> & { '~cluster'?: TCluster };\n rpcSubscriptions: RpcSubscriptions<SignatureNotificationsApi> & { '~cluster'?: TCluster };\n};\n\n/**\n * Creates a promise that resolves when a recently-landed transaction achieves the target\n * confirmation commitment, and throws when the transaction fails with an error.\n *\n * The status of recently-landed transactions is available in the network's status cache. This\n * confirmation strategy will only yield a result if the signature is still in the status cache. To\n * fetch the status of transactions older than those available in the status cache, use the\n * {@link GetSignatureStatusesApi.getSignatureStatuses} method setting the\n * `searchTransactionHistory` configuration param to `true`.\n *\n * @param config\n *\n * @example\n * ```ts\n * import { createRecentSignatureConfirmationPromiseFactory } from '@solana/transaction-confirmation';\n *\n * const getRecentSignatureConfirmationPromise = createRecentSignatureConfirmationPromiseFactory({\n * rpc,\n * rpcSubscriptions,\n * });\n * try {\n * await getRecentSignatureConfirmationPromise({\n * commitment,\n * signature,\n * });\n * console.log(`The transaction with signature \\`${signature}\\` has achieved a commitment level of \\`${commitment}\\``);\n * } catch (e) {\n * console.error(`The transaction with signature \\`${signature}\\` failed`, e.cause);\n * throw e;\n * }\n * ```\n */\nexport function createRecentSignatureConfirmationPromiseFactory({\n rpc,\n rpcSubscriptions,\n}: CreateRecentSignatureConfirmationPromiseFactoryConfig<'devnet'>): GetRecentSignatureConfirmationPromiseFn;\nexport function createRecentSignatureConfirmationPromiseFactory({\n rpc,\n rpcSubscriptions,\n}: CreateRecentSignatureConfirmationPromiseFactoryConfig<'testnet'>): GetRecentSignatureConfirmationPromiseFn;\nexport function createRecentSignatureConfirmationPromiseFactory({\n rpc,\n rpcSubscriptions,\n}: CreateRecentSignatureConfirmationPromiseFactoryConfig<'mainnet'>): GetRecentSignatureConfirmationPromiseFn;\nexport function createRecentSignatureConfirmationPromiseFactory<\n TCluster extends 'devnet' | 'mainnet' | 'testnet' | void = void,\n>({\n rpc,\n rpcSubscriptions,\n}: CreateRecentSignatureConfirmationPromiseFactoryConfig<TCluster>): GetRecentSignatureConfirmationPromiseFn {\n return async function getRecentSignatureConfirmationPromise({\n abortSignal: callerAbortSignal,\n commitment,\n signature,\n }) {\n const abortController = new AbortController();\n function handleAbort() {\n abortController.abort();\n }\n callerAbortSignal.addEventListener('abort', handleAbort, { signal: abortController.signal });\n /**\n * STEP 1: Set up a subscription for status changes to a signature.\n */\n const signatureStatusNotifications = await rpcSubscriptions\n .signatureNotifications(signature, { commitment })\n .subscribe({ abortSignal: abortController.signal });\n const signatureDidCommitPromise = (async () => {\n for await (const signatureStatusNotification of signatureStatusNotifications) {\n if (signatureStatusNotification.value.err) {\n throw getSolanaErrorFromTransactionError(signatureStatusNotification.value.err);\n } else {\n return;\n }\n }\n })();\n /**\n * STEP 2: Having subscribed for updates, make a one-shot request for the current status.\n * This will only yield a result if the signature is still in the status cache.\n */\n const signatureStatusLookupPromise = (async () => {\n const { value: signatureStatusResults } = await rpc\n .getSignatureStatuses([signature])\n .send({ abortSignal: abortController.signal });\n const signatureStatus = signatureStatusResults[0];\n if (\n signatureStatus?.confirmationStatus &&\n commitmentComparator(signatureStatus.confirmationStatus, commitment) >= 0\n ) {\n return;\n } else if (signatureStatus?.err) {\n throw getSolanaErrorFromTransactionError(signatureStatus.err);\n } else {\n await new Promise(() => {\n /* never resolve */\n });\n }\n })();\n try {\n return await safeRace([signatureDidCommitPromise, signatureStatusLookupPromise]);\n } finally {\n abortController.abort();\n }\n };\n}\n","import type { Commitment } from '@solana/rpc-types';\n\ntype Config = Readonly<{\n abortSignal: AbortSignal;\n /**\n * The timeout promise will throw after 30 seconds when the commitment is `processed`, and 60\n * seconds otherwise.\n */\n commitment: Commitment;\n}>;\n\n/**\n * When no other heuristic exists to infer that a transaction has expired, you can use this promise\n * factory with a commitment level. It throws after 30 seconds when the commitment is `processed`,\n * and 60 seconds otherwise. You would typically race this with another confirmation strategy.\n *\n * @param config\n *\n * @example\n * ```ts\n * import { safeRace } from '@solana/promises';\n * import { getTimeoutPromise } from '@solana/transaction-confirmation';\n *\n * try {\n * await safeRace([getCustomTransactionConfirmationPromise(/* ... *\\/), getTimeoutPromise({ commitment })]);\n * } catch (e) {\n * if (e instanceof DOMException && e.name === 'TimeoutError') {\n * console.log('Could not confirm transaction after a timeout');\n * }\n * throw e;\n * }\n * ```\n */\nexport async function getTimeoutPromise({ abortSignal: callerAbortSignal, commitment }: Config) {\n return await new Promise((_, reject) => {\n const handleAbort = (e: AbortSignalEventMap['abort']) => {\n clearTimeout(timeoutId);\n const abortError = new DOMException((e.target as AbortSignal).reason, 'AbortError');\n reject(abortError);\n };\n callerAbortSignal.addEventListener('abort', handleAbort);\n const timeoutMs = commitment === 'processed' ? 30_000 : 60_000;\n const startMs = performance.now();\n const timeoutId =\n // We use `setTimeout` instead of `AbortSignal.timeout()` because we want to measure\n // elapsed time instead of active time.\n // See https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static\n setTimeout(() => {\n const elapsedMs = performance.now() - startMs;\n reject(new DOMException(`Timeout elapsed after ${elapsedMs} ms`, 'TimeoutError'));\n }, timeoutMs);\n });\n}\n","import { AbortController } from '@solana/event-target-impl';\nimport type { Signature } from '@solana/keys';\nimport { safeRace } from '@solana/promises';\nimport type { Commitment } from '@solana/rpc-types';\n\nimport { createRecentSignatureConfirmationPromiseFactory } from './confirmation-strategy-recent-signature';\n\nexport interface BaseTransactionConfirmationStrategyConfig {\n abortSignal?: AbortSignal;\n commitment: Commitment;\n getRecentSignatureConfirmationPromise: ReturnType<typeof createRecentSignatureConfirmationPromiseFactory>;\n}\n\ntype WithNonNullableAbortSignal<T> = Omit<T, 'abortSignal'> & Readonly<{ abortSignal: AbortSignal }>;\n\nexport async function raceStrategies<TConfig extends BaseTransactionConfirmationStrategyConfig>(\n signature: Signature,\n config: TConfig,\n getSpecificStrategiesForRace: (config: WithNonNullableAbortSignal<TConfig>) => readonly Promise<unknown>[],\n) {\n const { abortSignal: callerAbortSignal, commitment, getRecentSignatureConfirmationPromise } = config;\n callerAbortSignal?.throwIfAborted();\n const abortController = new AbortController();\n if (callerAbortSignal) {\n const handleAbort = () => {\n abortController.abort();\n };\n callerAbortSignal.addEventListener('abort', handleAbort, { signal: abortController.signal });\n }\n try {\n const specificStrategies = getSpecificStrategiesForRace({\n ...config,\n abortSignal: abortController.signal,\n });\n return await safeRace([\n getRecentSignatureConfirmationPromise({\n abortSignal: abortController.signal,\n commitment,\n signature,\n }),\n ...specificStrategies,\n ]);\n } finally {\n abortController.abort();\n }\n}\n","import { Signature } from '@solana/keys';\nimport {\n getSignatureFromTransaction,\n Transaction,\n TransactionWithBlockhashLifetime,\n TransactionWithDurableNonceLifetime,\n} from '@solana/transactions';\n\nimport { createBlockHeightExceedencePromiseFactory } from './confirmation-strategy-blockheight';\nimport { createNonceInvalidationPromiseFactory } from './confirmation-strategy-nonce';\nimport { BaseTransactionConfirmationStrategyConfig, raceStrategies } from './confirmation-strategy-racer';\nimport { getTimeoutPromise } from './confirmation-strategy-timeout';\n\nexport type TransactionWithLastValidBlockHeight = Omit<TransactionWithBlockhashLifetime, 'lifetimeConstraint'> & {\n lifetimeConstraint: Omit<TransactionWithBlockhashLifetime['lifetimeConstraint'], 'blockhash'>;\n};\n\ninterface WaitForDurableNonceTransactionConfirmationConfig extends BaseTransactionConfirmationStrategyConfig {\n getNonceInvalidationPromise: ReturnType<typeof createNonceInvalidationPromiseFactory>;\n transaction: Readonly<Transaction & TransactionWithDurableNonceLifetime>;\n}\n\ninterface WaitForRecentTransactionWithBlockhashLifetimeConfirmationConfig\n extends BaseTransactionConfirmationStrategyConfig {\n getBlockHeightExceedencePromise: ReturnType<typeof createBlockHeightExceedencePromiseFactory>;\n transaction: Readonly<Transaction & TransactionWithLastValidBlockHeight>;\n}\n\ninterface WaitForRecentTransactionWithTimeBasedLifetimeConfirmationConfig\n extends BaseTransactionConfirmationStrategyConfig {\n getTimeoutPromise: typeof getTimeoutPromise;\n /**\n * A 64 byte Ed25519 signature, encoded as a base-58 string, that uniquely identifies a\n * transaction by virtue of being the first or only signature in its list of signatures.\n */\n signature: Signature;\n}\n\n/**\n * Supply your own confirmation implementations to this function to create a custom nonce\n * transaction confirmation strategy.\n *\n * @example\n * ```ts\n * import { waitForDurableNonceTransactionConfirmation } from '@solana/transaction-confirmation';\n *\n * try {\n * await waitForDurableNonceTransactionConfirmation({\n * getNonceInvalidationPromise({ abortSignal, commitment, currentNonceValue, nonceAccountAddress }) {\n * // Return a promise that rejects when a nonce becomes invalid.\n * },\n * getRecentSignatureConfirmationPromise({ abortSignal, commitment, signature }) {\n * // Return a promise that resolves when a transaction achieves confirmation\n * },\n * });\n * } catch (e) {\n * // Handle errors.\n * }\n * ```\n */\nexport async function waitForDurableNonceTransactionConfirmation(\n config: WaitForDurableNonceTransactionConfirmationConfig,\n): Promise<void> {\n await raceStrategies(\n getSignatureFromTransaction(config.transaction),\n config,\n function getSpecificStrategiesForRace({ abortSignal, commitment, getNonceInvalidationPromise, transaction }) {\n return [\n getNonceInvalidationPromise({\n abortSignal,\n commitment,\n currentNonceValue: transaction.lifetimeConstraint.nonce,\n nonceAccountAddress: transaction.lifetimeConstraint.nonceAccountAddress,\n }),\n ];\n },\n );\n}\n\n/**\n * Supply your own confirmation implementations to this function to create a custom confirmation\n * strategy for recently-landed transactions.\n *\n * @example\n * ```ts\n * import { waitForRecentTransactionConfirmation } from '@solana/transaction-confirmation';\n *\n * try {\n * await waitForRecentTransactionConfirmation({\n * getBlockHeightExceedencePromise({ abortSignal, commitment, lastValidBlockHeight }) {\n * // Return a promise that rejects when the blockhash's block height has been exceeded\n * },\n * getRecentSignatureConfirmationPromise({ abortSignal, commitment, signature }) {\n * // Return a promise that resolves when a transaction achieves confirmation\n * },\n * });\n * } catch (e) {\n * // Handle errors.\n * }\n * ```\n */\nexport async function waitForRecentTransactionConfirmation(\n config: WaitForRecentTransactionWithBlockhashLifetimeConfirmationConfig,\n): Promise<void> {\n await raceStrategies(\n getSignatureFromTransaction(config.transaction),\n config,\n function getSpecificStrategiesForRace({\n abortSignal,\n commitment,\n getBlockHeightExceedencePromise,\n transaction,\n }) {\n return [\n getBlockHeightExceedencePromise({\n abortSignal,\n commitment,\n lastValidBlockHeight: transaction.lifetimeConstraint.lastValidBlockHeight,\n }),\n ];\n },\n );\n}\n\n/** @deprecated */\nexport async function waitForRecentTransactionConfirmationUntilTimeout(\n config: WaitForRecentTransactionWithTimeBasedLifetimeConfirmationConfig,\n): Promise<void> {\n await raceStrategies(\n config.signature,\n config,\n function getSpecificStrategiesForRace({ abortSignal, commitment, getTimeoutPromise }) {\n return [\n getTimeoutPromise({\n abortSignal,\n commitment,\n }),\n ];\n },\n );\n}\n"]}