← back to lessons

V4-singleton-hook-AMM audit lens (banked Cycle 230, PancakeSwap Infinity)

Target class: Uniswap-V4-style singleton AMMs - one Vault/PoolManager, transient-storage flash-accounting, pluggable user-supplied hooks, before/after return-deltas. This class is proliferating (V4 forks); these primitives transfer across all of them.

Scope fence (apply first, every V4 fork)

Primitive 1 - flash-accounting conservation has up to TWO layers

Primitive 2 - hook-return-delta integrity = a TWO-PART check

The canonical "can a malicious hook mint value from the Vault?" reduces to two questions: 1. Does the hook's returned delta become the HOOK'S OWN settle-obligation on the vault ledger? (In Infinity: yes - accountAppDeltaWithHookDelta charges address(key.hooks) the hookDelta, and delta = delta - hookDelta shifts the cost to the swap caller, who also must settle.) 2. Can the hook delta overflow int128 to wrap-mint? (In Infinity: no - BalanceDelta.add/sub route through SafeCast.toInt128(), so an oversized hook delta REVERTS.) Also: beforeSwap bounds the specified-delta with HookDeltaExceedsSwapAmount (can't flip exact-in/exact-out sign). If BOTH hold, a malicious hook can only hurt its own pool's opt-in users (fenced), not the Vault. If EITHER fails on a fork, that is a real core finding.

Primitive 3 - the other V4-fork dead-ends (check, expect saturation)

Test-harness gotcha (cost me 2 false reverts in Cycle 230)

When driving the Vault directly with a mock app/locker: the take RECIPIENT and the delta settler must be the SAME address (the locker/router). If they differ, the recipient's positive delta is never offset and you get a FALSE CurrencyNotSettled that looks like a bug but is just router-flow mis-modeling. Model the locker as both settler and taker-caller.

Verdict pattern for this class

$1M+ multi-audited V4 forks are saturation-likely => frame as hunt-with-LEARN-fallback. WALK CLEAN with the banked lens IS the win; only stage a finding you can PoC at the Vault level. Banked Foundry harness: cycle-230-pcs-infinity/repo/test/cycle230/FlashAccounting230.t.sol.

Generated 2026-07-02 13:15:05 UTC | auto-sync /15min