Parameters
string
required
Transaction to simulate, as a base-64 encoded string
object
Configuration object containing:
boolean
If true, verify transaction signatures
string
Commitment level (processed, confirmed, finalized)
string
Encoding format for the transaction (base58, base64, json)
boolean
If true, replace the transaction’s recent blockhash with the most recent blockhash
object
number
The minimum slot that the request can be evaluated at
Response
object
Object containing:
string | null
Error if transaction simulation failed, null if simulation succeeded
array
Array of log messages the transaction instructions output during execution
array
Array of accounts with their data (if requested)
number
Number of compute units consumed by the transaction
object
Program return data from the simulation
Code Examples
Basic Request
curl https://fra.rpc.orbitflare.com?api_key=YOUR-API-KEY -X POST -H "Content-Type: application/json" -d '{
"jsonrpc": "2.0",
"id": 1,
"method": "simulateTransaction",
"params": [
"4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaBCncVG7BFggS8w9snUts67BSh3EqKpXLUm5UMHfD7ZBe9GhARjbNQMLJ1QD3Spr6oMTFNhyKNMr3WNFCrXgDS7uV7u",
{
"sigVerify": false,
"commitment": "confirmed",
"encoding": "base64"
}
]
}'
Using web3.js
import { Connection, Transaction, PublicKey, SystemProgram } from '@solana/web3.js';
const connection = new Connection('https://fra.rpc.orbitflare.com?api_key=YOUR-API-KEY');
// Create and simulate transaction
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: new PublicKey('83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri'),
toPubkey: new PublicKey('J7rBdM6AecPDEZp8aPq5tPmsPzPhQG4HD6YtAcQBDfJj'),
lamports: 1000000000
})
);
const simulation = await connection.simulateTransaction(transaction);
console.log('Simulation result:', simulation);
// Simulate transaction with analysis
async function simulateTransactionWithAnalysis(
transaction: Transaction,
config: {
sigVerify?: boolean;
commitment?: string;
replaceRecentBlockhash?: boolean;
}
) {
const simulation = await connection.simulateTransaction(transaction, config);
return {
simulation: {
success: !simulation.value.err,
error: simulation.value.err,
logs: simulation.value.logs,
unitsConsumed: simulation.value.unitsConsumed
},
transaction: {
recentBlockhash: transaction.recentBlockhash,
feePayer: transaction.feePayer?.toBase58(),
instructions: transaction.instructions.length
},
metadata: {
timestamp: Date.now(),
commitment: config.commitment
}
};
}
Notes
- Simulates sending a transaction without actually sending it
- The response includes execution logs and errors
- The simulation is performed on the current state
- No state changes are persisted
- Useful for testing and debugging transactions
Best Practices
- Use simulation before sending real transactions
- Check compute unit consumption
- Analyze program logs for errors
- Verify account states after simulation
- Handle simulation errors appropriately
Common Errors
| Code | Message | Solution |
|---|---|---|
| -32601 | Method not found | Verify you’re connected to a Solana RPC node |
| -32602 | Invalid params | Check transaction format and encoding |
| -32003 | Transaction simulation failed | Verify transaction validity and account balances |
| -32004 | Blockhash not found | Use a more recent blockhash |
| -32005 | Node is behind | Try a different RPC node |
Use Cases
-
Transaction Analysis
interface TransactionAnalysis { transaction: { instructions: number; signers: number; estimatedUnits: number; }; simulation: { success: boolean; error: string | null; logs: string[]; unitsConsumed: number; }; analysis: { programInvocations: number; accountAccesses: number; errorAnalysis?: string; }; metadata: { timestamp: number; commitment?: string; }; } class TransactionAnalyzer { async analyzeTransaction( transaction: Transaction, config: { sigVerify?: boolean; commitment?: string; } ): Promise<TransactionAnalysis> { const simulation = await connection.simulateTransaction(transaction, config); const logs = simulation.value.logs || []; const programInvocations = logs.filter(log => log.includes('Program') && log.includes('invoke') ).length; const accountAccesses = logs.filter(log => log.includes('Account') || log.includes('Token') ).length; let errorAnalysis; if (simulation.value.err) { errorAnalysis = this.analyzeError(simulation.value.err); } return { transaction: { instructions: transaction.instructions.length, signers: transaction.signatures.length, estimatedUnits: simulation.value.unitsConsumed || 0 }, simulation: { success: !simulation.value.err, error: simulation.value.err, logs, unitsConsumed: simulation.value.unitsConsumed || 0 }, analysis: { programInvocations, accountAccesses, errorAnalysis }, metadata: { timestamp: Date.now(), commitment: config.commitment } }; } private analyzeError(error: any): string { if (typeof error === 'string') { if (error.includes('insufficient funds')) { return 'Transaction failed due to insufficient funds'; } if (error.includes('invalid account owner')) { return 'Transaction failed due to invalid account ownership'; } if (error.includes('account not found')) { return 'Transaction failed due to missing account'; } } return 'Unknown error occurred during simulation'; } } -
Transaction Validation
interface TransactionValidation { transaction: { signature: string; blockhash: string; feePayer: string; }; checks: Array<{ name: string; passed: boolean; details?: string; }>; recommendations: Array<{ type: 'fix' | 'warning' | 'info'; message: string; }>; metadata: { timestamp: number; }; } class TransactionValidator { private readonly maxUnits = 200000; private readonly minAccountRent = 890880; async validateTransaction( transaction: Transaction, config: { sigVerify?: boolean; commitment?: string; } ): Promise<TransactionValidation> { const simulation = await connection.simulateTransaction(transaction, config); const checks: Array<{ name: string; passed: boolean; details?: string; }> = []; const recommendations: Array<{ type: 'fix' | 'warning' | 'info'; message: string; }> = []; // Check compute units const unitsConsumed = simulation.value.unitsConsumed || 0; checks.push({ name: 'Compute Units', passed: unitsConsumed <= this.maxUnits, details: `${unitsConsumed} units consumed` }); if (unitsConsumed > this.maxUnits) { recommendations.push({ type: 'fix', message: 'Transaction exceeds compute unit limit' }); } // Check for errors checks.push({ name: 'Simulation', passed: !simulation.value.err, details: simulation.value.err?.toString() }); if (simulation.value.err) { recommendations.push({ type: 'fix', message: `Fix simulation error: ${simulation.value.err}` }); } // Analyze logs const logs = simulation.value.logs || []; checks.push({ name: 'Program Execution', passed: logs.some(log => log.includes('Program log:')), details: 'Program execution logs present' }); // Check account rent const rentWarnings = logs.filter(log => log.includes('insufficient lamports for rent') ); if (rentWarnings.length > 0) { checks.push({ name: 'Account Rent', passed: false, details: 'Insufficient lamports for rent' }); recommendations.push({ type: 'fix', message: `Ensure accounts have minimum rent: ${this.minAccountRent} lamports` }); } return { transaction: { signature: transaction.signatures[0]?.signature?.toString() || '', blockhash: transaction.recentBlockhash || '', feePayer: transaction.feePayer?.toBase58() || '' }, checks, recommendations, metadata: { timestamp: Date.now() } }; } } -
Transaction Optimization
interface TransactionOptimization { original: { instructions: number; unitsConsumed: number; }; optimized: { instructions: number; unitsConsumed: number; savings: number; }; changes: Array<{ type: 'merge' | 'remove' | 'reorder'; description: string; impact: number; }>; metadata: { timestamp: number; }; } class TransactionOptimizer { async optimizeTransaction( transaction: Transaction ): Promise<TransactionOptimization> { // Simulate original transaction const originalSimulation = await connection.simulateTransaction(transaction); const originalUnits = originalSimulation.value.unitsConsumed || 0; const changes: Array<{ type: 'merge' | 'remove' | 'reorder'; description: string; impact: number; }> = []; // Create optimized transaction const optimizedTransaction = new Transaction(); const instructions = [...transaction.instructions]; // Analyze and merge similar instructions const mergedInstructions = this.mergeInstructions(instructions); if (mergedInstructions.length < instructions.length) { changes.push({ type: 'merge', description: `Merged ${instructions.length - mergedInstructions.length} similar instructions`, impact: 0 // Will be updated after simulation }); } // Remove redundant instructions const cleanedInstructions = this.removeRedundantInstructions(mergedInstructions); if (cleanedInstructions.length < mergedInstructions.length) { changes.push({ type: 'remove', description: `Removed ${mergedInstructions.length - cleanedInstructions.length} redundant instructions`, impact: 0 }); } // Reorder instructions for optimal execution const orderedInstructions = this.reorderInstructions(cleanedInstructions); changes.push({ type: 'reorder', description: 'Reordered instructions for optimal execution', impact: 0 }); // Add optimized instructions orderedInstructions.forEach(instruction => { optimizedTransaction.add(instruction); }); // Simulate optimized transaction const optimizedSimulation = await connection.simulateTransaction(optimizedTransaction); const optimizedUnits = optimizedSimulation.value.unitsConsumed || 0; // Calculate impacts const totalSavings = originalUnits - optimizedUnits; changes.forEach(change => { change.impact = Math.floor(totalSavings / changes.length); }); return { original: { instructions: instructions.length, unitsConsumed: originalUnits }, optimized: { instructions: orderedInstructions.length, unitsConsumed: optimizedUnits, savings: totalSavings }, changes, metadata: { timestamp: Date.now() } }; } private mergeInstructions( instructions: Array<any> ): Array<any> { // Implementation would analyze and merge similar instructions // This is a placeholder that returns the original instructions return instructions; } private removeRedundantInstructions( instructions: Array<any> ): Array<any> { // Implementation would identify and remove redundant instructions // This is a placeholder that returns the original instructions return instructions; } private reorderInstructions( instructions: Array<any> ): Array<any> { // Implementation would reorder instructions for optimal execution // This is a placeholder that returns the original instructions return instructions; } }