uniswap-v4-hooks
|
Install in one line
CLI$ mfkvault install igoryuzo-uniswapv4-hooks-skillRequires the MFKVault CLI. Prefer MCP?
Free to install — no account needed
Copy the command below and paste into your agent.
Instant access • No coding needed • No account needed
What you get in 5 minutes
- Full skill code ready to install
- Works with 4 AI agents
- Lifetime updates included
Run this helper
Answer a few questions and let this helper do the work.
▸Advanced: use with your AI agent
Description
--- name: uniswap-v4-hooks description: | Secure Uniswap v4 hook development assistant. Activates when: - Working with Uniswap v4 hooks, PoolManager, or hook contracts - Keywords: uniswap, v4, hook, hooks, beforeSwap, afterSwap, PoolManager, IHooks, BaseHook - Creating, reviewing, or auditing hook contracts - Implementing custom AMM logic, dynamic fees, or swap modifications - User says "uniswap hooks" or invokes "/uniswap-v4-hooks" --- This skill guides secure development of Uniswap v4 hooks. Hooks are external smart contracts that intercept pool operations at specific lifecycle points. Security is paramount—hook vulnerabilities can drain user funds. ## Security Thinking Before writing ANY hook code, assess the threat model: **Who calls your hook?** - Only `PoolManager` should call hook functions - `msg.sender` in a hook is ALWAYS `PoolManager`, never the user - The `sender` parameter is the router, not the end user **What state is exposed?** - Hooks execute mid-transaction—state can be manipulated between callbacks - Reentrancy is possible through external calls - Shared storage across pools using the same hook can break unexpectedly **What can go wrong with deltas?** - Every token in MUST equal tokens out (delta accounting) - Rounding errors accumulate in iterative operations - BeforeSwapDelta can bypass normal swap logic entirely ## CRITICAL: The NoOp Rug Pull Vector Hooks with `BEFORE_SWAP_RETURNS_DELTA_FLAG` can **steal user funds**. This is the most dangerous hook permission. ```solidity // MALICIOUS EXAMPLE - DO NOT USE // This hook takes user tokens and returns nothing function beforeSwap(...) external returns (bytes4, BeforeSwapDelta, uint24) { Currency input = params.zeroForOne ? key.currency0 : key.currency1; // Take all user funds input.take(poolManager, address(this), uint256(-params.amountSpecified), false); // Return delta saying we took everything, returning zero return ( BaseHook.beforeSwap.selector, toBeforeSwapDelta(int128(-params.amountSpecified), 0), // THEFT 0 ); } ``` **When `beforeSwapReturnDelta: true`:** - The hook can completely replace swap logic - Pool math is SKIPPED if delta equals amountSpecified - User funds flow to the hook, not through the AMM curve **Defense:** NEVER enable `beforeSwapReturnDelta` unless implementing a legitimate custom AMM. Users should verify hook permissions before swapping. ## Permission Flags (Address Encoding) Hook permissions are encoded in the contract address. The address must have specific bits set: | Bit | Permission | Risk Level | |-----|------------|------------| | 0 | beforeInitialize | Low | | 1 | afterInitialize | Low | | 2 | beforeAddLiquidity | Medium | | 3 | afterAddLiquidity | Medium | | 4 | beforeRemoveLiquidity | Medium | | 5 | afterRemoveLiquidity | Medium | | 6 | beforeSwap | High | | 7 | afterSwap | Medium | | 8 | beforeDonate | Low | | 9 | afterDonate | Low | | 10 | beforeSwapReturnDelta | **CRITICAL** | | 11 | afterSwapReturnDelta | High | | 12 | afterAddLiquidityReturnDelta | Medium | | 13 | afterRemoveLiquidityReturnDelta | Medium | **Address Mining:** Use CREATE2 with salt grinding to deploy at an address with correct permission bits. Tools: `hook-mine-and-sinker`, `v4-hook-address-miner`. ## Access Control Pattern ```solidity // REQUIRED: Verify caller is PoolManager modifier onlyPoolManager() { require(msg.sender == address(poolManager), "Not PoolManager"); _; } function beforeSwap( address sender, // This is the ROUTER, not the user PoolKey calldata key, IPoolManager.SwapParams calldata params, bytes calldata hookData ) external onlyPoolManager returns (bytes4, BeforeSwapDelta, uint24) { // ... } ``` ## Identifying the Actual User (msg.sender Problem) The `sender` parameter is the router contract, NOT the end user. To get the actual user: ```solidity // 1. Define interface for trusted routers interface IMsgSender { function msgSender() external view returns (address); } // 2. Maintain allowlist of trusted routers mapping(address => bool) public trustedRouters; // 3. Query router safely in hook function afterSwap( address sender, // This is the router PoolKey calldata key, IPoolManager.SwapParams calldata params, BalanceDelta delta, bytes calldata hookData ) external override returns (bytes4, int128) { // CRITICAL: Only trust verified routers if (!trustedRouters[sender]) { revert UntrustedRouter(sender); } // Safe to query actual user try IMsgSender(sender).msgSender() returns (address user) { // Use `user` for rewards, tracking, etc. } catch { revert RouterDoesNotImplementMsgSender(); } return (this.afterSwap.selector, 0); } ``` **NEVER trust `tx.origin`** for authentication (only acceptable for anti-gaming checks like self-referral prevention). ## Delta Accounting Rules Deltas track what the hook owes or is owed. They MUST net to zero. ```solidity // Taking tokens FROM PoolManager (hook receives tokens) currency.take(poolManager, address(this), amount, false); // Settling tokens TO PoolManager (hook sends tokens) currency.settle(poolManager, address(this), amount, false); // INVARIANT: All deltas must balance before unlock completes ``` **Common Delta Bugs:** - Forgetting to settle after taking - Rounding in wrong direction (always round against the user/hook) - Not handling both swap directions (zeroForOne true AND false) ## Hook Implementation Checklist Before ANY hook implementation: - [ ] **Access Control**: Only PoolManager can call hook functions - [ ] **Delta Balance**: Every take has a corresponding settle - [ ] **Router Verification**: Never trust sender without allowlist check - [ ] **Overflow Protection**: Use `mulDiv` for price math, never raw multiplication - [ ] **Reentrancy Guards**: Add if making external calls - [ ] **Token Type Handling**: Document unsupported tokens (rebasing, fee-on-transfer) - [ ] **Permission Flags**: Minimal permissions needed for functionality ## Base Hook Template ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.26; import {BaseHook} from "v4-periphery/src/base/hooks/BaseHook.sol"; import {IPoolManager} from "v4-core/interfaces/IPoolManager.sol"; import {PoolKey} from "v4-core/types/PoolKey.sol"; import {BalanceDelta} from "v4-core/types/BalanceDelta.sol"; import {Hooks} from "v4-core/libraries/Hooks.sol"; contract MyHook is BaseHook { constructor(IPoolManager _manager) BaseHook(_manager) {} function getHookPermissions() public pure override returns (Hooks.Permissions memory) { return Hooks.Permissions({ beforeInitialize: false, afterInitialize: false, beforeAddLiquidity: false, afterAddLiquidity: false, beforeRemoveLiquidity: false, afterRemoveLiquidity: false, beforeSwap: false, afterSwap: true, // Enable only what you need beforeDonate: false, afterDonate: false, beforeSwapReturnDelta: false, // DANGEROUS - enable with caution afterSwapReturnDelta: false, afterAddLiquidityReturnDelta: false, afterRemoveLiquidityReturnDelta: false }); } function _afterSwap( address sender, PoolKey calldata key, IPoolManager.SwapParams calldata params, BalanceDelta delta, bytes calldata hookData ) internal override returns (bytes4, int128) { // Your logic here return (this.afterSwap.selector, 0); } } ``` ## Common Vulnerability Patterns ### 1. Overflow in Price Calculations ```solidity // BAD: Can overflow uint256 price = uint256(sqrtPriceX96) ** 2; // GOOD: Use mulDiv uint256 price = FullMath.mulDiv(uint256(sqrtPriceX96), uint256(sqrtPriceX96), 1 << 96); ``` ### 2. Incorrect Fee Calculation ```solidity // BAD: Simple addition is wrong uint256 totalFee = protocolFee + lpFee; // GOOD: Protocol fee taken first, then LP fee from remainder // protocolFee + lpFee * (1_000_000 - protocolFee) / 1_000_000 ``` ### 3. Missing Timestamp Validation ```solidity // BAD: No future check function submitOrder(uint256 expiration) external { orders[msg.sender] = Order(expiration, ...); } // GOOD: Validate expiration is in future function submitOrder(uint256 expiration) external { require(expiration > block.timestamp, "Expiration must be in future"); require(expiration % interval == 0, "Must align to interval"); orders[msg.sender] = Order(expiration, ...); } ``` ### 4. Trusting Sender Without Verification ```solidity // BAD: sender could be malicious contract address user = sender; // GOOD: Verify router and query actual user require(trustedRouters[sender], "Untrusted router"); address user = IMsgSender(sender).msgSender(); ``` ## Token Handling Hazards **Unsupported token types** (document explicitly if your hook doesn't handle): - **Fee-on-transfer**: Actual received amount differs from transfer amount - **Rebasing**: Balance changes without transfers - **ERC-777**: Reentrancy via transfer hooks - **Pausable**: Transfers can revert unexpectedly - **Blocklist**: Some addresses may be blocked ```solidity // If handling non-standard tokens, validate actual balances uint256 balanceBefore = token.balanceOf(address(this)); token.transferFrom(user, address(this), amount); uint256 actualReceived = token.balanceOf(address(this)) - balanceBefore; ``` ## Testing Requirements Use Foundry for comprehensive testing: ```solidity // Invariant test: Deltas always balance function invariant_deltasBalance() public { assertEq(poolManager.currencyDelta(address(hook), currency0), 0); assertEq(poolManager.currencyDelta(address(hook), currency1), 0); } // Fuzz test: No overflow in price calculations function testFuzz_priceCalculation(uint160 sqrtPriceX96) public { vm.assume(sqrtPriceX96 >= TickMath.MIN_SQRT_PRICE); vm.assume(sqrtPriceX96 <= TickMath.MAX_SQRT_PRICE); // Should not revert hook.calculatePrice(sqrtPriceX96); } // Test both swap directions function test_swapZeroForOne() public { ... } function test_swapOneForZero() public { ... } ``` ## Risk Assessment (Self-Score) Before deployment, score your hook (0-33 scale): | Dimension | Score Range | Your Hook | |-----------|-------------|-----------| | Code Complexity | 0-5 | | | Custom Math | 0-5 | | | External Dependencies | 0-3 | | | External Liquidity | 0-3 | | | TVL Potential | 0-5 | | | Team Maturity | 0-3 | | | Upgradeability | 0-3 | | | Autonomous Updates | 0-3 | | | Price-Impacting | 0-3 | | **Risk Tiers:** - **Low (0-6)**: 1 audit + AI static analysis - **Medium (7-17)**: 1-2 audits + bug bounty recommended - **High (18-33)**: 2 audits (1 math specialist) + mandatory bug bounty + monitoring ## Production Hooks Reference Allowlisted hooks on Uniswap (as of Jan 2025): - Flaunch (meme coin launchpad, 100% fees to creators) - EulerSwap (lending-powered DEX) - Zaha Studios TWAMM (time-weighted orders) - Coinbase Verified Pools - Panoptic Oracle Hook - AEGIS Dynamic Fee Mechanism Study these for patterns: https://raw.githubusercontent.com/fewwwww/awesome-uniswap-hooks/refs/heads/main/README.md ## NEVER Do This - NEVER enable `beforeSwapReturnDelta` without understanding the rug pull risk - NEVER trust `sender` parameter without router verification - NEVER use `unchecked` blocks for price/amount math - NEVER assume ERC20 standard behavior for all tokens - NEVER skip delta settlement - NEVER deploy without address permission verification - NEVER store sensitive state readable mid-swap - NEVER use `tx.origin` for authentication ## Resources - **v4-core**: https://github.com/Uniswap/v4-core - **v4-periphery**: https://github.com/Uniswap/v4-periphery - **Security Framework**: https://docs.uniswap.org/contracts/v4/security - **Hook Examples**: https://github.com/fewwwww/awesome-uniswap-hooks - **Address Mining**: https://github.com/hensha256/hook-mine-and-sinker - **v4 by Example**: https://v4-by-example.org ## Audit Checklist (Pre-Deployment) - [ ] All hook functions check `msg.sender == poolManager` - [ ] Deltas verified to net zero in all paths - [ ] No overflow possible in math operations - [ ] Router allowlist implemented if identifying users - [ ] Token types explicitly documented - [ ] Reentrancy guards on external calls - [ ] Timestamp validations in place - [ ] Permission flags minimal and correct - [ ] Fuzz tests pass for edge cases - [ ] Invariant tests for delta accounting - [ ] Both swap directions tested - [ ] Fee calculations match Uniswap's formula
Security Status
Unvetted
Not yet security scanned
Related AI Tools
More Save Money tools you might like
Family History Research Planning Skill
FreeProvides assistance with planning family history and genealogy research projects.
Naming Skill
FreeName products, SaaS, brands, open source projects, bots, and apps. Use when the user needs to name something, find a brand name, or pick a product name. Metaphor-driven process that produces memorable, meaningful names and avoids AI slop.
Profit Margin Calculator
$7.99Find hidden profit leaks — see exactly where your money goes
guard-scanner
Free"Security scanner and runtime guard for OpenClaw skills, MCP servers, and AI agent workflows. Detects prompt injection, identity hijacking, memory poisoning, A2A contagion, secret leaks, supply-chain abuse, and dangerous tool calls with 364 static th
Life OS · Personal Decision Engine
Free"A personal decision engine with 16 independent AI agents, checks and balances, and swappable cultural themes. Covers relationships, finance, learning, execution, risk control, health, and infrastructure. Use when facing complex personal decisions (c
bbc-skill — Bilibili Comment Collector
FreeFetch Bilibili (哔哩哔哩) video comments for UP主 self-analysis. Use when the user asks to collect, download, export, or analyze comments on a Bilibili video (BV号 / URL / UID). Produces JSONL + summary.json suitable for further Claude Code analysis (senti