A base kit for building Uniswap v4 hooks — a clean BaseHook, four production-shaped example hooks (dynamic fee, TWAP oracle, allowlist, anti-snipe) and the CREATE2 address-mining helper you can't deploy without.
HOOKED
Solidity Uniswap License Build
A base kit for building Uniswap v4 hooks — a clean BaseHook, four production-shaped example hooks, and the address-mining helper you can't deploy without.When v4 shipped at the end of January 2025, I dropped what I was doing. Hooks change the game. For the first time, a pool isn't a fixed AMM — it's a programmable surface where you can run your own logic at every lifecycle point: before/after initialize, add/remove liquidity, swap, donate. Dynamic fees, on-chain oracles, limit orders, MEV capture, KYC pools, anti-snipe launches — things that needed a whole protocol in v3 are now ~100 lines bolted onto a pool. The design space just exploded, and most of it is unbuilt. I wanted to be early and fluent. So I built the scaffolding I'd reach for on every v4 project and a few hooks that show what the surface can do.
v4 in 60 seconds (what changed)
- One singleton
PoolManagerholds every pool — not a contract per pair. - Hooks are external contracts a pool calls at lifecycle points. A pool commits to one hook at init.
- A hook's permissions are encoded in its ADDRESS. The low 14 bits say which callbacks fire (
beforeSwap,afterSwap, …). You don't configure this — you mine a CREATE2 salt so the deployed address carries the right bits, or the PoolManager won't call you (andBaseHookrefuses to deploy). That's whatHookMineris for. - Flash accounting: balances net out within one
unlockcallback and settle at the end — cheaper, composable. - Dynamic fees: a pool can defer its fee to its hook on every swap.
What's in the kit
| File | What it is |
|---|---|
BaseHook.sol | Implements the full IHooks surface; you override only the _-callbacks you use. Locks every entrypoint to the PoolManager and self-checks its address bits against the permissions it declares. Depends only on @uniswap/v4-core. |
lib/HookMiner.sol | Finds a CREATE2 salt whose address carries your permission flags. Without it you can't deploy a hook. |
hooks/ReferenceHook.sol | Every callback in one file — all 10 lifecycle hooks + all 14 permission bits, each annotated with what you can do (and return) there. Not for deployment; a map of the whole surface to copy from. |
hooks/DynamicFeeHook.sol | Overrides the LP fee per swap (size-based surge here — swap in your own signal). The v4 capability v3 never had. |
hooks/TwapOracleHook.sol | A built-in geomean tick oracle per pool — accumulates time-weighted ticks in afterSwap; no separate oracle contract. |
hooks/AllowlistHook.sol | A permissioned / KYC pool — gates swaps & liquidity by an owner-managed allowlist. |
hooks/LaunchGuardHook.sol | Anti-snipe: caps swap size for the first N blocks after launch, killing the block-0 sweep. |
Each hook is a few dozen lines on top of BaseHook — that's the point: the hard part (PoolManager auth, address validation, the IHooks surface) is handled once.
Install
These hooks build on the real v4 contracts:
forge install uniswap/v4-coreremappings.txt:
@uniswap/v4-core/=lib/v4-core/foundry.toml needs Cancun (v4 uses transient storage):
solc = "0.8.26"evm_version = "cancun"Pin v4-core to a recent commit. These hooks importSwapParams/ModifyLiquidityParamsfrom@uniswap/v4-core/src/types/PoolOperation.sol; on older tags those structs still live insideIPoolManager. Match the version you build against.
Writing a hook
contract MyHook is BaseHook { constructor(IPoolManager pm) BaseHook(pm) {} function getHookPermissions() public pure override returns (Hooks.Permissions memory p) { p.beforeSwap = true; // declare only what you use } function _beforeSwap(address, PoolKey calldata, SwapParams calldata, bytes calldata) internal override returns (bytes4, BeforeSwapDelta, uint24) { // your logic here return (IHooks.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA, 0); }}Deploying a hook (the address-mining step)
import {HookMiner} from "./lib/HookMiner.sol"; uint160 flags = uint160(Hooks.BEFORE_SWAP_FLAG); // the callbacks you enabled(address hookAddr, bytes32 salt) = HookMiner.find( CREATE2_DEPLOYER, // e.g. 0x4e59b44847b379578588920cA78FbF26c0B4956C flags, type(MyHook).creationCode, abi.encode(poolManager) // constructor args);MyHook hook = new MyHook{salt: salt}(poolManager);require(address(hook) == hookAddr); // address carries the permission bitsBaseHook's constructor calls Hooks.validateHookPermissions(this, getHookPermissions()) — deploy at a wrong address and it reverts, by design.
Status
An open-source starter kit for building on Uniswap v4 — study it, fork it, build your own hooks on top. Requires @uniswap/v4-core. Provided as-is and unaudited; hooks sit in the critical path of every swap, so test thoroughly (v4-core ships Deployers test utilities) and audit before mainnet.
License
MIT © 2025 c0llback
Built right after the v4 launch — because the most interesting surface in DeFi just opened, and I wanted to be building on it on day one.