What is Transaction Simulation?

Learn what transaction simulation is, how it works on blockchain systems, why wallets use it for security, and where its guarantees break down.

Sara ToshiMar 21, 2026
Summarize this blog post with:
What is Transaction Simulation? hero image

Introduction

Transaction simulation is the practice of executing a proposed blockchain transaction against a chosen snapshot of chain state before broadcasting it, so you can inspect what it is expected to do without committing it on-chain. It exists because blockchains are unusually unforgiving interfaces: once a transaction is signed and included, the important question is no longer "what did I mean to do?" but "what did the bytecode actually do?" Simulation is the tool that tries to answer that question early enough to matter.

The need is easy to see if you compare modern smart contract transactions with simpler payments. A plain transfer says, in effect, "move this amount from A to B." A contract interaction says something more like, "call this program with these inputs, let it call other programs, let those programs emit events, update balances and storage according to the current state, and if anything fails, revert according to the execution rules of this chain." Humans do not reliably infer those consequences from calldata, ABI labels, or a dapp button that says Swap or Mint. Simulation exists to turn opaque intent into an inspectable forecast.

That forecast is valuable for both security and correctness. wallets use it to warn users about suspicious asset drains, unexpected approvals, or failing transactions. Developers use it to inspect internal execution traces, decoded logs, gas or resource needs, and multi-step transaction flows before sending anything real. On Ethereum-family chains, the basic off-chain primitive is eth_call, which executes a message call without creating a transaction on-chain, and eth_estimateGas, which estimates gas needed without adding the transaction to the blockchain. Higher-level simulation systems build on those primitives to produce friendlier outputs like asset changes, decoded traces, and bundle execution previews.

The central idea is simple, but the details matter: simulation is not prophecy. It is counterfactual execution against a specified state snapshot. If the state used for the preview differs from the state at real execution time, the result can change. If the simulator does not model the environment faithfully, a malicious contract may detect the difference and behave nicely only during simulation. Understanding transaction simulation means understanding both why it is so useful and why its guarantees are conditional.

How does transaction simulation run a transaction without committing state?

At a first-principles level, transaction simulation works because smart contract execution is, within a chosen environment, just computation. A blockchain node already knows how to process a transaction: load the relevant account state, execute code instruction by instruction, track calls, storage writes, logs, gas or resource use, and either commit the resulting state changes or discard them if execution reverts. Simulation reuses almost that same machinery, but stops short of consensus inclusion and persistent state update.

On Ethereum, eth_call is the clearest expression of this idea. It executes a message call immediately without creating a transaction on the blockchain. That means the node can tell you what the call would return, whether it would revert, and (if the tooling is richer) what internal calls and logs would appear along the way. eth_estimateGas uses a similar idea for a narrower question: how much gas is likely needed for the transaction to complete. In both cases, the transaction is not added to the chain.

That “not added” part is the invariant that makes simulation safe to use repeatedly. You can ask, “What happens if this transaction runs?” without paying finality costs or changing shared state. But to answer that question meaningfully, the node still needs all the inputs that would matter during real execution: the transaction fields such as from, to, data or input, value, fee fields, and often a block context such as latest, pending, safe, finalized, or a specific block number or hash depending on the chain and RPC method.

The block context is not a minor parameter. It defines which world you are simulating in. If a token balance changed one block ago, or a storage slot was updated in the mempool but not yet finalized, simulation results may differ depending on whether you ask for latest, pending, or a finalized state. On Ethereum RPC methods, the block parameter determines the height or tag of the state used for execution. On Solana, analogous tradeoffs appear through commitment levels such as processed, confirmed, and finalized, which choose how recent and how rollback-resistant the queried bank state is. Different chains expose the choice differently, but the underlying issue is the same: simulation always means “simulate relative to this state.”

What information does a transaction simulation reveal?

ViewShowsBest forLimitations
Top-level successreturn value or revertquick failure checksmisses internal transfers
Asset changestoken and native deltasend-user value impactmay hide call paths
Execution tracesinternal calls and decoded logsdeveloper or auditor debuggingtoo technical for end users
Figure 177.1: Simulation views: asset changes vs execution traces

A common misunderstanding is to treat simulation as a yes-or-no answer: safe or unsafe, success or failure. In reality, simulation is useful because it can surface several layers of information at once.

At the most basic level, it can tell you whether execution succeeds or reverts. Ethereum execution APIs specify that eth_call can return raw hex-encoded bytes on success, and if execution reverts it returns an error with raw EVM revert data. That alone is already helpful: a wallet can stop a user from submitting a transaction that is very likely to fail, and a developer can decode the revert path before wasting fees.

