Development of Uniswap v4 Hooks
Uniswap v4 inverts DEX architecture: instead of thousands of separate pool contracts, a single singleton PoolManager and infinitely extensible logic through hooks. This isn't just a refactor—it's a platform where a custom hook can implement dynamic fees, built-in TWAP oracles, automatic rebalancing, or permission systems without forking the core protocol. We develop production-ready hooks with full test coverage and audit-ready documentation.
Hook Architecture: Critical Understanding Before Code
Hook Address as Configuration
In v4, a hook's address is its configuration. The last 14 bits of the address encode which callback functions the hook implements: beforeSwap, afterSwap, beforeAddLiquidity, afterAddLiquidity, and others—14 flags total. PoolManager reads the hook address on pool registration and knows which callbacks to invoke without extra on-chain queries.
Consequence: you cannot simply deploy a contract and get the desired address. You need mining—iterating through salt values in CREATE2 until the address contains the correct bits. Foundry automates this:
bytes32 salt = HookMiner.find(deployer, flags, creationCode, constructorArgs);
With incorrect flags, PoolManager.initialize reverts with HookAddressNotValid. This is the first place most stumble when upgrading from v3.
BeforeSwap and AfterSwap: Asymmetric Control
beforeSwap can return (bytes4 selector, BeforeSwapDelta delta, uint24 lpFeeOverride). Through delta, the hook can modify the number of tokens participating in the swap—essentially intercepting part of the flow. Through lpFeeOverride, it can set a dynamic fee for this particular swap instead of the static fee set at pool initialization.
afterSwap receives BalanceDelta—the swap result—and can add custom logic on top. A typical use case: a rebate hook that returns part of the fee to active LPs as tokens.
Important nuance: hooks operate in the context of the PoolManager transaction. All token operations use flash accounting—real ERC-20 transfers only happen at the end through settle/take. If a hook tries a direct transfer inside a callback, it breaks flash accounting and causes revert or, worse, incorrect balance state.
Reentrancy in v4: New Rules
PoolManager is protected by a Lock modifier—only one lock call is active simultaneously. A hook attempting to call PoolManager.swap inside beforeSwap gets a revert. This means architectures where hooks must initiate secondary swaps (e.g., automatic rebalancing) require deferred execution—through an external contract queue or through afterSwap with a separate subsequent call.
How We Develop Hooks
Common Use Cases from Practice
Dynamic fees based on volatility. The hook reads TWAP from its own accumulator (updated in afterSwap), calculates σ over the last N blocks, maps σ to fee tier: low volatility → 0.01%, high → 1%. lpFeeOverride is returned in beforeSwap. LPs automatically get protection during sharp moves without manual intervention.
Whitelist hook for permissioned pools. In beforeSwap and beforeAddLiquidity, check merkleProof or ERC-721 balance of the swapper. Addresses without access get a revert. Used for institutional pools with KYC restrictions.
LVR mitigation through auction. A before-swap hook implements a commit-reveal scheme: MEV bots must bid for the right to the first swap in a block. Auction revenue goes to LP. Reduces Loss-Versus-Rebalancing for passive liquidity providers.
Stack and Tools
Development uses Foundry with v4-template from Uniswap. Tests fork Ethereum Sepolia (v4 is already deployed on testnet). HookTest base contract provides deployFreshManagerAndRouters—no need to set up mock PoolManager manually.
For mining hook addresses, use HookMiner from v4-periphery. In CI, this is a step before tests: mine salt, pass to deployment script.
Verify flag correctness with a dedicated test:
assertEq(uint160(address(hook)) & HookFlags.ALL_FLAGS, expectedFlags);
A failed test immediately shows that the address was mined incorrectly.
Audit-Specific Aspects
Standard Slither detectors don't know about v4 callback contracts. Write custom detectors for specific patterns:
- Direct ERC-20 transfer inside a callback (breaks flash accounting)
- Reading
slot0directly instead of through PoolManager (outdated v3 pattern) - Missing
msg.sender == address(poolManager)check in callback functions
The last point is critical: if the hook doesn't verify who calls beforeSwap, anyone can call it directly with arbitrary parameters. Depending on logic, this can lead to state manipulation without a real swap.
Work Process
Analytics (2-3 days). Formalize hook logic: which callbacks are needed, is there custom storage, do you need oracle access. Check compatibility with existing pool architecture.
Design (2-3 days). Hook-to-PoolManager interaction scheme, storage layout definition (minimize SLOAD in hot paths), interface for owner configuration.
Development (1-2 weeks). Implement callback functions, fork tests on Sepolia, fuzz-tests on input boundary values.
Audit. Custom Slither detectors + manual review of all paths where the hook modifies BeforeSwapDelta. Document invariants for external auditors.
Deployment. HookMiner in CI, deployment script via Foundry with flag verification. Monitor the PoolManager event log for the first 72 hours post-deployment.
Timeline Estimates
Simple hook (single callback, read-only): 4-6 days. Hook with dynamic fees and custom oracle: 1-2 weeks. Complex hook with auction mechanics or custom LP position tracking: 3-4 weeks.
Pricing calculated after technical specification analysis.







