Uniswap v4 Hooks
Learn how Uniswap v4 hooks extend pool behavior at key lifecycle execution points.
Uniswap v4 introduces Hooks, a system that allows developers to customize and extend the behavior of liquidity pools.
Hooks are external smart contracts that can be attached to individual pools. Every pool can have one hook but a hook can serve an infinite amount of pools to intercept and modify the execution flow at specific points during pool-related actions.
Key Concepts
Pool-specific hooks
- Each liquidity pool in Uniswap v4 can have its own hook contract attached to it. Hooks are optional for Uniswap v4Â pools.
- The hook contract is specified when creating a new pool in the
PoolManager.initialize function. - Having pool-specific hooks allows for fine-grained control and customization of individual pools.
Core Hook Functions
Uniswap v4 provides a set of core hook functions that can be implemented by developers. Developers do not have to implement every hook, you can mix&match them to whatever your liking is. You can use one or all of them!
- Hook contracts specify the permissions that determine which hook functions they implement, which is encoded in the address of the contract.
- The
PoolManageruses these permissions to determine which hook functions to call for a given pool based on its Key.
Initialize hooks
beforeInitialize: Called before a new pool is initialized.afterInitialize: Called after a new pool is initialized.- These hooks allow developers to perform custom actions or validations during pool initialization, but these hooks can only be invoked once.
Liquidity modification hooks
The liquidity modification hooks are extremely granular for security purposes.
beforeAddLiquidity: Called before liquidity is added to a pool.afterAddLiquidity: Called after liquidity is added to a pool.beforeRemoveLiquidity: Called before liquidity is removed from a pool.afterRemoveLiquidity: Called after liquidity is removed from a pool.
Swap hooks
beforeSwap: Called before a swap is executed in a pool.afterSwap: Called after a swap is executed in a pool.
Donate hooks
beforeDonate: Called before a donation is made to a pool.afterDonate: Called after a donation is made to a pool.- Donate hooks provide a way to customize the behavior of token donations to liquidity providers.
Innovation and Potential
The introduction of hooks in Uniswap v4 opens up a world of possibilities for developers to innovate and build new DeFi protocols. Some potential use cases include:
- Customized AMMs with different pricing curves than xy =Â k.
- Yield farming and liquidity mining protocols that incentivize liquidity provision.
- Derivative and synthetic asset platforms built on top of Uniswap v4Â liquidity.
- Lending hooks integrated with Uniswap v4Â pools.
As a hook developer you can easily bootstrap the codebase of an entirely new DeFi protocol through hook designs, which subsequently drives down your audit costs and allows you to develop faster. However, it's important to note that just because you made a hook, that does not mean you will get liquidity routed to your hook from the Uniswap frontend.
FAQ
When do I need a hook in Uniswap v4?
Hooks are optional. A v4 pool works without one, using the same concentrated liquidity behavior as Uniswap v3. You need a hook only when you want to customize pool behavior at specific lifecycle points, such as:
- Running logic before or after a swap
- Gating who can add or remove liquidity
- Applying dynamic fees
- Building custom accounting or a custom curve
If your use case is a standard pool, you do not need to write or attach a hook.
How do I deploy a hook to a valid hook address?
A hook contract must be deployed to an address whose low bits encode exactly the permissions it implements. Each hook function maps to a flag stored in a specific bit of the 20-byte address, so you cannot deploy a hook to an arbitrary address.
To get a valid address you mine a CREATE2 salt that produces an address with the correct flag bits set, then deploy with that salt. The HookMiner helper library finds the salt:
uint160 flags = uint160(Hooks.AFTER_ADD_LIQUIDITY_FLAG | Hooks.AFTER_SWAP_FLAG);
bytes memory constructorArgs = abi.encode(POOLMANAGER);
(address hookAddress, bytes32 salt) =
HookMiner.find(CREATE2_DEPLOYER, flags, type(PointsHook).creationCode, constructorArgs);The deployment script then asserts that the deployed address matches the mined address. For local testing, Foundry's deployCodeTo cheatcode can place a hook at any address without mining. See Hook Deployment for the full walkthrough.
What hook permissions are available in Uniswap v4?
A hook declares its permissions through getHookPermissions, which returns a struct of boolean flags. The call permissions are:
beforeInitialize/ÂafterInitializebeforeAddLiquidity/ÂafterAddLiquiditybeforeRemoveLiquidity/ÂafterRemoveLiquiditybeforeSwap/ÂafterSwapbeforeDonate/ÂafterDonate
There are also four return-delta permissions that let a hook adjust balances: beforeSwapReturnDelta, afterSwapReturnDelta, afterAddLiquidityReturnDelta, and afterRemoveLiquidityReturnDelta. A hook implements only the functions it needs, and those choices must match the flags encoded in its address. See the full flag list in Hooks.sol.
Can I add a hook to an existing pool?
No. The hook is part of the PoolKey and is set once when the pool is created through PoolManager.initialize. It cannot be added, removed, or swapped afterward.
To use a different hook, or to add one to a pool that has none, you create a new pool with the desired hook in its key. A single hook contract can serve many pools, so you do not need to redeploy the hook itself.
How do I test a Uniswap v4 hook?
Most hook development uses Foundry. The v4-template repository ships a preconfigured project with v4-core and v4-periphery already imported:
git clone https://github.com/uniswapfoundation/v4-template.git
cd v4-template
forge install
forge testFor unit tests you can deploy the hook to a valid address using the deployCodeTo cheatcode, which avoids mining during tests. You can also run a local Anvil node, deploy v4 and your hook with a Foundry script, and point the test suite at it:
forge test --rpc-url 127.0.0.1:8545See Hooks Overview for the full local setup.
What happens if the address flags do not match the implemented functions?
The address flags and the implemented functions must agree:
- If the address lacks a flag, the
PoolManagernever calls that hook function, so the logic silently does nothing. - Permissions are validated against the address at deployment, so declaring permissions that do not match the mined address makes the deployment fail.
Mining the correct address and declaring matching permissions through getHookPermissions keeps the two in sync.