A retail swap on Ethereum mainnet was sandwiched on 2026-05-14 at block 25095209 by a same-address MEV bot operating around the WOJAK/WETH Uniswap V2 pair 0xcaa3a16f8440f85303afaab1992f2b97d12469b1. The victim transaction 0xbffc57f64535df9e495c3fc0b5a5be5a8131aa1173d64f3e3ba7c9e81edf25c9 used Uniswap’s UniversalRouter to swap 1.1240366018008159 WETH into approximately 21,581,532,459.673218 WOJAK across a mixed V2/V3 route, while the same sandwich bot contract 0x1f2f10d1c40777ae1da742455c65828ff36df387 bought before the victim at tx index 3 and sold back at tx index 5. No flawed smart-contract logic was exercised in the victim trace: the pair, router, WETH, and WOJAK token all behaved according to their expected swap semantics. The measurable harm was pure execution slippage from public-mempool ordering; on the V2 leg alone, the victim received about 1,837,162,159.530743 WOJAK less than a no-frontrun execution, equivalent to roughly 0.08816977289183164 WETH and consistent with the alert’s reported ~$201.97 loss.

Root Cause

Vulnerable Contract

No vulnerable contract is evidenced by this transaction. The key contracts in the victim trace are UniversalRouter, the WOJAK/WETH UniswapV2Pair, a UniswapV3Pool, the wojak ERC20, and canonical WETH9. All of them executed normal swap, callback, reserve, transfer, and balance-check logic. The loss came from transaction ordering in the public mempool rather than a defect in these contracts.

Vulnerable Function

No vulnerable function exists in the sense used for protocol exploit reports. The victim transaction entered UniversalRouter.execute(bytes,bytes[],uint256) (0x3593564c) and then executed a standard sequence of WETH wrap/transfer, a Uniswap V2 swap(uint256,uint256,address,bytes) (0x022c0d9f) on the WOJAK/WETH pair, and a Uniswap V3 swap(address,bool,int256,uint160,bytes) (0x128acb08) with callback uniswapV3SwapCallback(int256,int256,bytes) (0xfa461e33).

Vulnerable Code

The relevant executed code is standard AMM swap code. For the V2 pair leg, the pair simply transfers out output tokens and then updates reserves based on balances:

function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external {
    require(amount0Out > 0 || amount1Out > 0, 'INSUFFICIENT_OUTPUT_AMOUNT');
    (uint112 _reserve0, uint112 _reserve1,) = getReserves();
    require(amount0Out < _reserve0 && amount1Out < _reserve1, 'INSUFFICIENT_LIQUIDITY');

    if (amount0Out > 0) _safeTransfer(token0, to, amount0Out);
    if (amount1Out > 0) _safeTransfer(token1, to, amount1Out);

    uint balance0 = IERC20(token0).balanceOf(address(this));
    uint balance1 = IERC20(token1).balanceOf(address(this));
    _update(balance0, balance1, _reserve0, _reserve1);
}

The Universal Router dispatch path is also standard command execution rather than privileged logic:

function execute(bytes calldata commands, bytes[] calldata inputs, uint256 deadline) external payable {
    checkDeadline(deadline);
    for (uint256 commandIndex = 0; commandIndex < commands.length; commandIndex++) {
        bytes1 command = commands[commandIndex];
        bytes calldata input = inputs[commandIndex];
        _execute(command, input);
    }
}

Why It’s Vulnerable

It is not vulnerable in the smart-contract sense. The incident is a public-mempool sandwich / MEV extraction event.

Expected behavior: a user broadcasting a swap into the public mempool can be reordered around by searchers if the order exposes enough slippage and interacts with sufficiently shallow liquidity. Standard AMMs will price the swap against the reserves that exist when the transaction actually executes, not the reserves the user expected when signing.

Actual behavior: the sandwich bot contract 0x1f2f10d1c40777ae1da742455c65828ff36df387 bought 225,710,875,379.4457 WOJAK for 11.262591031834575 WETH in tx index 3, moving the WOJAK/WETH pair reserves from approximately 254.8743141546237 WETH / 5,348,955,529,701.916 WOJAK to 266.13690518645825 WETH / 5,123,244,654,322.471 WOJAK. The victim then executed their router swap at tx index 4, paying 1.067834771710775 WETH into that distorted V2 pair and receiving only 20,412,930,711.015053 WOJAK on the V2 leg. Using the pre-frontrun reserves and the same Uniswap V2 fee formula, the victim would have received about 22,250,092,870.545795 WOJAK on that leg without the frontrun. The difference, 1,837,162,159.530743 WOJAK, corresponds to approximately 0.08816977289183164 WETH of execution loss.

Normal flow: user swap executes against prevailing reserves, with the router taking the best route it is instructed to take.

Attack flow: a searcher observes the pending swap, buys first to worsen the V2 price, lets the victim trade against the inflated price, then sells back immediately after.

Attack Execution

