DEV Community

Version 6 LLC
Version 6 LLC

Posted on • Originally published at immute.io

BUY_LOCK_BLOCKS: How Immute Blocks Same-Block Sandwich Attacks

In decentralized finance, few attack vectors are as well-documented—and yet as persistently exploitable—as the sandwich attack. When a victim's trade sits in the public mempool, opportunistic miners or MEV bots can exploit transaction ordering to extract value at the expense of the honest trader. For bonding-curve reward tokens like Immute, where every buy and sell distributes fees pro-rata to holders, this vulnerability is particularly acute. If attackers can reliably sandwich-protect their own trades while sandwiching others, they effectively skim value from the holder community without contributing fairly to the ecosystem. This article examines Immute's per-address buy-lock window mechanism—a smart contract sandwich attack prevention technique that forces would-be sandwichers to wait before executing the sell side of their attack, neutralizing same-block profitability and restoring fair execution order.

Understanding the Sandwich Attack Vector

A sandwich attack operates by exploiting the transparent nature of the public mempool. The attacker monitors the pending transaction pool for victims submitting swaps, particularly large ones that will meaningfully shift pool reserves. When detected, the attacker executes two transactions in rapid succession: a front-run buy that inflates the token price, followed by a back-run sell that captures the victim's slippage-induced price movement [1][3][4][5].

In AMM-based DEXs like Uniswap, a victim's large swap shifts pool reserves according to the constant product formula (x · y = k), creating measurable price impact. The attacker exploits this by placing their buy transaction with a higher gas fee, ensuring it executes immediately before the victim's trade, and their sell transaction immediately after, harvesting the spread [5][7]. Traditional prevention strategies have focused on private order flow, batch auctions, and slippage tolerance warnings—but these are user-side mitigations that don't fundamentally alter contract-level vulnerabilities.

The Per-Address Buy-Lock Window: A Contract-Level Defense

Immute implements a smart contract sandwich attack prevention mechanism that operates at the protocol level rather than relying on off-chain ordering solutions. The core innovation is the per-address buy-lock window, which enforces a cooldown period after any purchase, preventing the same address from immediately executing a sell.

The mechanism centers on two storage variables: a lockedUntil mapping that records the timestamp when an address's lock expires, and an isLocked() view function that returns whether a given address is currently prevented from selling. When a user buys IMT, the contract sets lockedUntil[msg.sender] = block.timestamp + LOCK_WINDOW, where LOCK_WINDOW is a protocol-defined duration—sufficiently long to prevent same-block exploitation but short enough to preserve liquidity access for legitimate traders.

The sell function includes a guard clause that queries isLocked(msg.sender) and reverts if true. This means that after buying, a user cannot sell back through the contract until the lock window expires—even if they submit the transaction in the same block. The critical insight is that block.timestamp is consistent within a block, so an attacker attempting to front-run-buy and back-run-sell within the same block will find their sell reverted by the lock check, even though the timestamps appear identical from the transaction ordering perspective.

Mechanics: Same-Block Prevention in Practice

Consider a concrete attack scenario demonstrating why the per-address buy-lock window constitutes effective smart contract sandwich attack prevention:

The victim submits a buy transaction to an AMM pool. The attacker's MEV bot detects this pending transaction and constructs a sandwich in the same block. The attacker first executes a buy transaction—which sets lockedUntil[attacker] = block.timestamp + WINDOW. The victim's transaction then executes at the now-inflated price. Finally, the attacker attempts to execute their back-run sell to capture the slippage. However, when the sell function checks isLocked(attacker), it returns true because block.timestamp < lockedUntil[attacker]. The sell reverts [2][8].

The attacker cannot bypass this check by submitting with higher gas or different ordering—the lock is enforced at the contract level and is indifferent to transaction sequencing. To successfully execute a sandwich, the attacker would need to wait through the entire lock window before selling. By that time, arbitrageurs and natural market activity have typically closed the artificial price gap, eliminating the profit opportunity that motivated the attack.

This design preserves multi-user liquidity because the lock is address-specific. Only the attacking address is locked; other participants can freely buy and sell. The mechanism targets the specific threat model of MEV bots exploiting mempool transparency without introducing friction for legitimate protocol users who don't attempt sandwich attacks [8].

Why Contract-Level Enforcement Matters

Traditional smart contract audits often focus on access control, reentrancy guards, and arithmetic overflow checks—important vulnerabilities, but they miss the off-chain ordering threats that enable MEV exploitation. Sandwich attacks are not contract bugs in the traditional sense; they're emergent behaviors from the interaction between public mempool transparency, transaction ordering economics, and AMM pricing mechanics [5].

By implementing the per-address buy-lock window at the contract level, Immute shifts the defense burden from user-side privacy solutions to protocol-level enforcement. This is a more robust approach because it doesn't require users to adopt specific wallet configurations, use privacy-preserving RPC endpoints, or understand MEV mechanics. The protection is automatic and compulsory—any address attempting a sandwich attack within the same block will be rejected, regardless of their sophistication or gas bidding power.

Implementation Considerations for Developers

Immute is live on Sepolia Testnet (chainId 11155111) for developers and security researchers to analyze and test this mechanism. The IMT V8 contract at 0xB575A8760c66F09a26A03bc215D612EA2486373C and FeederV9 at 0xa87e7c25c2f754C7D6bFc9b4472E0c36096E4bF6 are publicly verifiable on Sepolia Etherscan [5].

For developers integrating Immute or building similar defenses, several implementation details warrant attention:

The lockedUntil timestamp should be set to a duration that exceeds typical block time variance while remaining short enough to avoid liquidity lockup complaints. The choice involves tradeoff analysis: too short, and MEV bots can potentially sandwich across multiple transactions with minimal delay; too long, and legitimate traders face meaningful access friction.

The isLocked() function should be a pure view function with no gas overhead for callers—this ensures the check doesn't introduce significant gas costs for non-attacking users. The lock state should be per-address, not global, to avoid disrupting legitimate trading activity from unrelated addresses.

Finally, the mechanism should be documented and publicized. Sandwich attack profitability depends on victim unawareness; if participants understand that same-block sandwiching is prevented, rational attackers won't attempt it, and the defense becomes self-enforcing.

Looking Toward Mainnet

The per-address buy-lock window is one component of Immute's broader security architecture for a product-powered reward token. As the protocol moves toward mainnet launch—pending testnet validation—these contract-level defenses will face increased scrutiny from a live, value-bearing adversary environment.

The testnet deployment at https://immute.io invites developers to interact with the contracts, test the lock mechanism, and identify any edge cases the current implementation might miss. Free Sepolia ETH is available from faucets like https://sepolia-faucet.pk910.de/ or https://www.alchemy.com/faucets/ethereum-sepolia, removing financial barriers to participation.

For the developer community, Immute represents an opportunity to engage with novel token economics—the bonding curve's 10% fee distribution to holders, the Feeder contract's 1% on-curve routing for integrated products—while also stress-testing a practical smart contract sandwich attack prevention mechanism. The per-address buy-lock window demonstrates that protocol-level defenses against off-chain ordering threats are viable, and Immute's open testnet deployment makes this research accessible to anyone with a wallet and curiosity.

Top comments (0)