Calculated from recorded token losses using historical USD prices at the incident time.
0x6fb7f8e9eb09d6ae17dbe82b2b42f46f64fb9c3197438b68ecf03e832d5fc7910xe5c6f5fef89b64f36bfccb063962820136bac42fEthereum0x53eef67f96ccb71fb1750df973fb9e8c82096759EthereumOn Ethereum mainnet block 19570745, an unprivileged adversary used a public Uniswap V3 flash loan to borrow HOPPY, sold part of the borrowed inventory into the public HOPPY/WETH Uniswap V2 pair, transferred just enough HOPPY into the HOPPY token contract to move its balance above the public _taxSwapThreshold, and then executed a second sell that forced HOPPY itself to dump 4206900000000000000000 raw HOPPY into the same pair. HOPPY's swap-back converted that inventory into 2280201362044709503 wei and forwarded the ETH to tax wallet 0x8b75ce8e330ba0ee5fb3a2b47b9e9b4260c08438 before the attacker's own sell finished. The attacker then bought back enough HOPPY at the depressed price to repay the flash loan plus fee and withdrew the residual WETH as ETH profit. The seed balance diff shows the initiating EOA 0x676c3262e8f0fba0031a93ea74ff801b99ac177b rising from 3726569022950483568 wei to 4090146245323000072 wei, a net gain of 363577222372516504 wei after gas.
The root cause is HOPPY's public sell-triggered auto-swap path inside _transfer. Any seller can deterministically convert protocol-held tax inventory into an additional market sell by pushing the token contract balance above _taxSwapThreshold and then selling into the public Uniswap V2 pair. Because the trigger conditions, balances, and venues are all public, this is a permissionless ACT/MEV opportunity rather than a privileged attack.
HOPPY () is a fee-on-transfer token whose verified source shows that transfer taxes accumulate on the token contract balance. When a qualifying sell targets the Uniswap V2 pair , may call and then , converting contract-held HOPPY into ETH and forwarding the ETH to the tax wallet.
0xe5c6f5fef89b64f36bfccb063962820136bac42f0x53eef67f96ccb71fb1750df973fb9e8c82096759_transferswapTokensForEthsendETHToFeeThe relevant public parameters in the verified source are:
uint256 public _taxSwapThreshold = 4206900000000 * 10**_decimals;
uint256 public _maxTaxSwap = 8413800000000 * 10**_decimals;
if (!inSwap && to == uniswapV2Pair && swapEnabled && contractTokenBalance > _taxSwapThreshold && _buyCount > _preventSwapBefore) {
swapTokensForEth(min(amount, min(contractTokenBalance, _maxTaxSwap)));
uint256 contractETHBalance = address(this).balance;
if (contractETHBalance > 0) {
sendETHToFee(address(this).balance);
}
}
At the exploited pre-state, the seed trace shows the HOPPY contract holding exactly 4000000000000000000000 raw HOPPY, which is below the public threshold 4206900000000000000000. The public Uniswap V3 pool 0xaa6f337f16e6658d9c9599c967d3126051b6c726 held 7485235167653113869853 raw HOPPY, providing permissionless flash liquidity for the attack.
The vulnerability class is MEV driven by user-triggerable maintenance logic. HOPPY couples a market-impacting protocol action, swapping accumulated tax inventory to ETH, directly to arbitrary user sells into the Uniswap V2 pair. The sell path is public, the threshold is public, and the amount swapped is bounded by attacker-controlled sell size and contract balance through min(amount, min(contractTokenBalance, _maxTaxSwap)).
That design breaks the expected invariant that a user's market sell should price only the user's inventory. Once the attacker pushes the contract's balance above _taxSwapThreshold, the next sell into the pair makes HOPPY perform an additional contract-originated sell before finalizing the attacker's own transfer. The attacker therefore controls when protocol-owned inventory is dumped and can atomically arbitrage the deterministic price impact.
This is not a speculative explanation. The seed transaction trace shows the contract balance top-up, the nested HOPPY-triggered router swap, the ETH delivery to the tax wallet, the attacker buyback, the flash-loan repayment, and the final profit extraction in one transaction.
The seed trace begins with exploit contract 0xc976ed4b25e1e7019ff34fb54f4e63b1550b70c3 calling the public Uniswap V3 pool flash primitive:
0xaa6f337f16e6658d9c9599c967d3126051b6c726::flash(
0xC976ED4b25e1e7019Ff34FB54f4e63B1550b70c3,
0,
7485235167653113869853,
...
)
Within uniswapV3FlashCallback, the attacker first sells 3071435167652113869853 raw HOPPY into the public Uniswap V2 router path [HOPPY, WETH], receiving 2163042004622102462 raw WETH. The same trace then shows a direct transfer of 206900000001000000000 raw HOPPY from the exploit contract to the HOPPY token contract:
Hoppy::balanceOf(Hoppy) -> 4000000000000000000000
Hoppy::transfer(Hoppy, 206900000001000000000)
That top-up moves the contract balance from 4000000000000000000000 to 4206900000001000000000, strictly above _taxSwapThreshold. The attacker then sells 4206900000000000000000 raw HOPPY into the V2 pair. Because the threshold condition is now satisfied, HOPPY's _transfer enters its swap-back branch and calls the V2 router to sell contract-held HOPPY before the attacker's own transfer is finalized:
Hoppy::transferFrom(attacker_contract, v2_pair, 4206900000000000000000)
...
UniswapV2Router::swapExactTokensForETHSupportingFeeOnTransferTokens(
4206900000000000000000,
0,
[HOPPY, WETH],
Hoppy,
...
)
...
0x8B75ce8e330bA0EE5fB3a2B47b9e9b4260C08438::fallback{value: 2280201362044709503}()
This is the code-level breakpoint and the economic breakpoint. HOPPY itself dumps 4206900000000000000000 raw HOPPY and forwards 2280201362044709503 wei to the tax wallet, creating the exploitable price dislocation in the public HOPPY/WETH pair. The attacker's own second sell also completes and yields additional WETH.
After the forced dump, the trace shows the attacker buying back exactly 7560087519329645008552 raw HOPPY by spending 3528538897342426033 raw WETH:
UniswapV2Router::swapTokensForExactTokens(
7560087519329645008552,
3907363705363283233,
[WETH, HOPPY],
attacker_contract,
...
)
The exploit contract transfers 7560087519329645008552 raw HOPPY back to the Uniswap V3 pool, matching flash principal plus fee. It then withdraws the leftover 378824808020857200 raw WETH to ETH and transfers the ETH back to the initiating EOA. The seed metadata records 447332 gas used at 34202399462 wei gas price, and the seed balance diff confirms the initiating EOA's net ETH increase of 363577222372516504 wei after gas.
The adversary flow is a single-transaction MEV sequence executed from EOA 0x676c3262e8f0fba0031a93ea74ff801b99ac177b through helper contract 0xc976ed4b25e1e7019ff34fb54f4e63b1550b70c3.
0xaa6f337f16e6658d9c9599c967d3126051b6c726 to flash-borrow 7485235167653113869853 raw HOPPY.3071435167652113869853 raw HOPPY into the public Uniswap V2 pair and receives 2163042004622102462 raw WETH.206900000001000000000 raw HOPPY into the HOPPY contract, pushing balanceOf(address(this)) from 4000000000000000000000 to just above _taxSwapThreshold.4206900000000000000000 raw HOPPY into the V2 pair; HOPPY's _transfer immediately performs its own swapTokensForEth on the same amount and forwards 2280201362044709503 wei to the tax wallet.3528538897342426033 raw WETH to buy 7560087519329645008552 raw HOPPY.378824808020857200 raw WETH to ETH, and transfers the ETH back to the initiating EOA.Every stage uses only permissionless contracts and public state. No privileged roles, private keys, or attacker-specific off-chain artifacts are required.
The measurable realized attacker profit was 363577222372516504 wei net ETH on the initiating EOA after gas, as shown by the seed balance_diff.json. The forced swap-back also transferred 2280201362044709503 wei from the HOPPY/WETH pair path into the tax wallet, confirming that protocol-held tax inventory was dumped via the attacker-triggered sell path.
{
"attacker_eoa_delta_wei": "363577222372516504",
"tax_wallet_delta_wei": "2280201362044709503",
"gas_used": "447332"
}
The economic harm is the deterministic price dislocation imposed on the HOPPY/WETH market and its counterparties. The protocol's public tax-conversion logic became an attacker-controlled extra sell, and the attacker captured the resulting arbitrage spread.
0x6fb7f8e9eb09d6ae17dbe82b2b42f46f64fb9c3197438b68ecf03e832d5fc791 on Ethereum mainnet block 19570745.balance_diff.json, showing the initiating EOA net gain of 363577222372516504 wei and the tax wallet gain of 2280201362044709503 wei.0xe5c6f5fef89b64f36bfccb063962820136bac42f, specifically _transfer, swapTokensForEth, and sendETHToFee.