Introduction to Bunni V2 Protocol
Bunni is liquidity protocol built on Uniswap V4 but instead of integrating liquidity curve of Uniswap, it customized it's own curve by utilizing the new hooks feature introduced in V4 to develop UniformDistribution equivalent to uniswap V3 position where it recomputes the idle balance of the pool after each trade BunniHookLogic to detect if the curve has a liquidity surplus, if found it rebalance the liquidity pool to maintain the curve in the correct tokens ratio.
How the Attacker Exploit the Protocol
The exploit targeted this rebalance mechanism. By crafting a sequence of swaps, the attacker tricked the hook into miscalculating surplus, causing it to distribute more output tokens than intended. This logical flaw allowed the attacker to drain ~$8.3M from the pool.
- Attacker created the first malicious contract using EAO: 0x0c3d8fa7762ca5225260039ab2d3990c035b458d
-
With the same EOA, created another malicious contract
- Using his second malicious contract address to take a flash loan of 3M UST from Uniswap v3 on Ethereum.
- If we expand the flash loan transaction to see all internal transfers and interactions across all involved protocols:
-
Line 41:BunniHubcontract identified thepoolIdto capture thepoolStateand returnliquidityDensityFunctionparameters -
Line 42:attacker took a USDT flash loan from Uniswap v3 for $3Mamount1=3,000,000,000,000. -
Line 43:returns balance of WETHamount0in Uniswap v3. -
Line 44:returns balance of USDTamount1in Uniswap v3. -
Line 45:Uniswap executes USDT transfer of flash loan amount on USDT contract. -
Line 46:USDT contract emitsTransferevent withfromUniswap,toattacker's second malicious contract, andvalueis the $3M flash loan amount. -
Line 47:uniswapV3FlashCallbackenforce flash loan repayment in same transaction, in total of $9M that include principle plus fee wherefee1=9,000,000,000,000ofamount1earlier. -
Line 48:uniswapV3FlashCallbackemits alog_stringevent (“Depositing to euler”). -
Line 49:since Bunni v2 is using Hooks and built on Uniswap v4, all transactions except pool initiation without funding has to unlockpoolManagerprior to executing trade viaunlockCallback. -
Line 50:flash loan recipient contract executesunlockCallback. -
Line 51:emitsunlockCallbackevent on successful call.
-
To manipulate the
UniformDistributionattacker executed a series of swaps on USDC-USDT pool, to trigger the flaw of Bunni Hook liquidity accounting mechanism that successfully yield more output token. -
Every swap executed triggered
beforeSwaphook that captured Bunni's pool pair ratio before swap, while internally there are 2 operations taking place for a successful swap; Uniswap v4 Flash Accounting and Bunni's Uniform Distribution. - With each swap and with the distribution function miscalculation of delta after each swap, the error got accumulated because of Uniswap flash accounting in favor of attacker as a positive balance to withdraw.
-
Final exploit in Bunni's protocol was to withdraw
takethe compounded balance and pay offsettlethe flash loan.
- Attacker used another EOA `0xe04efd87f410e260cf940a3bcb8bc61f33464f2b` to deposit $1.4M USDT and $1.32M USDC in Aave v3
- Till the time writing this post, exploit amounts are still in attacker's EOAs as follow:
Hack Analysis
Bunni's Uniform Distribution of liquidity miscalculated balance after each trade that goes through Uniswap v4, didn't count properly for flash accounting and deltas which left change or small amounts to be exploit by accumulation, if a well sized swap executed repeatedly.