Uniswap v4 Hooks: Custom Logic and Security Risks
Uniswap v4 lets pool creators inject custom code into trades and liquidity moves. That opens up massive flexibility. It also opens up brand-new attack vectors.
Key takeaways
- →Uniswap v4 replaces individual pool contracts with a single master contract and external hook scripts.
- →Hooks trigger custom code before or after key events like swaps, deposits, and fee collection.
- →Dynamic fee hooks can be weaponized to siphon trade value or sandwich users with unfair pricing.
- →Hook permissions are encoded directly into the top bits of the hook contract's address.
Uniswap v4 lets developers execute custom code right inside an automated market maker transaction. Earlier versions were rigid. You had a fixed fee tier, a standard math formula, and hardcoded logic for how trades and deposits went down. You knew exactly what you were getting when you sent a swap. Every single pool ran the exact same code underneath.
Uniswap v4 flips that script. Instead of deploying separate contracts for every single token pair, v4 sweeps all pools into one master architecture called the Singleton. Want custom features? Enter hooks: external smart contracts that run custom code right before or after core pool actions. Developers can use them to build limit orders, dynamic fee setups, time-weighted market makers, or auto-compounding yields. But that flexibility works both ways. By giving external code permission to alter execution paths mid-trade, hooks introduce brutal security risks that simply don't exist in standard AMMs.
How Uniswap v4 Hooks Alter Execution
In Uniswap v3, swapping token A for token B follows a straight, predictable line. The pool checks its current liquidity, calculates slippage along the constant-product curve, takes out a static fee, updates its internal state, and sends over the tokens. Zero interruptions during execution.
Uniswap v4 breaks this process wide open. The main Singleton contract handles token balances and state accounting. When a trade hits, the pool checks if a hook contract is attached. If it finds one, the pool halts its standard run to call out to that hook contract at specific checkpoints.
They call these checkpoints lifecycle callbacks. A hook can ask for permission to run code at eight distinct execution points:
- beforeInitialize / afterInitialize: Fires when a brand-new trading pool gets created.
- beforeAddLiquidity / afterAddLiquidity: Fires right before or after a liquidity provider deposits assets.
- beforeRemoveLiquidity / afterRemoveLiquidity: Fires right before or after an LP pulls assets out.
- beforeSwap / afterSwap: Fires right before or right after a trader makes a swap.
- beforeDonate / afterDonate: Fires right before or after tokens get donated straight into pool reserves.
When you submit a swap to a v4 pool with an attached hook, execution ticks through these six steps:
- Swap Initiation: You send a trade request to the v4 Singleton contract.
- Pre-Swap Hook Execution: The Singleton checks if the pool flipped the
beforeSwapflag on. If it did, it passes trade details—caller, token pair, trade size, direction—to the hook contract. - Hook Logic Processing: The hook runs its code. It can modify swap parameters, trigger external smart contract calls, update internal state, or tweak the pool fee.
- Core Math Execution: Control shifts back to the Singleton. The pool calculates token output based on those updated parameters and the liquidity curve.
- Post-Swap Hook Execution: If the
afterSwapflag is live, control passes right back to the hook for extra logic, like updating an oracle or placing a second order. - Settlement: The Singleton calculates net balances, double-checks that all debts are cleared using flash accounting, and pushes the final token output to your wallet.
Novel Attack Vectors Introduced by Hooks
Standard AMMs keep you safe by restricting what can happen during a swap. Hooks toss those guardrails out the window. Because hook logic runs right in the middle of execution, a rogue dev can exploit callback logic to siphon funds or drain pool reserves dry.
1. Malicious Dynamic Fee Manipulation
Uniswap v4 lets hooks override fixed pool fees and crank up dynamic fees on the fly during the beforeSwap callback. Honest devs use this feature to drop fees when volatility drops, or raise them when markets turn chaotic to shield liquidity providers from loss-versus-rebalancing (LVR).
A malicious hook creator can build code that spies on incoming trades. Say a retail trader drops a massive buy order. The hook's beforeSwap code spots the trade size or caller address and jacks up the fee to 99% for that specific trade. The swap processes, the trader gets wrecked, and the hook routes that massive stolen fee straight into an address owned by the developer.
2. Reentrancy via Callbacks
Reentrancy happens when an external call lets an attacker jump back into the main contract before state updates settle. In v4, the Singleton uses flash accounting, which means actual token transfers don't settle until the end of the entire transaction block.
If a hook's afterSwap or afterRemoveLiquidity code dials out to an untrusted contract, an attacker can use that callback to re-enter the Singleton or a connected vault. If the hook's internal tracking state fails to update before making that call, the attacker can trigger repeated liquidity withdrawals or swaps before initial balance checks ever close out.
3. Gas Griefing and Execution Denial
Because swap transactions have to run hook code to finish, the hook holds the keys to whether your trade passes or fails. A developer can write a beforeSwap hook that spins up infinite loops or eats through massive gas under hidden conditions. By pumping gas costs to astronomical levels for specific traders or during market crashes, the hook can lock traders out from closing positions or dodging bad liquidations.
4. Upgradable Logic and Unchecked Dependencies
A hook is an independent smart contract. The core Uniswap v4 Singleton is completely immutable, but a hook contract might carry admin keys, proxy setups, or references to external price oracles. If the creator holds an admin key, they can change how the hook behaves long after LPs deposit cash. A hook that acts totally clean on day one can be rewritten on day two to drain pool assets.
Worked Example: Honest vs. Malicious Dynamic Fee Hook

