VINU Reserve Drain
Exploit Transactions
0xaf46a42fe1ed7193b25c523723dc047c7500e50a00ecb7bbb822d665adb3e1f3Victim Addresses
0xf7ef0d57277ad6c2babf87ab64ba61abdd2590d2Ethereum0xa8af8ac7acd97095c0d73ed51e30564d52b19cd8EthereumLoss Breakdown
Similar Incidents
NOON Pool Drain via Public transfer
38%SBR reserve desynchronization exploit drains WETH from UniswapV2 pair
34%PumpToken removeLiquidityWhenKIncreases Uniswap LP Drain
34%0x7CAE Approved-Spender Drain
34%V3Utils Arbitrary Call Drain
34%USDTStaking Approval Drain
34%Root Cause Analysis
VINU Reserve Drain
1. Incident Overview TL;DR
In Ethereum mainnet block 17421007, transaction 0xaf46a42fe1ed7193b25c523723dc047c7500e50a00ecb7bbb822d665adb3e1f3 executed a single-transaction attack against the VINU token and its VINU/WETH Uniswap V2 pool at 0xa8af8ac7acd97095c0d73ed51e30564d52b19cd8. The attacker EOA 0x9748c8540a5f752ba747f1203ac13dae789033de funded helper contract 0xf73b8ea8838cba9148fb182e267a000f7cfba8dd, bought VINU with 0.1 ETH, repeatedly called VINU's public addLiquidityETH with the pair supplied as devaddr, forced the pair to sync to the reduced VINU balance, and then sold the acquired VINU back into the manipulated pool. The attacker extracted 3256513152378912968 wei of WETH and ended with a net cluster gain of 3140869820147531576 wei in ETH-equivalent after gas.
The root cause is a direct authorization and accounting failure in VINU.addLiquidityETH(address routeraddr,address lpraddr,address devaddr). Any caller can choose an arbitrary devaddr, including the live VINU/WETH pair, and the function immediately removes 80% of that address's VINU balance before any legitimate liquidity operation occurs. Because the caller also controls routeraddr, the attacker can route the call through a fake router that returns success without adding real liquidity, then exploit the distorted reserve state through a standard Uniswap V2 sync and swap flow.
2. Key Background
The affected token contract is VINU at 0xf7ef0d57277ad6c2babf87ab64ba61abdd2590d2. VINU is not a vanilla ERC20: its transfer path delegates balance handling to an external address stored in routerbyt, and it exposes a token-side addLiquidityETH helper that is callable by any external account. That helper is not the standard Uniswap router implementation; it directly mutates VINU balances and only then calls the user-supplied router.
The affected pool is the VINU/WETH pair at 0xa8af8ac7acd97095c0d73ed51e30564d52b19cd8, which public Etherscan source identifies as a verified UniswapV2Pair. In Uniswap V2, prices depend on cached reserves, and sync() updates those reserves to the pair's current token balances. That means any token contract that can arbitrarily lower the pair's token balance can alter the price seen by the next swap once sync() is called.
The relevant standard pair behavior is:
function sync() external lock {
_update(
IERC20(token0).balanceOf(address(this)),
IERC20(token1).balanceOf(address(this)),
reserve0,
reserve1
);
}
This matters because VINU's bug let the attacker push the pair's actual VINU balance far below the previously cached reserve while leaving WETH untouched. A later sync() therefore converted the manipulated balances into official reserves.
3. Vulnerability Analysis & Root Cause Summary
This incident is an ATTACK category bug, not an MEV-only opportunity without broken invariants. The violated invariant is straightforward: only a token holder or an approved spender should be able to reduce that holder's balance, and any liquidity helper should preserve the relationship between balances and actual liquidity additions. VINU breaks both rules in one public function. addLiquidityETH lets an arbitrary caller nominate any devaddr, subtracts 80% of that address's VINU balance, credits those tokens to the VINU contract itself, and only afterwards performs router interactions. Because routeraddr is caller-controlled, the attacker supplied a fake router contract that implemented the required methods and simply returned success. No real liquidity was added, but the pair still lost VINU balance. Once the attacker called sync(), the pair adopted the depleted VINU reserve and allowed an extremely favorable WETH-out swap against a tiny VINU-in trade.
4. Detailed Root Cause Analysis
The vulnerable VINU code is explicit:
function addLiquidityETH(address routeraddr,address lpraddr,address devaddr) external payable {
uint256 senderBalance = _balances[devaddr] * 80 /100;
_balances[devaddr] -= senderBalance;
_balances[address(this)] = senderBalance;
emit Transfer(devaddr, address(this), senderBalance);
IUniswapV2Router02 router = IUniswapV2Router02(routeraddr);
_approve(address(this), address(router), _totalSupply);
address uniswapV2Pair = IUniswapV2Factory(router.factory()).createPair(address(this), router.WETH());
router.addLiquidityETH{value: msg.value}(address(this),balanceOf(address(this)),0,0,lpraddr,block.timestamp);
IERC20(uniswapV2Pair).approve(address(router), ~uint(0));
}
The code-level breakpoint is the first three state-changing lines. They execute before any trustworthy router validation and do not require devaddr to be msg.sender, owner-controlled, or approved in any way. That lets any caller confiscate 80% of the VINU balance of any chosen address.
The observed exploit used that exact behavior against the live VINU/WETH pair:
VINU::addLiquidityETH(fakeRouter, attackerHelper, VINU/WETH Pair)
emit Transfer(src: VINU/WETH Pair, dst: VINU, wad: 373769865218439328)
VINU::addLiquidityETH(fakeRouter, attackerHelper, VINU/WETH Pair)
emit Transfer(src: VINU/WETH Pair, dst: VINU, wad: 74753973043687865)
VINU::addLiquidityETH(fakeRouter, attackerHelper, VINU/WETH Pair)
emit Transfer(src: VINU/WETH Pair, dst: VINU, wad: 14950794608737573)
VINU::addLiquidityETH(fakeRouter, attackerHelper, VINU/WETH Pair)
emit Transfer(src: VINU/WETH Pair, dst: VINU, wad: 2990158921747515)
VINU/WETH Pair::sync()
emit Sync(3431124883166006871, 747539730436879)
VINU/WETH Pair::swap(3256513152378912968, 0, attackerHelper, 0x)
The step-by-step mechanism is deterministic:
- The attacker helper first bought
13983585451343353VINU with0.1 ETH, leaving the pair with3431124883166006871WETH and467212331523049160VINU. - The attacker called
addLiquidityETHfour times withdevaddr = pair. Because each call removes80%of the pair's current VINU balance, the pair-side VINU balance fell along this sequence:467212331523049160 -> 93442466304609832 -> 18688493260921967 -> 3737698652184394 -> 747539730436879. - The supplied fake router satisfied the expected interface but returned success without transferring any real liquidity into the genuine pair. The balance loss therefore remained uncompensated.
- The attacker called
sync(), and the verified Uniswap V2 pair updated reserves to the manipulated live balances:3431124883166006871WETH and747539730436879VINU. - The attacker transferred the previously purchased
13983585451343353VINU back to the pair and used standard Uniswap pricing against the distorted reserves to compute and withdraw3256513152378912968WETH.
The balance-diff artifact confirms the outcome. The pair's VINU balance moved from 481195916974392513 before the transaction to 14731125181780232 after the full exploit, a net delta of -466464791792612281. The sender EOA lost 515643331231381392 wei of native ETH, while the helper contract finished with 400000004000000000 wei native ETH and the extracted WETH position.
5. Adversary Flow Analysis
The adversary flow was a compact four-stage sequence inside one attacker-crafted transaction:
- Funding and entry:
The EOA
0x9748c8540a5f752ba747f1203ac13dae789033desent0.5 ETHto helper contract0xf73b8ea8838cba9148fb182e267a000f7cfba8dd, making that helper the transaction target and execution environment. - Initial VINU buy:
The helper sent
0.1 ETHthrough the canonical Uniswap V2 router0x7a250d5630b4cf539739df2c5dacb4c659f2488dand received13983585451343353VINU. - Reserve manipulation:
The helper repeatedly called VINU's public
addLiquidityETH, each time passing the live pair asdevaddrand an attacker-controlled fake router asrouteraddr. The pair kept losing VINU while WETH stayed unchanged. - Profit realization:
After
sync(), the helper transferred its bought VINU back into the pair and calledswapto pull out3256513152378912968WETH.
The attacker-related accounts are defensibly identified:
0x9748c8540a5f752ba747f1203ac13dae789033de: the EOA that submitted and funded the exploit.0xf73b8ea8838cba9148fb182e267a000f7cfba8dd: the helper contract that received VINU, performed the reserve-drain sequence, and ended with profit-bearing WETH and native ETH.
The exploit remained permissionless throughout. No privileged role, stolen key, private contract artifact, or non-public state was needed. The attacker needed only public Ethereum state, the verified VINU bytecode/source, a locally deployed fake router, and standard Uniswap V2 interactions.
6. Impact & Losses
The directly measurable loss was to the VINU/WETH pool, which lost 3256513152378912968 WETH (3.256513152378912968 WETH, 18 decimals) in a single transaction. The pool's WETH balance dropped from 3431124883166006871 to 174611730787093903, while its VINU reserve had already been forced down to a tiny remainder before the sell-back step.
From the attacker-cluster perspective, the net gain was 3140869820147531576 wei in ETH-equivalent after gas. That valuation combines the sender EOA's native ETH balance change, the helper contract's final native ETH balance, and the helper contract's final WETH balance. The result shows that the exploit was not merely reserve distortion; it produced realized, extractable profit in the reference asset.
7. References
- Exploit transaction:
0xaf46a42fe1ed7193b25c523723dc047c7500e50a00ecb7bbb822d665adb3e1f3in Ethereum block17421007. - VINU token contract:
0xf7ef0d57277ad6c2babf87ab64ba61abdd2590d2. - VINU/WETH Uniswap V2 pair:
0xa8af8ac7acd97095c0d73ed51e30564d52b19cd8. - Canonical Uniswap V2 router used for the initial buy:
0x7a250d5630b4cf539739df2c5dacb4c659f2488d. - Collected exploit trace and metadata:
/workspace/session/artifacts/collector/seed/1/0xaf46a42fe1ed7193b25c523723dc047c7500e50a00ecb7bbb822d665adb3e1f3/trace.cast.log,/workspace/session/artifacts/collector/seed/1/0xaf46a42fe1ed7193b25c523723dc047c7500e50a00ecb7bbb822d665adb3e1f3/metadata.json, and/workspace/session/artifacts/collector/seed/1/0xaf46a42fe1ed7193b25c523723dc047c7500e50a00ecb7bbb822d665adb3e1f3/balance_diff.json. - Verified VINU source:
/workspace/session/artifacts/collector/seed/1/0xf7ef0d57277ad6c2babf87ab64ba61abdd2590d2/src/Contract.sol. - Verified VINU/WETH pair source evidence from Etherscan:
/workspace/session/artifacts/auditor/iter_1/pair_sourcecode_etherscan.json.