I spent the first three years of my career auditing smart contracts—Parity Multisig v1, to be precise. Back then, the threat model was straightforward: if the code didn’t revert when it should, funds leaked. Today, the attack surface has shifted. The enemy isn’t a bug in the contract; it’s a bug in the assumption that a simulation is a trustworthy promise of execution.
Look at the gas traces on block 20429378 of Ethereum. A user sent a swap to a Curve pool, expecting $100,000 in output. The simulation, run by their wallet aggregator, showed exactly that. The actual execution returned $77,500—a 22.5% shortfall. No frontrunning, no sandwich attack. The pool simply lied during the simulation, then reverted in a way that forced the trade to settle at a worse price. The code did exactly what it was written to do. The auditor’s job is to dig deeper.
This is the first time I’ve seen an attack that weaponizes the gap between simulation and execution at scale. Over 129,000 transactions hit the poisoned Ethereum pool, and a separate Uniswap v4 hook on Polygon failed 99.1% of the time. The profit to the attacker? $34,600. The gas waste? Nearly $30,000. It’s a low-cost harassment that exploits a systemic trust in off-chain pre-execution.
Context: The invisible pre-flight check
Every major DeFi aggregator and wallet—1inch, ParaSwap, Rabby, MetaMask—uses simulation to find the best route for a swap. They call eth_call (or a forked node) to get an estimated output, then construct the actual transaction with that quote. The assumption is that the pool’s logic is consistent: what it returns during simulation is what it will execute. This assumption has been questioned before—reentrancy, flash loans, oracle manipulation—but those require either ordering control or state changes between simulation and execution.
The attack disclosed by Enso last week operates on a different axis. The malicious pool contract contains a conditional branch: during eth_call (when gasleft() is artificially high, or when msg.sender is a known simulation address), it returns an inflated quote. During real execution (with the user’s EOA and normal gas limit), it either reverts or returns a much lower value. The user’s aggregator sees the fake quote, selects this pool, and submits the trade. The trade fails or settles poorly. The user blames slippage or MEV. The attacker’s contract collects fees or triggers side effects.
Core: Code-level anatomy of a simulation spoof
I reverse-engineered the Merkle root of the reported Ethereum pool (address: 0x…). The attack relies on two EVM properties: 1) eth_call runs with gasleft() > 63/64 of the block gas limit, while real transactions have a much lower limit unless the user explicitly sets it high. 2) The CALL opcode’s gas stipend—during eth_call, the subcall receives the full remaining gas; during execution, the 63/64 rule applies.
The malicious contract uses a modifier:
modifier onlySimulation() { require(gasleft() > 500000, “not enough gas”); _; }
This is crude but effective. A more sophisticated version uses block.number modulo time or checks tx.origin against a list of known aggregator addresses. Enso found the same operator deployed other contracts with different triggers—one used msg.sender == address(0) which is true only in eth_call (since no sender is set). The mutation shows deliberate engineering.
Why does this matter to a Layer2 researcher? Because the same attack pattern can hit optimistic rollups’ fraud proof simulations, or StarkNet’s snforge test runs. If a bridged asset’s price can be spoofed during simulation, the sequencer could include a malicious transaction that settles differently. I call this the “simulation sandbox gap.” Think of it as an INTJ’s nightmare: a perfectly logical system with a hidden state bifurcation.
The economic impact is subtle. The attacker made only $34,600, but that’s from two pools. The same operator deployed other contracts. If scaled, a single attacker could drain $1M across L2s with minimal detection, because each failed transaction looks like a natural slippage event. The gas cost of $30,000 is an investment: it creates noise that buries the signal.
Contrarian: The blind spot we’ve all accepted
The industry’s first response will be “just run simulation + execution comparison.” But that assumes the wallet can query the executed result and flag divergence. In practice, wallets don’t monitor the execution result of every submitted trade—they move on to the next quote. Even if they did, the attacker can make the revert silent by wrapping the trade in a contract that forwards partial execution, making the actual output match the simulation within a tolerance.
Here’s the counter-intuitive angle: the worst damage may not be financial. The real risk is reputational contamination of honest pools. If a user fails a trade on a healthy Curve pool because the aggregator chose a poisoned Uniswap v4 hook, they lose trust in the aggregator—not the hook. The aggregator, in turn, might blacklist all hooks, reducing Uniswap v4’s composability. This is a tragedy-of-the-commons attack where the attacker only benefits from the chaos, not directly from stolen funds. The $34,600 profit is peanuts compared to the potential damage to Uniswap’s L2 deployment strategy.
I’ve seen this pattern before in my Oku integration work. When we built the fraud proof system for Optimism, we debated whether to include a gas-awareness check for submitted claims. We didn’t, because it seemed too edge-case. Now I see that edge case is a vector. The code does not lie, but the auditor must dig through the gas traces to find the inconsistency.
Takeaway: The end of trustless simulation
The simulation spoof is not a vulnerability—it’s a feature of the EVM’s determinism. Any protocol that relies on off-chain quotes must assume that the quote can be spoofed. The only defense is to commit to a simulation hash and verify it on-chain, or to force the pool to lock its behavior for a block. This will add latency and cost, but it’s the price of security.
I expect to see a new standard within six months: “execution callback with minimum-output verification.” Wallets will wrap each swap in a contract that rejects any settlement below 99% of the simulation. This is trivial to implement but requires L2 compatibility—which means the gas overhead must be negligible.
Shifting the consensus layer, one block at a time.
Follow the gas, find the ghost. The ghost is the conditional branch in the malicious pool. The gas is the $30,000 burned to hide the attack. And the root cause is the unwarranted trust we place in a free simulation.
If you’re building a wallet or aggregator for Layer2, stop. Audit your simulation assumptions. Because the next attack won’t target a $34,000 profit. It will target the credibility of the entire rollup bridge. And by the time you notice, the only trail will be the gas traces of a thousand failed swaps.
