Skip to main content

simulateTransaction

Simulate sending a transaction

Common use cases
Pre-flight transaction validationTest transaction logic and program behavior without broadcasting to network or consuming fees. Catch instruction errors, account access violations, and compute limit issues before submission to prevent wasted transaction costs.
Compute budget estimationDetermine exact compute units consumed by transaction execution. Essential for setting appropriate ComputeBudgetProgram limits—real-world pattern adds 10-20% buffer to simulation result for production transactions.
Wallet transaction previewDisplay expected balance changes and account state mutations to users before transaction approval. Requires fetching pre-simulation account states separately and comparing with simulation results to calculate deltas.
Program development debuggingInspect detailed program logs and account state changes during smart contract development without deploying to devnet. Use sigVerify:false to test logic without signature requirements.

Parameters

transaction (string, required)

Transaction, as an encoded string. The transaction must have a valid blockhash, but is not required to be signed.

config (object, optional)

Configuration object containing the following fields:

Fields:

  • commitment (string): Commitment level to simulate the transaction at. See Configuring State Commitment. Default finalized.
  • encoding (string): Encoding used for the transaction data. Values: base58 (slow, DEPRECATED), or base64.
  • replaceRecentBlockhash (bool): If true the transaction recent blockhash will be replaced with the most recent blockhash (conflicts with sigVerify)
  • sigVerify (bool): If true the transaction signatures will be verified (conflicts with replaceRecentBlockhash)
  • minContextSlot (number): The minimum slot that the request can be evaluated at
  • innerInstructions (bool): If true the response will include inner instructions. These inner instructions will be jsonParsed where possible, otherwise json.
  • accounts (object): Accounts configuration object containing the following fields:
    • addresses: An array of accounts to return, as base-58 encoded strings
    • encoding: Encoding for returned Account data. Note: jsonParsed encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If jsonParsed is requested but a parser cannot be found, the field falls back to base64 encoding, detectable when the returned accounts.data field is type string.

Request

curl https://solana-mainnet.api.syndica.io/api-key/YOUR_API_KEY \
-X POST \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "simulateTransaction",
"params": [
"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEEjNmKiZGiOtSZ+g0
{
"commitment": "confirmed",
"encoding": "base64",
"replaceRecentBlockhash": true
}
]
}'
Network Selection

Replace mainnet with devnet in the URL to query devnet instead.

Response

{
"jsonrpc": "2.0",
"result": {
"context": {
"apiVersion": "2.3.3",
"slot": 393226680
},
"value": {
"accounts": null,
"err": null,
"innerInstructions": null,
"loadedAccountsDataSize": 413,
"logs": [
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [1]",
"Program log: Instruction: Transfer",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1714 of 200000 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success"
],
"replacementBlockhash": {
"blockhash": "6oFLsE7kmgJx9PjR4R63VRNtpAVJ648gCTr3nq5Hihit",
"lastValidBlockHeight": 381186895
},
"returnData": null,
"unitsConsumed": 1714
}
},
"id": 1
}

Response Fields

accounts (array|null)

Array of accounts with the same length as the accounts.addresses array in the request. Each element is either:

  • null - if the account doesn't exist or if err is not null
  • An object containing:
  • lamports: <u64> - number of lamports assigned to this account
  • owner: <string> - base-58 encoded Pubkey of the program this account has been assigned to
  • data: <[string, encoding]|object> - data associated with the account, either as encoded binary data or JSON format {<program>: <state>}
  • executable: <bool> - boolean indicating if the account contains a program
  • rentEpoch: <u64> - the epoch at which this account will next owe rent

err (object|string|null)

Error if transaction failed, null if transaction succeeded. See TransactionError definitions

innerInstructions (object|undefined)

Defined only if innerInstructions was set to true. The value is a list of inner instructions.

loadedAccountsDataSize (u32|undefined)

The number of bytes of all accounts loaded by this transaction

logs (array|null)

Array of log messages the transaction instructions output during execution, null if simulation failed before the transaction was able to execute

replacementBlockhash (object|null)

The blockhash used to simulate the transaction, containing:

  • blockhash: <string> - the blockhash used to simulate the transaction
  • lastValidBlockHeight: <u64> - the last valid block height at which the blockhash is valid

returnData (object|null)

The most-recent return data generated by an instruction in the transaction, containing:

  • programId: <string> - the program that generated the return data, as base-58 encoded Pubkey
  • data: <[string, encoding]> - the return data itself, as base-64 encoded binary data

unitsConsumed (u64|undefined)

The number of compute budget units consumed during the processing of this transaction

FAQ and Troubleshooting

Why doesn't simulateTransaction return balance changes directly?

The method returns post-execution account states in the accounts array. To calculate balance changes, you must fetch account states before simulation using getAccountInfo and manually compare the lamports field or token balances (bytes 64-72 for SPL tokens).

How do I simulate a transaction without triggering wallet signature prompts?

Set "sigVerify": false in the config options. This skips signature verification and allows simulation without valid signatures—essential for UI previews and testing scenarios where you don't have access to private keys.

Why do I only see some accounts in the simulation result?

You must specify which accounts you want in the response using the accounts.addresses config array. Without this parameter, only accounts directly written to by the transaction are returned—accounts that are only read will not appear.

Can simulateTransaction override account balances for testing scenarios?

No, the current implementation always uses actual on-chain state. You cannot simulate with arbitrary token balances or modified account data—simulation reflects the real current state of accounts.

Does simulation guarantee the same result when I send the transaction?

No. Blockchain state can change between simulation and execution. Use simulation for pre-flight validation and estimation, but understand that network conditions, account states, or slot context may differ during actual execution.

sendTransaction
Broadcasts transactions to network after simulation validates logic. Standard workflow: simulate first to catch errors and estimate compute units, then send with appropriate compute budget limits.

getAccountInfo
Fetches account state before simulation to enable balance change calculations. simulateTransaction returns post-execution state only—compare with getAccountInfo results to determine deltas.

getFeeForMessage
Estimates transaction fees based on message content. Use together with simulateTransaction's unitsConsumed to calculate total transaction cost including priority fees.

getLatestBlockhash
Provides valid recent blockhash required for transaction construction. When simulating, set replaceRecentBlockhash:true to bypass blockhash expiration validation.

getRecentPrioritizationFees
Returns recent priority fees from network. Combine with simulateTransaction's compute unit estimates to set optimal ComputeUnitPrice for transaction landing success.

External Resources