C0LLBACK
c0llback/hooked

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.

solidityuniswap-v4hooksammdefiethereum
Solidity ^0.8.24License MITNetwork Ethereum9 files
Solidity 81.8%Markdown 15.3%Text 2.9%
c0llbacke4c7b21kit: BaseHook + dynamic-fee / TWAP-oracle / allowlist / launch-guard hooks + HookMinerFeb 11, 2025
README.md

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 PoolManager holds 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 (and BaseHook refuses to deploy). That's what HookMiner is for.
  • Flash accounting: balances net out within one unlock callback 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

FileWhat it is
BaseHook.solImplements 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.solFinds a CREATE2 salt whose address carries your permission flags. Without it you can't deploy a hook.
hooks/ReferenceHook.solEvery 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.solOverrides the LP fee per swap (size-based surge here — swap in your own signal). The v4 capability v3 never had.
hooks/TwapOracleHook.solA built-in geomean tick oracle per pool — accumulates time-weighted ticks in afterSwap; no separate oracle contract.
hooks/AllowlistHook.solA permissioned / KYC pool — gates swaps & liquidity by an owner-managed allowlist.
hooks/LaunchGuardHook.solAnti-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-core

remappings.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 import SwapParams / ModifyLiquidityParams from @uniswap/v4-core/src/types/PoolOperation.sol; on older tags those structs still live inside IPoolManager. 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 bits

BaseHook'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.

← Back to index© 2020 c0llbackMIT