Hooks in Uniswap v4 are external contracts that execute specific actions at certain points during the execution of a liquidity pool. These hooks provide flexibility and customization options for developers to create additional features for liquidity pools.
Uniswap v4 hooks can be used to:
- Execute large orders gradually over time using TWAMM (Time-Weighted Average Market Making)
- Implement on-chain limit orders that fill at specific prices
- Adjust fees dynamically based on market volatility or price movements
- Develop mechanisms to prevent or syphon MEV for liquidity providers
- Create custom oracle implementations (Uniswap TWAP price lookup is no longer implemented as default)
- Execute malicious code, users need to be careful about which pools they interact with
A 3rd party developer can write a solidity hook contract with custom logic prior to setting up the pool. When the liquidity pool is created on Uniswap v4, the hook contract can be specified.
Uniswap v4 currently supports eight different hook callbacks:
- beforeInitialize
- afterInitialize
- beforeModifyPosition
- afterModifyPosition
- beforeSwap
- afterSwap
- beforeDonate
- afterDonate
The donate hooks run before and after donate() is called which transfers fees to the pool at the end of the transaction. Uniswap v4 enables fees to be charged for both swapping and withdrawing liquidity
The capabilities of a hook are determined by immutable flags set when the pool is created.
There are example hooks published by the Uniswap team at: https://github.com/Uniswap/v4-periphery/tree/main/contracts/hooks/examples
And some code that I’ve been playing with here: https://github.com/jamesbachini/Uniswap-v4-Tests
We start by importing relevant libraries including the v4-core Hooks.sol
import {Hooks} from "@uniswap/v4-core/contracts/libraries/Hooks.sol";
We can then overwrite the getHooksCalls() function to declare what hooks we wish to activate.
function getHooksCalls() public pure override returns (Hooks.Calls memory) {
return Hooks.Calls({
beforeInitialize: false,
afterInitialize: false,
beforeModifyPosition: false,
afterModifyPosition: false,
beforeSwap: true,
afterSwap: false,
beforeDonate: false,
afterDonate: false
});
}
We can then overwrite the beforeSwap function
function beforeSwap(
address,
IPoolManager.PoolKey calldata key,
IPoolManager.SwapParams calldata
) external override poolManagerOnly returns (bytes4) {
// doSomethingInteresting
return ThisContract.beforeSwap.selector;
}
We return the 4 byte selector for the function after our code executes.
Uniswap v4 hooks provide Solidity developers with a lot more power to create liquidity pools with custom logic and functionality. There are security concerns around how users are exposed to that custom logic which could potentially contain malicious code. For devs it provides an opportunity to more closely integrate DeFi protocols with the largest decentralized exchange and create new systems for efficient liquidity.