DeFi/AMM Exploitation: Uniswap v4 Hook Precision/Rounding Abuse
Tip
Lernen & ĂŒben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & ĂŒben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
UnterstĂŒtzen Sie HackTricks
- ĂberprĂŒfen Sie die AbonnementplĂ€ne!
- Treten Sie der đŹ Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter đŠ @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Diese Seite dokumentiert eine Klasse von DeFi/AMM-Exploitation-Techniken gegen Uniswap v4âartige DEXes, die die Core-Mathematik mit benutzerdefinierten hooks erweitern. Ein aktueller Vorfall in Bunni V2 nutzte einen Rundungs-/PrĂ€zisionsfehler in einer Liquidity Distribution Function (LDF), die bei jedem Swap ausgefĂŒhrt wurde, und ermöglichte dem Angreifer, positive Credits anzusammeln und LiquiditĂ€t abzuziehen.
Kernaussage: Wenn ein hook zusĂ€tzliche BuchfĂŒhrung implementiert, die von FixedâPointâMath, TickâRundung und Schwellenwertlogik abhĂ€ngt, kann ein Angreifer exactâinput Swaps so gestalten, dass sie bestimmte Schwellen ĂŒberschreiten und Rundungsdifferenzen sich zu seinen Gunsten akkumulieren. Das Muster zu wiederholen und anschlieĂend das aufgeblĂ€hte Guthaben abzuheben realisiert Gewinn, oft finanziert durch einen flash loan.
Background: Uniswap v4 hooks and swap flow
- Hooks sind VertrĂ€ge, die der PoolManager zu bestimmten LifecycleâPunkten aufruft (z. B. beforeSwap/afterSwap, beforeAddLiquidity/afterAddLiquidity, beforeRemoveLiquidity/afterRemoveLiquidity).
- Pools werden mit einem PoolKey initialisiert, der die hooks-Adresse enthĂ€lt. Ist diese nicht null, fĂŒhrt der PoolManager Callback-Aufrufe bei jeder relevanten Operation aus.
- Die CoreâMathematik benutzt FixedâPointâFormate wie Q64.96 fĂŒr sqrtPriceX96 und TickâArithmetik mit 1.0001^tick. Jede zusĂ€tzliche benutzerdefinierte Mathematik darĂŒber muss die Rundungssemantik exakt nachbilden, um ein Drift der Invarianten zu vermeiden.
- Swaps können exactInput oder exactOutput sein. In v3/v4 bewegt sich der Preis entlang der ticks; das Ăberschreiten einer TickâGrenze kann RangeâLiquidity aktivieren/deaktivieren. Hooks können zusĂ€tzliche Logik bei Schwellen-/TickâĂberschreitungen implementieren.
Vulnerability archetype: thresholdâcrossing precision/rounding drift
Ein typisches anfÀlliges Muster in benutzerdefinierten hooks:
- Der hook berechnet pro Swap Liquidityâ oder BalanceâDeltas unter Verwendung von IntegerâDivision, mulDiv oder FixedâPointâKonversionen (z. B. token â liquidity mittels sqrtPrice und TickâRanges).
- Schwellenwertlogik (z. B. Rebalancing, stufenweise Redistribution oder perâRange Aktivierung) wird ausgelöst, wenn eine SwapâGröĂe oder Preisbewegung eine interne Grenze ĂŒberschreitet.
- Rundung wird inkonsistent angewendet (z. B. Trunkierung Richtung Null, floor versus ceil) zwischen der VorwĂ€rtsberechnung und dem SettlementâPfad. Kleine Abweichungen heben sich nicht auf, sondern schreiben dem Caller Guthaben gut.
- Exactâinput Swaps, prĂ€zise dimensioniert, um diese Grenzen zu ĂŒberqueren, ernten wiederholt die positive Rundungsremainder. Der Angreifer hebt anschlieĂend das akkumulierte Credit ab.
Voraussetzungen des Angriffs
- Ein Pool, der einen benutzerdefinierten v4 hook verwendet, der bei jedem Swap zusĂ€tzliche Mathematik ausfĂŒhrt (z. B. eine LDF/rebalancer).
- Mindestens ein AusfĂŒhrungspfad, bei dem Rundung den SwapâInitiator ĂŒber SchwellenĂŒbertritte begĂŒnstigt.
- Möglichkeit, viele Swaps atomar zu wiederholen (flash loans eignen sich gut, um temporÀre LiquiditÀt bereitzustellen und Gas zu amortisieren).
Practical attack methodology
- Identify candidate pools with hooks
- Enumeriere v4 Pools und prĂŒfe PoolKey.hooks != address(0).
- Inspektiere hookâBytecode/ABI auf Callbacks: beforeSwap/afterSwap und alle benutzerdefinierten RebalancingâMethoden.
- Suche nach Mathematik, die: durch liquidity teilt, zwischen tokenâBetrĂ€gen und liquidity konvertiert, oder BalanceDelta mit Rundung aggregiert.
- Model the hookâs math and thresholds
- Rekonstruiere die Liquidity/RedistributionâFormel des hooks: Inputs sind typischerweise sqrtPriceX96, tickLower/Upper, currentTick, fee tier und net liquidity.
- Mappe Schwellen-/Stufenfunktionen: ticks, BucketâGrenzen oder LDFâBreakpoints. Bestimme, auf welcher Seite jeder Grenze der Delta gerundet wird.
- Identifiziere Stellen, an denen Konversionen zwischen uint256/int256 erfolgen, SafeCast verwendet wird oder mulDiv mit implizitem floor arbeitet.
- Calibrate exactâinput swaps to cross boundaries
- Nutze Foundry/HardhatâSimulationen, um das minimale Îin zu berechnen, das nötig ist, um den Preis gerade ĂŒber eine Grenze zu bewegen und den HookâBranch auszulösen.
- Verifiziere, dass nach dem afterSwapâSettlement dem Caller mehr gutgeschrieben wird als die Kosten, sodass ein positives BalanceDelta oder Kredit in der HookâBuchfĂŒhrung verbleibt.
- Wiederhole Swaps, um Kredit anzusammeln; rufe dann den Entnahme/SettlementâPfad des Hooks auf.
Example Foundryâstyle test harness (pseudocode)
function test_precision_rounding_abuse() public {
// 1) Arrange: set up pool with hook
PoolKey memory key = PoolKey({
currency0: USDC,
currency1: USDT,
fee: 500, // 0.05%
tickSpacing: 10,
hooks: address(bunniHook)
});
pm.initialize(key, initialSqrtPriceX96);
// 2) Determine a boundaryâcrossing exactInput
uint256 exactIn = calibrateToCrossThreshold(key, targetTickBoundary);
// 3) Loop swaps to accrue rounding credit
for (uint i; i < N; ++i) {
pm.swap(
key,
IPoolManager.SwapParams({
zeroForOne: true,
amountSpecified: int256(exactIn), // exactInput
sqrtPriceLimitX96: 0 // allow tick crossing
}),
""
);
}
// 4) Realize inflated credit via hookâexposed withdrawal
bunniHook.withdrawCredits(msg.sender);
}
Calibrating the exactInput
- Berechne ÎsqrtP fĂŒr einen Tick-Schritt: sqrtP_next = sqrtP_current Ă 1.0001^(Îtick).
- Approximiere Îin mithilfe der v3/v4-Formeln: Îx â L Ă (ÎsqrtP / (sqrtP_next Ă sqrtP_current)). Stelle sicher, dass die Rundungsrichtung mit der Core-Mathematik ĂŒbereinstimmt.
- Passe Îin um ±1 wei um die Grenze herum an, um den Branch zu finden, in dem der Hook zugunsten deiner Rundung rundet.
- VerstÀrken mit flash loans
- Leihe einen groĂen Nominalbetrag (z. B. 3M USDT oder 2000 WETH), um viele Iterationen atomar auszufĂŒhren.
- FĂŒhre die kalibrierte Swap-Schleife aus, hebe dann ab und zahle innerhalb des flash loan callbacks zurĂŒck.
Aave V3 flash loan skeleton
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external returns (bool) {
// run thresholdâcrossing swap loop here
for (uint i; i < N; ++i) {
_exactInBoundaryCrossingSwap();
}
// realize credits / withdraw inflated balances
bunniHook.withdrawCredits(address(this));
// repay
for (uint j; j < assets.length; ++j) {
IERC20(assets[j]).approve(address(POOL), amounts[j] + premiums[j]);
}
return true;
}
- Exit und crossâchain replication
- If hooks are deployed on multiple chains, repeat the same calibration per chain.
- Bridge proceeds back to the target chain and optionally cycle via lending protocols to obfuscate flows.
Common root causes in hook math
- Mixed rounding semantics: mulDiv floors while later paths effectively round up; or conversions between token/liquidity apply different rounding.
- Tick alignment errors: using unrounded ticks in one path and tickâspaced rounding in another.
- BalanceDelta sign/overflow issues when converting between int256 and uint256 during settlement.
- Precision loss in Q64.96 conversions (sqrtPriceX96) not mirrored in reverse mapping.
- Accumulation pathways: perâswap remainders tracked as credits that are withdrawable by the caller instead of being burned/zeroâsum.
Defensive guidance
- Differential testing: mirror the hookâs math vs a reference implementation using highâprecision rational arithmetic and assert equality or bounded error that is always adversarial (never favorable to caller).
- Invariant/property tests:
- Sum of deltas (tokens, liquidity) across swap paths and hook adjustments must conserve value modulo fees.
- No path should create positive net credit for the swap initiator over repeated exactInput iterations.
- Threshold/tick boundary tests around ±1 wei inputs for both exactInput/exactOutput.
- Rounding policy: centralize rounding helpers that always round against the user; eliminate inconsistent casts and implicit floors.
- Settlement sinks: accumulate unavoidable rounding residue to protocol treasury or burn it; never attribute to msg.sender.
- Rateâlimits/guardrails: minimum swap sizes for rebalancing triggers; disable rebalances if deltas are subâwei; sanityâcheck deltas against expected ranges.
- Review hook callbacks holistically: beforeSwap/afterSwap and before/after liquidity changes should agree on tick alignment and delta rounding.
Case study: Bunni V2 (2025â09â02)
- Protocol: Bunni V2 (Uniswap v4 hook) with an LDF applied per swap to rebalance.
- Root cause: rounding/precision error in LDF liquidity accounting during thresholdâcrossing swaps; perâswap discrepancies accrued as positive credits for the caller.
- Ethereum leg: attacker took a ~3M USDT flash loan, performed calibrated exactâinput swaps on USDC/USDT to build credits, withdrew inflated balances, repaid, and routed funds via Aave.
- UniChain leg: repeated the exploit with a 2000 WETH flash loan, siphoning ~1366 WETH and bridging to Ethereum.
- Impact: ~USD 8.3M drained across chains. No user interaction required; entirely onâchain.
Hunting checklist
- Does the pool use a nonâzero hooks address? Which callbacks are enabled?
- Are there perâswap redistributions/rebalances using custom math? Any tick/threshold logic?
- Where are divisions/mulDiv, Q64.96 conversions, or SafeCast used? Are rounding semantics globally consistent?
- Can you construct Îin that barely crosses a boundary and yields a favorable rounding branch? Test both directions and both exactInput and exactOutput.
- Does the hook track perâcaller credits or deltas that can be withdrawn later? Ensure residue is neutralized.
References
- Bunni V2 Exploit: $8.3M Drained via Liquidity Flaw (summary)
- Bunni V2 Exploit: Full Hack Analysis
- Uniswap v4 background (QuillAudits research)
- Liquidity mechanics in Uniswap v4 core
- Swap mechanics in Uniswap v4 core
- Uniswap v4 Hooks and Security Considerations
Tip
Lernen & ĂŒben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & ĂŒben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
UnterstĂŒtzen Sie HackTricks
- ĂberprĂŒfen Sie die AbonnementplĂ€ne!
- Treten Sie der đŹ Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter đŠ @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.


