@xswap-link/sdk
Version:
JavaScript SDK for XSwap platform
132 lines (114 loc) • 4.66 kB
text/typescript
import {
Commitment,
Connection,
Transaction,
TransactionInstruction,
} from "@solana/web3.js";
import { CCIPContext } from "../core/models";
import { TxOptions } from "../tokenpools/abstract";
import { createErrorEnhancer } from "./errors";
import { Logger } from "./logger";
/**
* Extended options for transaction execution that includes error context
*/
export interface TransactionExecutionOptions extends TxOptions {
/**
* Optional context information to include in error messages
* This helps pinpoint the source and details of transaction failures
*/
errorContext?: Record<string, string>;
/**
* Optional operation name for logging and error reporting
*/
operationName?: string;
}
/**
* Extracts transaction options from various input structures
* Handles both nested txOptions and direct transaction parameters
*
* @param options Any object that might contain transaction options
* @returns Normalized TxOptions or undefined if no options found
*/
export function extractTxOptions(options?: any): TxOptions | undefined {
if (!options) {
return undefined;
}
// If the options object has a txOptions property, use that
if (options.txOptions) {
return options.txOptions;
}
// If the options object itself has tx option properties, extract those
const txOptions: TxOptions = {};
// Check for and copy over common tx option properties
if (options.skipPreflight !== undefined) txOptions.skipPreflight = options.skipPreflight;
if (options.preflightCommitment !== undefined) txOptions.preflightCommitment = options.preflightCommitment;
if (options.maxRetries !== undefined) txOptions.maxRetries = options.maxRetries;
if (options.commitment !== undefined) txOptions.commitment = options.commitment;
if (options.confirmationCommitment !== undefined) txOptions.confirmationCommitment = options.confirmationCommitment;
// Return undefined if no tx options were found
return Object.keys(txOptions).length > 0 ? txOptions : undefined;
}
/**
* Executes a transaction with the given instructions
* Handles the entire transaction lifecycle: creation, signing, sending, and confirmation
*
* @param context CCIP context with provider and connection
* @param instructions Array of transaction instructions to execute
* @param options Transaction execution options including commitment levels and error context
* @returns Transaction signature
*/
export async function executeTransaction(
context: CCIPContext,
instructions: TransactionInstruction[],
options?: TransactionExecutionOptions
): Promise<string> {
const logger = context.logger || { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} } as Logger;
const connection = context.provider.connection;
const txOptions = extractTxOptions(options);
// Setup error enhancement
const errorContext = options?.errorContext || {};
const operationName = options?.operationName || 'executeTransaction';
const enhanceError = createErrorEnhancer(logger);
try {
logger.debug(
`Starting transaction execution${operationName ? ` for ${operationName}` : ''}`
);
// Get the latest blockhash with configured commitment
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash({
commitment: txOptions?.commitment ?? "finalized",
});
// Create transaction with the instructions
const transaction = new Transaction();
transaction.recentBlockhash = blockhash;
transaction.feePayer = context.provider.getAddress();
// Add all instructions to the transaction
for (const instruction of instructions) {
transaction.add(instruction);
}
// Sign the transaction
const signedTx = await context.provider.signTransaction(transaction);
// Send the transaction with configurable options
const signature = await connection.sendRawTransaction(signedTx.serialize(), {
skipPreflight: txOptions?.skipPreflight ?? false,
preflightCommitment: txOptions?.preflightCommitment ?? ("processed" as Commitment),
maxRetries: txOptions?.maxRetries ?? 5,
});
logger.debug(`Transaction sent: ${signature}`);
// Wait for transaction confirmation
await connection.confirmTransaction(
{
signature,
blockhash,
lastValidBlockHeight,
},
txOptions?.confirmationCommitment ?? ("confirmed" as Commitment)
);
logger.debug(`Transaction confirmed: ${signature}`);
return signature;
} catch (error) {
throw enhanceError(error, {
operation: operationName,
...errorContext,
});
}
}