But the more important security value usually lies deeper than the top-level success bit. A transaction can “succeed” while doing something the user did not intend: granting a token approval, moving a different asset than expected, calling into a malicious helper contract, or making an internal transfer hidden behind a trusted front-end label. This is why modern simulation tools emphasize state changes and execution traces. Alchemy’s simulation APIs, for example, distinguish between an Asset Changes view, which returns a full list of asset changes from a simulated transaction, and an Execution Simulation view, which returns decoded execution traces and decoded logs. Those are different lenses on the same computation: one answers “what value moved?” and the other answers “how did the program get there?”

This distinction matters because each view compresses complexity differently. Asset changes are closer to what an end user cares about: “Will I lose 2 ETH and receive this token?” Execution traces are closer to what a developer, auditor, or advanced wallet needs: “Which contracts were called, in what structure, with what decoded methods and outputs?” A simulation that shows only logs but not internal calls may miss the path that produced the result. A simulation that shows only low-level calls but not summarized asset flows may overwhelm the user. Good systems often compute the same execution once and present different summaries for different readers.

How can simulation reveal malicious swaps or hidden approvals?

Imagine a user visiting a site that claims to offer a token swap. The wallet prompt shows a call to a router contract with opaque calldata. The front end labels it as a swap from token X to token Y, and perhaps that is even what the top-level contract method is named. Without simulation, the user is largely trusting labels.

Now run the transaction through simulation. The first thing the simulator does is execute the call against the selected chain state. During execution, it records internal calls: perhaps the router calls token X’s transferFrom, then approves another contract, then calls an aggregator, which in turn calls a token that emits a standard Transfer event, and finally returns. If the route is legitimate, the asset-change summary might show token X leaving the user and token Y arriving, with perhaps an approval or fee transfer that matches expectations.

But if the transaction is malicious, the same mechanism reveals that too. The trace might show an unexpected call to a token approval function granting a large allowance to a third-party contract. The asset-change view might show the user transferring an NFT or sending native currency without receiving the promised output. If the contract is a honeypot pattern, simulation of the sell path can reveal that the transaction reverts or that the exit path is blocked. This is why transaction simulation directly mitigates risks such as smart contract risk and honeypot tokens: it forces the transaction to reveal its execution behavior before the user commits.

Notice what made this possible. The simulator did not “understand” the dapp’s marketing language. It simply ran the code in a controlled environment and inspected the consequences. That is the heart of transaction simulation: not semantic trust, but mechanical preview.

When should you simulate bundles or multi-step transactions?

Single-transaction simulation is often not enough because many real workflows are stateful sequences. A liquidation bot may need to test whether one transaction changes state so that a second transaction becomes profitable. A wallet may want to understand a batched interaction routed through a multicall contract. A searcher or arbitrage system may care not about one call in isolation but about an ordered set of calls applied one after another.

This is why higher-level systems expose bundle simulation. Alchemy’s bundle endpoint simulates multiple transactions sequentially. Mechanically, the reason is straightforward: after the first simulated transaction executes, its resulting state becomes the starting state for the second simulated transaction, and so on through the bundle. The simulator still does not commit anything to the real chain, but it does maintain an internal hypothetical state trajectory. That lets the caller ask a more realistic question: “If these transactions happened in this order, what would the later ones see?”

The same pattern appears beyond Ethereum-style systems. In Stellar’s simulateTransaction flow for Soroban, simulation is used not only to see whether a contract invocation would succeed, but to compute the effective transaction data, required authorizations, ledger footprint, and minimal resource fee. There the issue is not just “will it run?” but also “what state entries will it touch, and what resource envelope must the transaction declare?” The platform-specific details differ, but the role of simulation is the same: discover execution consequences before submission so that the submitted transaction can be assembled correctly.

Why should wallets use simulation as a security control?

It is tempting to think of simulation as a debugging tool that wallets later adopted. The security perspective is stronger than that. Simulation is a control against interface opacity.

Blockchain systems ask users to authorize low-level actions whose true effects often depend on code they did not write, state they do not see, and call paths they cannot inspect manually. That combination is exactly where social engineering thrives. A malicious dapp can present a friendly label, but the signed payload is what matters. Simulation narrows the gap between those two things by showing likely consequences before approval.

