/** * Transaction Simulation Utilities * * Provides compute unit estimation via transaction simulation. * Industry best practice: simulate first, then add 10% buffer. */ import { Connection, Transaction, VersionedTransaction } from "@solana/web3.js"; export interface SimulationResult { computeUnits: number; error?: string; } /** * Simulate transaction to estimate compute units * Returns actual units + 10% buffer (industry standard) * * @param connection - Solana connection * @param transaction - Transaction to simulate * @param fallbackUnits - Fallback value if simulation fails (default: 200,000) * @returns Estimated compute units with 10% buffer * * @example * ```typescript * const tx = new VersionedTransaction(...); * const estimatedCU = await simulateComputeUnits(connection, tx); * // Use estimatedCU to set compute unit limit * ``` */ export async function simulateComputeUnits( connection: Connection, transaction: Transaction | VersionedTransaction, fallbackUnits: number = 200_000 ): Promise { try { // simulateTransaction has different overloads for Transaction and VersionedTransaction // We need to handle each type separately to satisfy TypeScript const sim = transaction instanceof VersionedTransaction ? await connection.simulateTransaction(transaction, { sigVerify: false, commitment: "confirmed", }) : await connection.simulateTransaction(transaction, [], false); if (sim.value.err) { console.warn("[simulateComputeUnits] Simulation error:", sim.value.err); return fallbackUnits; } const unitsConsumed = sim.value.unitsConsumed || fallbackUnits; // Add 10% buffer (best practice from Anza/Solana core team) const bufferedUnits = Math.ceil(unitsConsumed * 1.1); return bufferedUnits; } catch (error) { console.warn("[simulateComputeUnits] Simulation failed:", error); return fallbackUnits; } }