@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","safeRace","e","getTimeoutPromise"],"mappings":"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","file":"index.node.mjs","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 (signatureStatus?.err) {\n throw getSolanaErrorFromTransactionError(signatureStatus.err);\n } else if (\n signatureStatus?.confirmationStatus &&\n commitmentComparator(signatureStatus.confirmationStatus, commitment) >= 0\n ) {\n return;\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 extends BaseTransactionConfirmationStrategyConfig {\n getBlockHeightExceedencePromise: ReturnType<typeof createBlockHeightExceedencePromiseFactory>;\n transaction: Readonly<Transaction & TransactionWithLastValidBlockHeight>;\n}\n\ninterface WaitForRecentTransactionWithTimeBasedLifetimeConfirmationConfig 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"]}