Let's look at numbers to see how fee manipulation actually steals cash. Picture a pool with Token X and Token Y, where 1 Token X = 1 Token Y. A trader wants to swap 10,000 Token X into the pool.
| Parameter | Standard Pool (No Hook) | Honest Dynamic Fee Hook | Malicious Dynamic Fee Hook |
|---|---|---|---|
| Input Amount | 10,000 Token X | 10,000 Token X | 10,000 Token X |
| Base Fee Rate | 0.30% | 0.30% (Dynamic: 0.1% to 1.0%) | 0.30% (Hidden override) |
| Hook Execution | None | Checks volatility, sets fee to 0.5% | Detects size > 5,000, sets fee to 20% |
| Fee Deducted | 30 Token X ($30) | 50 Token X ($50) | 2,000 Token X ($2,000) |
| Amount Swapped | 9,970 Token X | 9,950 Token X | 8,000 Token X |
| Trader Receives | ~9,970 Token Y | ~9,950 Token Y | ~8,000 Token Y |
| Value Stolen/Diverted | $0 | $0 (Fee stays in pool) | $1,970 diverted to attacker address |
In a standard pool, you lose 30 Token X to static fees. Under an honest dynamic hook, the fee bumps slightly to 50 Token X to protect LPs against market swings. But look at the malicious hook: the code inspects trade size inside beforeSwap, catches the big transaction, and jacks the fee to 20%. You lose 2,000 Token X ($2,000 worth) right at the door, and the hook routes that extra fee right into an attacker's vault.
How Hook Permissions Work: Address Bitmasks
How does the Uniswap v4 Singleton know which callbacks a hook is allowed to run? Address flags.
When a dev deploys a hook, the address itself must have specific leading bits set to 1 or 0. Devs do this using address mining—the same trick used to generate vanity addresses. The Singleton reads the first 14 bits of the hook's Ethereum address to map out its exact permissions:
- Bit 1: BEFORE_INITIALIZE_FLAG
- Bit 2: AFTER_INITIALIZE_FLAG
- Bit 3: BEFORE_ADD_LIQUIDITY_FLAG
- Bit 4: AFTER_ADD_LIQUIDITY_FLAG
- Bit 5: BEFORE_REMOVE_LIQUIDITY_FLAG
- Bit 6: AFTER_REMOVE_LIQUIDITY_FLAG
- Bit 7: BEFORE_SWAP_FLAG
- Bit 8: AFTER_SWAP_FLAG
- Bit 9: BEFORE_DONATE_FLAG
- Bit 10: AFTER_DONATE_FLAG
- Bit 11: BEFORE_SWAP_RETURNS_DELTA_FLAG
- Bit 12: AFTER_SWAP_RETURNS_DELTA_FLAG
- Bit 13: AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG
- Bit 14: AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG
If Bit 7 isn't set to 1, the Singleton will never touch beforeSwap on that hook, no matter what code sits inside the contract. That stops hooks from running rogue callbacks. But if the address bitmask explicitly enables BEFORE_SWAP_FLAG, the Singleton has no choice but to trust the hook's internal logic during execution.
How to Evaluate a Uniswap v4 Hook Pool
Before you trade tokens or stake liquidity in a v4 pool running custom hooks, run through these steps to check its security setup.
- Extract the Hook Address: Pull up the v4 pool initialization settings and find the exact contract address of the attached hook. If it's
0x0000000000000000000000000000000000000000, there's no hook attached. You're dealing with standard AMM security. - Decode the Permission Bitmask: Convert the address prefix to binary. See which permissions are active. If a pool claims to be a basic dynamic fee pool but has liquidity removal flags or custom delta flags turned on, run.
- Verify Source Code Verification on Block Explorers: Check if the hook contract code is verified on Etherscan or block explorers. Unverified hook code? Immediate red flag.
- Inspect for Admin Keys and Upgradability: Search the code for proxy patterns (like
UUPSorTransparentUpgradeableProxy),OnlyOwnermodifiers, or admin functions. If an admin can tweak fees, pause swaps, or move token flows, you aren't trusting code—you're trusting an admin key. - Check External Price Oracle Dependencies: Check if the hook queries external oracle contracts like Chainlink or custom TWAPs. If flash loans can manipulate the oracle, they can trick the hook into mispricing swaps.
- Run a Transaction Simulation: Before sending real funds, run the trade through a simulator like Tenderly or your wallet's built-in preview. Keep an eye on estimated token outputs and gas usage to catch hidden fee jumps.
Common Mistakes Traders and LPs Make
Moving from immutable AMM pools to programmable hook setups creates brand-new trapdoors for people relying on old rules.
Assuming Audited Means Safe
Uniswap v4's core contracts went through massive audits. But anyone can write and attach a custom hook to a brand-new pool. An audit on the core Uniswap v4 codebase tells you zero about the safety of a random hook written by an anonymous developer.
Ignoring Upgradability Risk
LPs love checking a hook's code at launch, verifying it looks clean, and dumping capital in. If that hook uses a proxy pattern, the developer can alter the underlying logic weeks later. That lets them slide in malicious fee routines or block liquidity withdrawals after cash accumulates.
Skipping Slippage and Minimum Output Checks
Traders using custom interfaces sometimes fire off trades with infinite slippage tolerance or zero minimum outputs. In standard pools, your max loss is bounded by price impact. In custom hook pools, setting zero minimum output lets dynamic fee hooks or custom delta hooks strip 100% of your trade value instantly.
Confusing Pool Fees with Hook Fees
Standard v4 pools display a base fee percentage in their metadata. But hooks can charge secondary fees or rewrite that base fee during execution. Relying strictly on the pool's listed static fee tier is an easy way to eat unexpected losses.
Frequently Asked Questions
Can a malicious hook steal liquidity directly from the main Singleton?
No. A hook can't arbitrarily alter balances inside the core Singleton unless it has explicit permissions granted when the pool was created. But if a hook holds liquidity management permissions or dynamic fee controls, it can squeeze value out during regular trades or withdrawals.
Are all Uniswap v4 pools required to use a hook?
Nope. Hooks are completely optional. A pool creator can launch a vanilla pool with zero hooks by passing an empty address (address(0)). Pools without hooks run standard, deterministic AMM math with the exact same risk profile as traditional AMMs.
How do I know if a hook contract can be updated by its creator?
Inspect the hook's code on a block explorer. Look for upgrade patterns like proxy contracts, functions like upgradeTo, or ownership tied to a single private key. If those are present, the contract controller can change execution behavior whenever they want.