Alchemy’s documentation states the security benefit plainly: simulating a transaction before wallet approval helps prevent unwanted hacks or theft by revealing exactly what assets will be transferred, what logs will be emitted, and what internal calls will occur. That is a strong practical summary of why wallets increasingly integrate simulation into confirmation flows. The same idea also extends to wallet extensions and plugins. MetaMask Snaps, for example, provide surfaces for transaction insights in the confirmation window, which is exactly where simulation results become actionable for users.

There is also a subtle but important shift in user trust. Without simulation, a wallet confirmation often says little more than “call contract 0x... with data 0x... .” With simulation, the wallet can say something more like “this transaction is expected to transfer these assets, emit these logs, and interact with these contracts.” That does not make the wallet omniscient, but it changes the decision from blind signing to inspected signing.

How does snapshot freshness affect simulation reliability?

The most fundamental limitation is TOCTOU: time-of-check versus time-of-use. A simulator evaluates the transaction against some snapshot of state. The real transaction executes later, possibly in a different state. If the relevant balances, reserves, prices, storage slots, or ordering conditions change in between, the real result may differ.

This is not a bug in the idea; it is a consequence of what simulation is. It answers a counterfactual question: “What would happen if this transaction executed in this state?” For a static read-only query, that can be very reliable. For a swap on a fast-moving AMM, it can be only conditionally informative. The ZenGo white paper highlights this clearly: simulation of a Uniswap-style transaction can diverge from eventual execution when rates change between preview and inclusion.

This is why block or commitment selection matters so much. Using a fresher state such as latest or pending can make the preview more relevant to near-term execution, but often less stable or less reproducible. Using finalized or safe can make the state more trustworthy, but potentially less reflective of what will exist when the transaction lands. There is no universal best choice; the right setting depends on whether the application values freshness, reproducibility, or rollback resistance more.

It also explains why gas and fee estimates are estimates. Ethereum’s JSON-RPC documentation explicitly notes that eth_estimateGas may significantly exceed actual gas used for various reasons including EVM mechanics and node performance, and some clients treat limits differently. In other words, simulation frequently gives you the right kind of answer but not a perfect guarantee of the exact observed cost or outcome.

Can a contract detect simulation and give fake results?

Detection signalHow exploitedMitigation
Special variablescontract checks coinbase or timestamp defaultsinitialize realistic block header values
Unset environment fieldsbranch on zero or dummy valuespopulate environment fields from chain
Gas or timing differencesdifferent gas semantics or timing observeduse pending state or bundle simulation
Missing external dataoracle or randomness absent in previewsupply realistic oracle values or overrides
Figure 177.2: How contracts detect simulation (and mitigation)

A more surprising limitation is that a malicious contract may behave differently under simulation than on-chain if the simulator exposes detectable environmental differences. This is the logic behind red pill attacks.

The attack surface comes from the fact that contract execution depends not only on explicit transaction inputs but also on environmental values: block number, timestamp, block.coinbase or proposer address, base fee, randomness-related fields, and other chain-specific globals. If a simulator leaves these values unset, uses dummy placeholders like zero, or otherwise fails to mirror realistic blockchain conditions, the contract can test those values and branch on them. During simulation it presents benign behavior; during real execution it turns malicious.

ZenGo’s disclosure describes this class of attack and provides a concrete COINBASE example. In the exploit pattern, the contract checks whether block.coinbase is a null address, which may happen in a poorly initialized simulation environment. If so, it returns a fake profitable result to the wallet preview. On-chain, where block.coinbase is an actual miner or proposer address, the same contract follows the real malicious path and drains funds instead. The user sees a comforting simulation and signs the transaction.

This is a profound lesson about transaction simulation. The threat is not only stale state; it is fidelity of the execution environment. A simulator is trustworthy only to the extent that it reproduces the semantics the contract can observe. Tenderly’s mitigation advice reflects exactly this point: initialize special variables with meaningful blockchain-derived values rather than arbitrary defaults, and allow block-header overrides where needed so simulations are not trivially distinguishable from real execution.

The analogy here is a flight simulator. It explains why environment fidelity matters: if the simulator omits wind or instrument noise, pilots may train on conditions the aircraft will never actually face. But the analogy fails in one crucial way. A pilot is not trying to deceive the simulator. A malicious contract sometimes is. In transaction simulation, the environment is not just there to improve realism; it is part of the attack surface.

What risks or actions can simulation fail to detect?

Another important boundary is that simulation is strongest when the object being evaluated is an actual transaction or executable call. It is weaker for authorizations that are not immediately executed on-chain.

