Uniswap v4 Hooks: Must-Have AMM Extensions, Avoid Risks.
Article Structure

Uniswap v4 introduces “hooks,” small onchain programs that can run at precise points in a pool’s lifecycle. They extend AMM behavior without forking core code, enabling features like dynamic fees, intent-aware routing, and on-pool incentives. The freedom is powerful. The attack surface grows too.
This guide explains what hooks are, how they wire into the swap pipeline, where they shine, and where they bite. Two tiny scenarios show how a well-meaning hook can either improve execution or create a drain.
What hooks are in v4
A hook is a smart contract attached to a pool that can intercept and act on events such as initialization, modifying LP positions, swaps, and donations. Each pool can opt into a hook by setting the hook address at creation. From there, the pool calls the hook’s functions at defined checkpoints.
The standard interface exposes symmetrical pre/post callbacks: beforeInitialize/afterInitialize, beforeModifyPosition/afterModifyPosition, beforeSwap/afterSwap, and beforeDonate/afterDonate. The pool passes structured data; the hook can read pool state and, in some cases, adjust parameters like dynamic fee or surplus accounting.
How a swap flows through hooks
To understand control, it helps to see the ordered flow. The pool performs checks, calls the hook, updates state, then calls the hook again if allowed.
- The router submits a swap to a pool with a hook address set at create2 time.
- Pool validates inputs, then invokes beforeSwap with context (tick, fee, amountSpecified, zeroForOne).
- The hook may alter fee parameters or enforce custom conditions; it can also prepare accounting for rebates.
- The pool executes the core swap math and transfers tokens.
- The pool calls afterSwap with execution results, enabling logging, rebates, or post-trade invariants.
Example: a “time-of-day fee” hook raises fees during volatile hours in beforeSwap, then rebates loyal flow in afterSwap using a whitelist.
Advanced extensions hooks unlock
The design is modular, so single-purpose hooks compose. This opens a catalogue of new behaviors that would be awkward or brittle inside core AMM code.
- Dynamic fees: adjust bps by volatility, inventory skew, or oracle signals.
- Limiter rules: halt trades above a slippage budget, or block tokens during known pauses.
- Rebates and incentives: return a slice of fees to LPs who supply inventory at target ticks, or refund makers with on-pool points.
- Protocolized MEV: direct JIT-liquidity rents or sandwich protection fees into a vault.
- Intent-aware routing: accept meta-params from offchain solvers to tighten quotes for exact-output swaps.
A tiny scenario: a volatility-targeting hook reads a TWAP and widens fees as realized variance spikes. It calms down automatically when variance falls, reducing LP bleed during chop while keeping casual swappers unaffected most of the day.
Composability patterns that work
Hooks can be composed, but stuffing everything into one contract invites complexity. Patterns that keep state small and side effects clear tend to fare better.
Consider these practical patterns before writing your own:
- Parameter-gating: compute new fee/limit values from read-only inputs, write minimal state.
- Stateless metering: emit events and settle rebates in batches via a separate accounting contract.
- Role-splitting: isolate admin controls (e.g., changing an oracle address) from swap callbacks.
- Deterministic guards: precompute caps from constants and pool state; avoid external calls mid-swap.
These patterns reduce gas variance and reentrancy risk, and they make audits simpler because flows are predictable.
Common hook triggers and risks
The main callbacks have different powers and failure modes. The table below maps triggers to typical uses and their primary pitfalls so you can choose the right lever.
| Trigger | Typical use | Primary risk |
|---|---|---|
| beforeInitialize afterInitialize | Seed parameters, set fee schedule, register pool | Miset bootstrap; immutable config spoofing |
| beforeModifyPosition afterModifyPosition | LP gating, deposit caps, incentive tagging | Griefing LPs; dust positions blocking ticks |
| beforeSwap | Dynamic fees, slippage caps, pause lists | Reentrancy, price manipulation pre-state update |
| afterSwap | Rebates, logging, MEV share distribution | External call failures; gas griefing |
| beforeDonate afterDonate | Protocol revenue routing, buybacks | Accounting drift, double-claim vectors |
As a rule of thumb, do policy decisions in “before” hooks, then keep “after” hooks for recording and lightweight payouts to limit external dependencies during critical math.
Security pitfalls that keep showing up
Hooks sit on the hot path of swaps. Any bug becomes a money bug. The following issues appear frequently in audit reports and incident write-ups.
- Reentrancy through token callbacks: ERC-777 hooks, fee-on-transfer tokens, or malicious tokens can reenter after transfers if your hook calls out. Guard with nonReentrant modifiers, pull-pattern payouts, and explicit allowlists.
- Gas griefing: an attacker forces worst-case gas in afterSwap by crafting edge inputs. Keep afterSwap constant-time and avoid loops over user data.
- Oracle games: if dynamic fees depend on a manipulable spot, an attacker can “prime” the pool in a prior transaction and profit on the next swap. Prefer TWAPs or external oracles with sanity bounds.
- State desynchronization: writing to shared storage across multiple pools from one hook can leave partial updates when a call fails mid-way. Use transactional guards or staged commits.
- Unchecked external calls: EMV quirks like missing return booleans on ERC-20 transfers or silent failures can strand funds. Use safe wrappers and explicit revert reasons.
- Storage collisions and delegatecall: if your hook uses proxies, align storage slots and ban delegatecall in hooks unless absolutely necessary.
- Invariant drift in fees: incorrect rounding when adjusting fees can leak value over time. Unit-test boundary ticks and min/max fee caps.
- Permissioned backdoors: “admin can override fee” without timelocks or cap checks is a governance risk and a honeypot for key compromise.
- Sandwich-friendly logic: hooks that announce fee changes deterministically let sophisticated searchers time entries. Add randomness or minimum durations.
A tiny negative scenario: a rebate hook pays out in afterSwap using a loop over prior traders. An attacker pushes 2,000 tiny swaps, then triggers an honest user’s trade that runs the O(n) loop and consumes all gas, reverting the user and freezing the pool’s path.
Testing and monitoring that actually catches issues
Security starts with defaults: assume adversaries control calldata, token behavior, and ordering. Then test like they do.
- Model-based fuzzing: define invariants (e.g., fees collected ≥ expected) and fuzz swap/LP sequences across ticks, exact-in/out, and zeroForOne flips.
- Adversarial tokens: simulate fee-on-transfer, ERC-777 reentrancy, and tokens that return false on transfer.
- Gas profiling: assert upper gas bounds for before/after hooks under worst-case inputs so griefing won’t block routers.
- Shadow forks and dry runs: replay mainnet sequences around volatile windows; compare PnL versus a vanilla pool.
Onchain monitors should track fee deltas, revert rates, and abnormal event patterns per pool. A sudden spike in afterSwap reverts is often an early sign of a griefing campaign or a broken external dependency.
Governance, permissions, and upgrade policy
Even “immutable” hooks need policy. If you plan to upgrade or rotate parameters, make that path transparent and bounded.
- Timelocks and caps: enforce maximum fee and minimum notice periods in code, not just docs.
- Multisig hygiene: limit signer devices and geographic correlation; require simulation proofs for parameter changes.
- Kill switches: implement narrowly scoped emergency pauses that only affect risky features, not core swaps.
Publishing a threat model, including who can flip which switch, builds user trust and shortens incident response loops when pressure hits.
Practical checklist for building a v4 hook
Use this concise checklist as a final pass before deploying. It covers design, tests, and runtime practices.
- Define the minimal state you truly need; prefer computed policy to stored policy.
- Cap dynamic fees with hard min/max and clamp inputs from oracles.
- Avoid external calls inside beforeSwap; if required, cache and precompute off-path.
- Make afterSwap constant-time; batch complex payouts via a separate function.
- Guard against reentrancy; reject known-dangerous token standards or sandbox them.
- Fuzz edge cases: zero liquidity, tick boundary crossings, exact-out failures.
- Emit rich events and build a dashboard for reverts, fee changes, and payout lags.
Hooks turn pools into programmable marketplaces. With careful design, testing, and clear governance, they can price risk better, share MEV fairly, and reduce LP bleed—without handing attackers a new set of knobs.