High-Level Flow

  1. The sandwich bot EOA 0xae2fc483527b8ef99eb5d9b44875f005ba1fae13 called bot contract 0x1f2f10d1c40777ae1da742455c65828ff36df387 in tx index 3 and bought 225,710,875,379.4457 WOJAK from the WOJAK/WETH V2 pair for 11.262591031834575 WETH.
  2. The victim EOA 0xb8f01ec76a8d6bcad634d0f73ac360ce654edd41 then called UniversalRouter.execute(...) in tx index 4, wrapping WETH and buying WOJAK through a mixed route: 20,412,930,711.015053 WOJAK from the V2 pair plus 1,168,601,748.658165 WOJAK from a V3 pool.
  3. Immediately afterward, the same bot contract sold 225,710,870,657.07922 WOJAK back into the V2 pair in tx index 5 and received 11.285960468583154 WETH, unwinding the inventory at a profit.
  4. The V2 reserve sequence and the bot’s same-address same-block round trip establish a classical sandwich rather than a protocol exploit.

Detailed Call Trace

The victim trace contains 17 calls. The user enters UniversalRouter.execute(...), deposits ETH into WETH, transfers WETH into the V2 path, reads WOJAK balance and pair reserves, calls the V2 pair swap(...), then calls a secondary V3 pool swap(...) that settles via uniswapV3SwapCallback(...).

For the same-block sandwich legs, the pair receipt logs show:

  • Frontrun tx 0x914c4740...5ccd: 11.262591031834575 WETH into the pair and 225,710,875,379.4457 WOJAK out to the bot.
  • Victim tx 0xbffc57f6...25c9: 1.067834771710775 WETH into the pair and 20,412,930,711.015053 WOJAK out to the victim, plus a separate V3 output of 1,168,601,748.658165 WOJAK.
  • Backrun tx 0xa0e563ec...6d11: 225,710,870,657.07922 WOJAK back into the pair and 11.285960468583154 WETH out to the bot.

Key verified selectors:

  • execute(bytes,bytes[],uint256) -> 0x3593564c
  • swap(uint256,uint256,address,bytes) -> 0x022c0d9f
  • swap(address,bool,int256,uint160,bytes) -> 0x128acb08
  • uniswapV3SwapCallback(int256,int256,bytes) -> 0xfa461e33
  • getReserves() -> 0x0902f1ac
  • transfer(address,uint256) -> 0xa9059cbb
  • balanceOf(address) -> 0x70a08231

Financial Impact

Victim swap

The victim sent 1.1240366018008159 WETH into UniversalRouter and received approximately 21,581,532,459.673218 WOJAK total:

  • V2 pair output: 20,412,930,711.015053 WOJAK
  • V3 pool output: 1,168,601,748.658165 WOJAK

The alert’s quoted pair-only swap amount (1.067835 WETH -> 20,412,930,711.02 WOJAK) matches the V2 leg reflected in the victim receipt and trace. The additional 0.05620183009004079 WETH routed through the V3 pool produced the extra 1,168,601,748.658165 WOJAK.

Quantified sandwich damage

Using the pair reserves immediately before the frontrun but applying the same Uniswap V2 fee formula, the victim’s V2 leg should have returned about 22,250,092,870.545795 WOJAK. Instead it returned 20,412,930,711.015053 WOJAK.

  • Missing output on V2 leg: 1,837,162,159.530743 WOJAK
  • WETH-equivalent execution loss on that leg: 0.08816977289183164 WETH
  • At the alert’s pricing reference, this is approximately $201.97

Bot economics

The same sandwich bot contract performed both sides of the round trip:

  • Frontrun buy: spent 11.262591031834575 WETH, received 225,710,875,379.4457 WOJAK
  • Backrun sell: spent 225,710,870,657.07922 WOJAK, received 11.285960468583154 WETH
  • Gross WETH spread across the two V2 bot trades: 0.023369436748578828 WETH

The bot also retained a tiny residual WOJAK balance between the two legs (~4,722.366477 WOJAK) because the sell amount was slightly smaller than the buy amount.

Evidence

  • Transaction hash: 0xbffc57f64535df9e495c3fc0b5a5be5a8131aa1173d64f3e3ba7c9e81edf25c9
  • Chain: Ethereum mainnet
  • Block number: 25095209
  • Block timestamp: 2026-05-14T18:36:23Z
  • Victim EOA: 0xb8f01ec76a8d6bcad634d0f73ac360ce654edd41
  • Universal Router: 0x4c82d1fbfe28c977cbb58d8c7ff8fcf9f70a2cca
  • WOJAK token: 0x8de39b057cc6522230ab19c0205080a8663331ef
  • WETH: 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
  • WOJAK/WETH V2 pair: 0xcaa3a16f8440f85303afaab1992f2b97d12469b1
  • Secondary V3 pool: 0xa2b4bfae367ef535bd87a2684e2e51d80609b1a1
  • Sandwich bot EOA: 0xae2fc483527b8ef99eb5d9b44875f005ba1fae13
  • Sandwich bot contract: 0x1f2f10d1c40777ae1da742455c65828ff36df387
  • Frontrun tx: 0x914c47403d6b1fb25047f75201019d41cf19e1d56c0d95c968164167c0c95ccd (tx index 3)
  • Victim tx: 0xbffc57f64535df9e495c3fc0b5a5be5a8131aa1173d64f3e3ba7c9e81edf25c9 (tx index 4)
  • Backrun tx: 0xa0e563ecdd7750b51f251b722d2526342b07dcb9767911b3b5cd78d734466d11 (tx index 5)