ZenGo points out that offline signatures such as permits or marketplace listing signatures do not fit the same model. If the user signs a buffer today that someone else may submit later in a different context, there is no single immediate execution to simulate in the ordinary sense. The signature may authorize future behavior whose exact transaction, counterparty, price, or timing is not fixed at signing time. Wallets can still analyze the message structure and warn about permissions, but that is not the same as simulating a concrete state transition.

A related issue is visibility. Some simulation systems infer user-facing consequences by decoding standard events such as Transfer and Approval. That is useful, but not complete. Non-standard contracts may encode important effects without standard event patterns, or they may use proprietary state changes that matter economically but are not obvious from transfer logs alone. This is why low-level traces and state-diff style views remain important: logs are evidence of execution, but not the whole execution.

How can you verify the state used by a remote simulator?

ApproachWhat it verifiesCost/complexityBest for
State proofs (ethgetProof)account and storage Merkle proofsmoderate; needs a trusted anchorproof-backed verification
Run your own nodefull local state and executionhigh; operational overheadmaximum trust
Cross-provider checksconsistency across independent nodeslow; minimal setupdetect provider faults
Light client / trusted anchorblock header authenticitymedium; client support requiredmobile or light clients
Figure 177.3: How to verify simulation state

So far, the discussion has assumed you trust the node or service performing the simulation. In practice, that is another layer of risk. If a remote provider lies about the underlying state or the simulation result, how could a wallet or application detect it?

One partial answer comes from state proofs. EIP-1186 defines eth_getProof, an RPC method that returns account and storage values together with Merkle proofs. Combined with a trusted block header’s stateRoot, those proofs let an external party verify that specific state values were really part of Ethereum state at that block. This does not magically prove the full simulator ran correctly, but it can reduce blind trust in the state snapshot being reported.

The mechanism is straightforward. If you trust a block hash or block header, and you can fetch proofs for the accounts and storage slots relevant to your simulation, you can verify locally that the remote node’s reported state matches the committed state root. Tooling such as eth-proof was built around this idea: request data and proofs from an RPC provider, then verify the response against a trusted block hash before using it. The caveat is equally important: proofs are only meaningful relative to an anchor you already trust. A centralized service can forge a “proof” if it also controls the claimed anchor.

This means proof-backed verification is not a complete replacement for simulation services, but it clarifies an important architectural distinction. There are two trust questions: did the simulator execute faithfully? and was the input state genuine? State proofs help with the second question. They do not fully solve the first, but they can shrink the room for deception.

How does transaction simulation differ on Ethereum, Solana, and Soroban?

Looking across chains helps separate the fundamental idea from platform conventions.

On Ethereum and other EVM chains, simulation often centers on eth_call, gas estimation, traces, logs, asset changes, and bundle sequencing. That reflects the EVM model: contract calls, internal calls, events, and gas-bounded execution.

On Solana, the language is different because the execution model is different. Clients choose commitment levels like processed, confirmed, or finalized, and RPC responses often include a context.slot telling you the slot at which the operation was evaluated. The details of bank state and rollback risk are Solana-specific, but the underlying concern is the same as Ethereum’s block tags: which state snapshot did this preview use, and how stable is it?

On Stellar’s Soroban, simulation is deeply tied to footprint discovery, required authorizations, and multidimensional resource fees. That is not a cosmetic difference. Soroban transactions must declare what ledger entries they will touch, so simulation is part of assembling a valid transaction, not merely a convenience for preflight UX. Yet even here the shared principle remains: execute the candidate action against a snapshot, inspect consequences, then submit only once you understand the needed resources and likely outcome.

These differences show what is fundamental. Transaction simulation is not “an Ethereum API feature.” It is a broader pattern for systems where execution consequences depend on current shared state and are too complex to infer safely from user intent alone.

Key takeaways: how to use transaction simulation safely

Transaction simulation is best understood as off-chain execution for prediction, not on-chain execution for commitment. It exists because smart contract transactions are too opaque and too costly to treat as black boxes. By running a candidate transaction against a chosen state snapshot, wallets and developers can preview asset movements, traces, logs, authorizations, footprints, and likely failures before real submission.

Its power comes from using the chain’s own execution rules as the source of truth. Its limits come from the same place. If the state changes before inclusion, the result may change. If the simulation environment is unrealistic, a malicious contract may detect it and lie. If the thing being signed is not an immediately executed transaction, ordinary simulation may not apply cleanly.

