0x3d5b4a0d560e8dd750239b578e2b85921b523835b644714dc239a2db70cf067c0xe81c4a73bfddb1ddadf7d64734061be58d4c0b4cEthereum0xbc6a213cbb34424670548ef4b3388f5fdbd07992EthereumOn Ethereum mainnet block 20811949, an unprivileged attacker EOA 0x7248939f65bdd23aab9eaab1bc4a4f909567486e called helper contract 0xbdb0bc0941ba81672593cd8b3f9281789f2754d1 to execute a single-transaction flash-arbitrage against PESTO liquidity. The helper flash-borrowed PESTO from the Uniswap V3 PESTO/WETH pool 0x03d93835f5ce4dd7f0eaab019b33050939c722b1, sold into the Uniswap V2 pair 0xbc6a213cbb34424670548ef4b3388f5fdbd07992, pushed the token contract above its tax-swap threshold, and forced the token contract to dump its own inventory into the V2 pair during the next sell. That forced inventory sale distorted the V2 price enough for the helper to buy back the required repayment amount, repay the flash loan plus fee, unwrap residual WETH, and return 0.503881906767766532 ETH to the sender. After gas, the sender netted 0.496188056447385641 ETH.
The root cause is PESTO's sell-side auto-swap design. In the verified PestoTheBabyKingPenguin contract at 0xe81c4a73bfddb1ddadf7d64734061be58d4c0b4c, an ordinary sell into the Uniswap V2 pair can trigger a contract-owned token sale whose size is chosen by the seller-controlled amount. Because the contract inventory and swap threshold are public and permissionless, any searcher can prime the contract above threshold, force the dump, and arbitrage the resulting cross-pool price dislocation.
PESTO is a fee-on-transfer token that accumulates tax inventory on the token contract itself. When sells reach the configured path conditions, the contract swaps some of that inventory for ETH through the Uniswap V2 router and forwards the ETH to the tax wallet. This means user sells are not isolated from protocol-owned inventory management.
Two liquidity venues mattered during the incident. The Uniswap V2 PESTO/WETH pair at 0xbc6a213cbb34424670548ef4b3388f5fdbd07992 absorbed both the attacker sells and the contract's own forced sale, so its reserves determined the exploitable price move. The Uniswap V3 1% PESTO/WETH pool at 0x03d93835f5ce4dd7f0eaab019b33050939c722b1 provided permissionless flash liquidity, letting the attacker source temporary PESTO inventory without upfront capital or privileged access.
The relevant pre-state was block 20811948, immediately before the exploit transaction. At that point the token contract already held 2878895419298712592 PESTO, while the verified source fixed _taxSwapThreshold == _maxTaxSwap == 4200000000000000000. That meant a public top-up of 1321104580701287410 PESTO would move the contract from below threshold to just above threshold and arm the next sell-triggered auto-swap.
This incident is an ACT-style attack rooted in tokenomics logic, not privileged access. The verified PESTO source makes ordinary user sells responsible for deciding whether the token contract should dump its own inventory into the V2 pair. Critically, the amount dumped is min(amount, min(contractTokenBalance, _maxTaxSwap)), so the attacker controls the dump size by choosing the size of their sell. Because the contract inventory is public and transferable, the attacker can deterministically top the contract up above threshold before making the triggering sell. Once that sell executes, the contract performs an extra market sale of protocol-owned inventory into the same pool, creating a predictable reserve shock. External liquidity on Uniswap V3 lets the attacker source temporary inventory, and the cheaper post-dump V2 price lets the attacker buy back enough PESTO to settle the flash obligation and keep residual ETH. The broken invariant is that an untrusted seller should not be able to force protocol-owned inventory into the same trade path in an attacker-chosen size.
The verified PESTO contract shows the exact breakpoint inside _transfer:
if (!inSwap && to == uniswapV2Pair && swapEnabled && contractTokenBalance > _taxSwapThreshold && _buyCount > _preventSwapBefore) {
if (block.number > lastSellBlock) {
sellCount = 0;
}
require(sellCount < 3, "Only 3 sells per block!");
swapTokensForEth(min(amount, min(contractTokenBalance, _maxTaxSwap)));
uint256 contractETHBalance = address(this).balance;
if (contractETHBalance > 0) {
sendETHToFee(address(this).balance);
}
sellCount++;
lastSellBlock = block.number;
}
This logic is vulnerable because amount is the seller's input, not a protocol-controlled quantity. If the seller can ensure contractTokenBalance > _taxSwapThreshold, then their sell can force the contract to sell up to _maxTaxSwap from protocol inventory before the user's sell path completes.
The exploit trace confirms that exact sequence. First, the helper took a flash loan of 18906536720334536200 PESTO from the Uniswap V3 pool:
UniswapV3Pool::flash(..., amount1: 18906536720334536200, ...)
...
emit Flash(..., amount1: 18906536720334536200, paid1: 189065367203345362)
Second, it sold 13385432139633248790 PESTO into the V2 pair and received 6209005191781857360 WETH-equivalent output, moving the pair reserves without yet triggering the contract dump. Third, it transferred exactly 1321104580701287410 PESTO into the token contract, taking the contract from 2878895419298712592 to 4200000000000000002 PESTO:
PestoTheBabyKingPenguin::balanceOf(PestoTheBabyKingPenguin) -> 2878895419298712592
PestoTheBabyKingPenguin::transfer(PestoTheBabyKingPenguin, 1321104580701287410)
...
storage change on token self balance: 2878895419298712592 -> 4200000000000000002
That top-up crossed the strict contractTokenBalance > _taxSwapThreshold check. The helper then sold 4200000000000000000 PESTO, and the nested trace shows the token contract itself approving the router and executing swapExactTokensForETHSupportingFeeOnTransferTokens(4200000000000000000, ...), which is the forced dump of contract-owned inventory. The relevant trace segment ends with the token contract self-balance falling from 4200000000000000002 to 2 and the tax wallet receiving 1156824291651339159 wei:
PestoTheBabyKingPenguin::transferFrom(attacker_helper, V2_pair, 4200000000000000000)
...
0x7a250d...::swapExactTokensForETHSupportingFeeOnTransferTokens(4200000000000000000, ...)
...
storage change on token self balance: 4200000000000000002 -> 2
0x72fdF486...::fallback{value: 1156824291651339159}()
Once the forced dump cheapened PESTO on V2, the helper used 6628443693871385473 WETH to buy back 19095602087537881562 PESTO via swapTokensForExactTokens, repaid the V3 pool, and kept the residual spread. The final trace confirms repayment and profit realization:
0x7a250d...::swapTokensForExactTokens(19095602087537881562, 7156286754336690036, ...)
PestoTheBabyKingPenguin::transfer(UniswapV3Pool, 19095602087537881562)
WETH9::withdraw(527843060465304563)
0x7248939f65bdd23aab9eaab1bc4a4f909567486e::fallback{value: 503881906767766532}
The balance-diff artifact matches the economic outcome. The attacker EOA gained 496188056447385641 wei net after gas, and WETH supply in the V2 ecosystem dropped by 1679843922116643722 wei-equivalent, which is the measurable victim-side depletion captured in the analysis.
The attacker flow is fully contained in transaction 0x3d5b4a0d560e8dd750239b578e2b85921b523835b644714dc239a2db70cf067c.
0x7248939f65bdd23aab9eaab1bc4a4f909567486e calls helper 0xbdb0bc0941ba81672593cd8b3f9281789f2754d1.UniswapV3Pool::flash on 0x03d93835f5ce4dd7f0eaab019b33050939c722b1 and receives 18906536720334536200 PESTO, with a required repayment of borrowed amount plus 189065367203345362 fee.swapExactTokensForTokensSupportingFeeOnTransferTokens for 13385432139633248790 PESTO, receiving WETH and pushing the V2 price downward.1321104580701287410 PESTO directly to the token contract, priming address(this) balance to 4200000000000000002 so the next sell satisfies the strict threshold check.4200000000000000000 more PESTO. During this sell, the token contract auto-sells its own 4200000000000000000 PESTO into the same V2 pair and forwards 1.156824291651339159 ETH to the tax wallet.6628443693871385473 WETH to reacquire 19095602087537881562 PESTO, which exactly covers the flash loan principal plus fee.527843060465304563 WETH, pays 23961153697538490 wei to builder address 0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97, and returns 503881906767766532 wei to the EOA.Every step uses public contracts and permissionless functionality. No privileged contract roles, private keys, or attacker-specific bytecode from the original incident are required to realize the opportunity.
The direct economic victim was the Uniswap V2 PESTO/WETH liquidity position, which absorbed both the attacker sells and the token contract's forced inventory sale. The root cause artifact records total measurable loss as 1679843922116643722 WETH units (1.679843922116643722 WETH) extracted from the V2-side liquidity environment. The attacker EOA realized 0.496188056447385641 ETH net after gas, while the tax wallet separately received 1.156824291651339159 ETH from the contract-owned forced dump.
This matters beyond the single transaction because the exploit conditions were public and repeatable: visible contract inventory, public threshold values, permissionless flash liquidity, and externally tradable liquidity on another venue. Any unprivileged searcher able to simulate the state could have taken the same opportunity.
0x3d5b4a0d560e8dd750239b578e2b85921b523835b644714dc239a2db70cf067c0x7248939f65bdd23aab9eaab1bc4a4f909567486e0xbdb0bc0941ba81672593cd8b3f9281789f2754d10xe81c4a73bfddb1ddadf7d64734061be58d4c0b4c0xbc6a213cbb34424670548ef4b3388f5fdbd079920x03d93835f5ce4dd7f0eaab019b33050939c722b1