@lifi/sdk
Version:
LI.FI Any-to-Any Cross-Chain-Swap SDK
111 lines (93 loc) • 3.42 kB
text/typescript
import type { SignatureResult, VersionedTransaction } from '@solana/web3.js'
import { sleep } from '../../../utils/sleep.js'
import { getJitoConnections } from '../connection.js'
export type BundleResult = {
bundleId: string
txSignatures: string[]
signatureResults: (SignatureResult | null)[]
}
/**
* Send and confirm a bundle of transactions using Jito
* Automatically selects a Jito-enabled RPC connection and polls for confirmation
* across multiple Jito RPCs in parallel
* @param signedTransactions - an Array of signed transactions
* @returns - {@link BundleResult} object containing Bundle ID, transaction signatures, and confirmation results
*/
export async function sendAndConfirmBundle(
signedTransactions: VersionedTransaction[]
): Promise<BundleResult> {
const jitoConnections = await getJitoConnections()
if (jitoConnections.length === 0) {
throw new Error(
'No Jito-enabled RPC connection available for bundle submission'
)
}
const abortController = new AbortController()
const confirmPromises = jitoConnections.map(async (jitoConnection) => {
try {
// Send initial bundle for this connection
let bundleId: string
try {
bundleId = await jitoConnection.sendBundle(signedTransactions)
} catch (_) {
return null
}
const [blockhashResult, initialBlockHeight] = await Promise.all([
jitoConnection.getLatestBlockhash('confirmed'),
jitoConnection.getBlockHeight('confirmed'),
])
let currentBlockHeight = initialBlockHeight
while (
currentBlockHeight < blockhashResult.lastValidBlockHeight &&
!abortController.signal.aborted
) {
const statusResponse = await jitoConnection.getBundleStatuses([
bundleId,
])
const bundleStatus = statusResponse.value[0]
// Check if bundle is confirmed or finalized
if (
bundleStatus &&
(bundleStatus.confirmation_status === 'confirmed' ||
bundleStatus.confirmation_status === 'finalized')
) {
// Bundle confirmed! Extract transaction signatures from bundle status
const txSignatures = bundleStatus.transactions
// Fetch individual signature results
const sigResponse =
await jitoConnection.getSignatureStatuses(txSignatures)
if (!sigResponse?.value || !Array.isArray(sigResponse.value)) {
// Keep polling, if can't find signature results.
continue
}
// Immediately abort all other connections when we find a result
abortController.abort()
return {
bundleId,
txSignatures,
signatureResults: sigResponse.value,
}
}
await sleep(400)
if (!abortController.signal.aborted) {
currentBlockHeight = await jitoConnection.getBlockHeight('confirmed')
}
}
return null
} catch (error) {
if (abortController.signal.aborted) {
return null // Don't treat abortion as an error
}
throw error
}
})
// Wait for first successful confirmation
const result = await Promise.any(confirmPromises).catch(() => null)
if (!abortController.signal.aborted) {
abortController.abort()
}
if (!result) {
throw new Error('Failed to send and confirm bundle')
}
return result
}