So the durable takeaway is this: simulation is one of the most important safety checks in modern blockchain UX, but it is a conditional forecast, not a guarantee. The right way to use it is neither blind trust nor dismissal. It is to treat simulation as a high-value preview whose reliability depends on state selection, environment fidelity, and the honesty of the infrastructure performing it.

How should I review a crypto transaction before signing it?

Review the destination, asset movement, approval scope, and fees before you sign. On Cube, check the transaction details in the review flow and use on‑chain explorer links when needed to confirm addresses and token contracts.

  1. Copy the transaction destination address and verify it on a block explorer or against a known allowlist/ENS name.
  2. Confirm the exact token contract, amount, decimals, and the quoted "min received" or slippage tolerance shown in the review.
  3. If the transaction requests an approval, set the allowance to the exact spend amount (avoid infinite approvals) or revoke/reset existing allowances before proceeding.
  4. Compare the quoted gas/fee estimate and the net amount you will receive; only sign if the fee, slippage, and destination match what you expect.

Frequently Asked Questions

What does a transaction simulation actually guarantee, and what does it not guarantee?
+
Simulation runs the transaction’s code against a chosen snapshot of chain state and shows the forecasted effects, but it does not commit or guarantee the same result on-chain — if state or environment changes between the preview and inclusion, the real execution can differ.
How does choosing 'latest', 'pending', or 'finalized' affect the usefulness of a simulation?
+
The block or commitment parameter selects which snapshot of the chain state the simulator uses; using `pending` or `latest` favors freshness (more likely to match near-term execution) while `finalized` or safer commitment levels favor reproducibility and rollback resistance, so there is a trade‑off between freshness and stability.
Can a contract tell it’s being simulated and cheat the preview?
+
Yes; a malicious contract can detect differences in simulated environment values (the ‘red pill’ class of attacks) and behave benignly during simulation while acting maliciously on-chain; mitigating this requires simulators to faithfully initialize environment globals or allow realistic block‑header overrides so simulations are not trivially distinguishable.
What information do modern simulators provide beyond 'will this transaction revert?'?
+
Simulation can report more than success/failure: it can return raw return data or revert data, decoded logs, internal call traces, and summarized asset changes — the latter two views answer different questions (how the program executed vs what value moved) and are commonly provided separately by tooling like Alchemy’s Asset Changes and Execution Simulation endpoints.
Why do simulators offer bundle or multi‑step simulation instead of only single‑transaction previews?
+
Bundle or multi‑step simulation exists because many real workflows are ordered sequences of transactions; simulators apply each transaction sequentially to an internal hypothetical state so callers can ask “what if these transactions happened in this order?” (useful for liquidation bots, multicall flows, or arbitrage testing).
Can simulation help detect malicious swaps, unexpected approvals, or honeypot tokens?
+
Yes—by executing the call and exposing internal calls and asset-change summaries a simulator can reveal unexpected approvals, transfers of different assets, or blocked sell paths (honeypot behavior), thereby surfacing smart‑contract risks that a UI label alone would hide.
How accurate are gas and fee estimates from simulation (e.g., eth_estimateGas)?
+
Gas/fee outputs are estimates, not exact guarantees: eth_estimateGas and similar APIs can significantly overestimate or sometimes be insufficient because of EVM mechanics, node behavior, and changing pending‑state or block gas limits, so wallets and dapps should treat gas results as guidance rather than a strict bound.
Can you simulate the risks of signing offline permits or marketplace listing signatures?
+
Simulation is weaker for offline signatures or permits because those signatures authorize future or externally constructed transactions that have no single, immediate execution snapshot to run against; wallets can analyze the signed payload for permissions but cannot fully simulate the unspecified future use context.
If I don’t trust a simulation provider, how can I verify the state it used for the preview?
+
You can reduce trust in a remote simulator’s reported state by requesting Merkle proofs for account and storage values (e.g., eth_getProof / EIP‑1186) and verifying them against a trusted block header, but proofs only vouch for the reported state relative to that anchor and do not by themselves prove the simulator executed correctly.
Is transaction simulation the same on Ethereum, Solana, and Soroban, or are there important differences?
+
The core idea of simulating execution is the same across chains, but the APIs and important parameters differ: EVM chains use eth_call/gas estimates and traces, Solana exposes commitment levels and slot contexts, and Soroban (Stellar) ties simulation to ledger‑footprint discovery and resource budgeting — in each case the key question remains which state snapshot was used and how rollback‑prone it is.

Related reading

Keep exploring

Your Trades, Your Crypto