mcpField
V
v4-hook-generator

v4-hook-generator

github.com/uniswap开发236692 次安装2 天前更新
代码仓库

关于 v4-hook-generator

v4-hook-generator 是一项技能,通过 OpenZeppelin Contracts Wizard 配置并生成 Uniswap v4 hook 合约。它帮助 Solidity 开发者选择 hook 类型和参数、组装 MCP 请求,并安排后续安全审查。

主要功能

  1. 01比较适用于不同目标的 14 种 hook
  2. 02配置权限、工具库、份额和访问控制
  3. 03组装规范的 MCP 工具调用 JSON
  4. 04选择 hook 专用数值参数
  5. 05遵循生成到安全审查的流程

适用场景

  1. 01搭建费用、预言机或 MEV 防护 hook
  2. 02为自定义 hook 逻辑选择权限
  3. 03准备 generate_hook 请求
  4. 04在实现前权衡配置选项

MCP 相关

指导构造 OpenZeppelin Contracts Wizard MCP 工具 `generate_hook` 的请求,该工具用于生成 Solidity hook 代码。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/uniswap/uniswap-ai --skill v4-hook-generator

安装后在 Claude Code 中输入/v4-hook-generator确认已加载。

详细介绍

v4 钩子生成器

通过 OpenZeppelin Contracts Wizard MCP 工具生成 Uniswap v4 钩子合约。本技能将指导你选择合适的钩子类型、配置权限和实用工具、组装规范的 MCP JSON,并调用 MCP 工具生成可直接编译的 Solidity 代码。

安全配套技能:生成的钩子代码涉及处理资金的合约。生成后请立即应用 v4-security-foundations 技能,在部署到任何网络之前审计权限、差额记账和访问控制。

何时使用此技能

在以下情况下使用此技能:

  • 从头搭建新的 Uniswap v4 钩子合约
  • 针对特定用例(费用、MEV 保护、预言机等)选择合适的基础钩子类型
  • 配置钩子权限、实用工具库、份额和访问控制
  • 生成调用 OpenZeppelin Contracts Wizard 的规范 MCP 工具调用 JSON
  • 在确定实现方案之前,了解不同钩子配置选项之间的权衡

前置/配套技能:v4-security-foundations — 编写自定义逻辑前以及部署前都要运行此技能。钩子配置不当可能导致用户资金被盗。

钩子类型决策表

选择与主要目标匹配的基础钩子类型。如果钩子有多个目标,请选择覆盖最关键问题的类型,并在此基础上叠加其他逻辑。

目标使用钩子
自定义交换逻辑BaseHook
异步/延迟交换BaseAsyncSwap
钩子自有流动性BaseCustomAccounting
自定义曲线BaseCustomCurve
动态 LP 费用BaseDynamicFee
动态交换费用BaseOverrideFee
交换后费用BaseDynamicAfterFee
固定钩子费用BaseHookFee
MEV 保护AntiSandwichHook
JIT 保护LiquidityPenaltyHook
限价订单LimitOrderHook
闲置资金收益ReHypothecationHook
预言机BaseOracleHook
兼容 V3 的预言机OracleHookWithV3Adapters

选择建议:

  • BaseHook 是通用的起点——只有在专用类型的内置逻辑能带来明确价值时,才选择专用类型。
  • BaseCustomCurve 会替换整个 AMM 数学逻辑;仅在实现新颖的定价算法时使用。
  • AntiSandwichHook 和 LiquidityPenaltyHook 都用于应对 MEV,但针对的对象不同(交易者与 JIT LP)。请明确要缓解哪种攻击途径。
  • 如果下游集成需要兼容 Uniswap v3 IUniswapV3Pool 的预言机接口,则适合使用 OracleHookWithV3Adapters。

最简决策清单

调用 MCP 工具之前,请确认以下六项决定:

  1. 钩子类型——从上方的决策表中选择
  2. 要启用的权限——仅启用逻辑实际使用的回调(beforeSwap、afterSwap 等)
  3. 实用工具库——按需使用 currencySettler、safeCast、transientStorage
  4. 份额——false、ERC20、ERC6909 或 ERC1155
  5. 访问控制——ownable、roles 或 managed
  6. 钩子输入项——blockNumberOffset、maxAbsTickDelta(仅适用于会用到这些参数的钩子类型)

权限配置

共 14 个权限标志,并说明何时启用。请先将所有标志设为 false,仅启用钩子逻辑所需的标志。每启用一项权限,都会扩大钩子的攻击面,并要求在钩子的已部署地址中设置特定的位(见下方的地址编码说明)。

权限标志启用时机风险
beforeInitialize需要验证或限制池创建参数时低
afterInitialize需要在创建池后设置状态时低
beforeAddLiquidity需要限制或转换 LP 存款时中
afterAddLiquidity需要跟踪 LP 仓位或分发奖励时低
beforeRemoveLiquidity需要设置锁定期或收取退出费用时高
afterRemoveLiquidity需要为记账跟踪仓位移除情况时低
beforeSwap需要修改交换行为、应用动态费用或阻止交换时高
afterSwap需要观察最终交换状态以供预言机或记账使用时中
beforeDonate需要限制哪些地址可以向池捐赠时低
afterDonate需要跟踪捐赠事件时低
beforeSwapReturnDelta实现自定义 AMM 曲线或 JIT 流动性时(严重:NoOp 攻击途径——见 v4-security-foundations)严重
afterSwapReturnDelta需要从交换输出中提取钩子费用时高
afterAddLiquidityReturnDelta需要在存款时调整 LP 代币数量高
afterRemoveLiquidityReturnDelta需要调整提款金额时高

地址编码说明:权限以位的形式编码在钩子合约的已部署地址中。部署时必须在地址中设置正确的位,否则 PoolManager 将回滚。使用 HookMiner(来自 v4-periphery)挖掘能生成正确位模式地址的盐值。部署后绝不可更改权限,因为地址不可变。

实用工具库选择

生成的 hook 可选包含三个实用工具库。只包含 hook 逻辑实际用到的库。

库包含条件
currencySettlerhook 会在自身与 PoolManager 之间转移代币(例如,自定义记账、收取费用)
safeCasthook 执行的算术运算在不同整数类型转换时可能溢出
transientStoragehook 需要在单笔交易内的回调之间传递数据,但不将数据持久化到存储中(要求 EVM Cancun 或更高版本,Solidity >= 0.8.24)

指南:

  • 启用 beforeSwapReturnDelta、afterSwapReturnDelta、afterAddLiquidityReturnDelta 或 afterRemoveLiquidityReturnDelta 时,几乎总是需要 currencySettler——它提供 settle 和 take 辅助函数,用于实现正确的 sync → transfer → settle 顺序。
  • transientStorage 是一种节省 Gas 的替代方案,可用于存储交易内状态。 使用它可以将标志或值从 beforeSwap 传递到 afterSwap,避免为冷 SSTORE 支付 20k Gas。
  • 只要计算涉及从 int256/uint256 转换得出的金额,就建议使用 safeCast, 特别是在计算费用时。

份额配置

shares 选项控制生成的 hook 是否会发行代表用户份额的代币 (例如,hook 自有流动性池中的 LP 头寸)。

选项说明适用场景
false无份额代币——hook 不会跟踪已存入资产的所有权不持有用户资金的简单 hook
ERC20同质化份额代币——一个代币代表用户对 hook 持有的所有资产的按比例所有权由 hook 管理、份额可互换的流动性池
ERC6909多代币(精简版)——一个合约管理多个代币 ID,开销低于 ERC1155hook 高效管理多个不同资产类别
ERC1155多代币(标准版)——完整支持 ERC1155,并支持元数据 URIhook 需要广泛兼容钱包和交易市场

权衡:

  • false:字节码最小,无份额记账开销;适用于费用 hook 和预言机。
  • ERC20:最简单的同质化份额;具备良好的 DeFi 可组合性(例如,可用作抵押品)。
  • ERC6909:采用精简接口的高效多代币;新协议设计的首选方案。
  • ERC1155:生态支持最广(钱包、区块浏览器、NFT 交易市场);每次转账的 Gas 成本高于 ERC6909。

访问控制选项

access 选项决定生成的钩子的构造函数形式和管理界面。

选项构造函数形式适用场景
ownableconstructor(IPoolManager, address initialOwner)单个所有者控制所有管理功能
rolesconstructor(IPoolManager, address admin)通过细粒度权限设置多个角色(OpenZeppelin AccessControl)
managedconstructor(IPoolManager, address authority)由外部权限合约管理权限(OpenZeppelin AccessManaged)

使用建议:

  • ownable 最简单——一个地址即可执行所有特权操作。适用于早期阶段的钩子和个人工具。
  • roles 通过 OpenZeppelin AccessControl 添加 ADMIN_ROLE、PAUSER_ROLE 等角色。当不同团队成员需要不同权限时使用(例如,keeper 机器人可以更新费用,但不能升级合约)。
  • managed 将所有权限检查委托给单独的 AccessManager 合约。当你需要在多个合约间建立统一的治理层,或希望对管理操作设置时间锁时使用。

注意:更改 access 选项会改变构造函数签名。请相应更新部署脚本和初始化逻辑。使用 ownable 时,请确保 initialOwner 不是零地址——自 v5 起,OpenZeppelin 的 Ownable 遇到零地址时会回滚。

钩子输入参考

某些钩子类型接受用于调整行为的数值配置输入。这些输入通过 MCP 工具调用中的 inputs 对象传入。

输入类型使用方说明
blockNumberOffsetuint256AntiSandwichHook、LiquidityPenaltyHook三明治/JIT 检测窗口开启前的区块数
maxAbsTickDeltaint24AntiSandwichHook在 MEV 保护触发前,每个区块允许的最大 tick 变化量

对于不使用这些输入的钩子类型,请省略 inputs 字段或传入空对象 {}。向 MCP 工具传入不支持的输入不会导致错误,但这些值会被忽略。

MCP 工具调用(规范格式)

OpenZeppelin Contracts Wizard 提供了一个 generate_hook MCP 工具。以下是规范的 JSON 架构——根据上文各部分的决定填写每个字段,然后将此对象作为工具参数传入。

{
  "hook": "BaseHook",
  "name": "MyHook",
  "pausable": false,
  "currencySettler": true,
  "safeCast": true,
  "transientStorage": false,
  "shares": { "options": false },
  "permissions": {
    "beforeInitialize": false,
    "afterInitialize": false,
    "beforeAddLiquidity": false,
    "beforeRemoveLiquidity": false,
    "afterAddLiquidity": false,
    "afterRemoveLiquidity": false,
    "beforeSwap": true,
    "afterSwap": false,
    "beforeDonate": false,
    "afterDonate": false,
    "beforeSwapReturnDelta": false,
    "afterSwapReturnDelta": false,
    "afterAddLiquidityReturnDelta": false,
    "afterRemoveLiquidityReturnDelta": false
  },
  "inputs": {
    "blockNumberOffset": 1,
    "maxAbsTickDelta": 100
  },
  "access": "ownable",
  "info": { "license": "MIT" }
}

字段说明:

  • hook:字符串——决策表中的 14 种钩子类型之一
  • name:字符串——Solidity 合约名称(PascalCase,不含空格)
  • pausable:布尔值——使用 OpenZeppelin Pausable 包装钩子;添加 pause()/unpause() 管理函数
  • shares.options:false | "ERC20" | "ERC6909" | "ERC1155"
  • access:"ownable" | "roles" | "managed"
  • info.license:SPDX 许可证标识符——开源钩子使用 "MIT"
  • inputs:对于不使用 blockNumberOffset/maxAbsTickDelta 的钩子类型,请省略或传入 {}

工作流:收集 → 配置 → 生成 → 保护

每次使用此技能时,都请按顺序执行以下步骤。

步骤 1:收集需求

询问用户(或根据上下文推断):

  1. Hook 的主要目标是什么?(映射到决策表。)
  2. Hook 需要拦截哪些生命周期事件?(映射到权限。)
  3. Hook 是否会持有或转移用户资金?(决定 currencySettler 和 shares。)
  4. 谁管理 Hook?(单一所有者、基于角色的团队,还是外部治理?)
  5. Hook 是否需要在单笔交易的多个回调之间传递状态?
  6. 这是用于支持 EVM Cancun 的链吗?(transientStorage 的必需条件。)
步骤 2:选择 Hook 类型

使用决策表确定最合适的单一 Hook 类型。如果用户的目标对应多种类型,请解释取舍并让用户确认。记录选定的类型及原因。

步骤 3:配置全部六项决策

按最简决策清单逐项处理:

  1. 将 hook 设为选定的类型。
  2. 设置每个权限标志——默认值为 false,仅在逻辑需要时启用。
  3. 根据工具库指南设置 currencySettler、safeCast、transientStorage。
  4. 根据 shares 指南设置 shares.options。
  5. 根据访问控制指南设置 access。
  6. 仅当 Hook 类型使用 blockNumberOffset 或 maxAbsTickDelta 时,才设置 inputs。
步骤 4:组装并调用 MCP 工具

根据步骤 3 构造 JSON 对象,并使用该对象调用 OpenZeppelin Contracts Wizard MCP 工具。 该工具会返回 Solidity 源代码——不会自动写入文件。

收到生成的代码后:

  1. 向用户展示代码。
  2. 说明生成代码中的关键部分(构造函数、getHookPermissions、已启用的回调)。
  3. 说明任何所需的手动步骤(使用 HookMiner 挖掘地址;如果 access 为 roles 或 managed,则更新构造函数参数对应的部署脚本)。
步骤 5:落实安全基础要求

在部署代码之前,务必提醒用户并调用 v4-security-foundations:

  • 确认所有已启用的回调都会检查 msg.sender == address(poolManager)。
  • 审查所有已启用的 *ReturnDelta 权限是否存在 NoOp 攻击风险。
  • 确认每条执行路径上的 delta 会计总和均为零。
  • 按照 v4-security-foundations 执行完整的部署前审计清单。

重要说明

  • 访问控制会改变构造函数的形式:选择 ownable 会添加 initialOwner 参数;选择 roles 会添加 admin 参数;选择 managed 会添加 authority 参数。相应地更新部署脚本和工厂合约。
  • 权限编码在 Hook 地址中:每个已启用的权限标志都对应 Hook 已部署地址低位字节中的特定比特位。PoolManager 会在每次回调时验证这些比特位。使用 v4-periphery 中的 HookMiner 挖掘部署 salt,以生成匹配的地址。
  • MCP 只返回代码——不会写入文件:生成的 Solidity 代码会以字符串形式返回。你必须自行将其写入磁盘(例如 packages/contracts/src/hooks/MyHook.sol)。

相关技能

  • v4-security-foundations — 生成后运行此项。 Uniswap v4 Hook 的安全审计:权限风险矩阵、NoOp 攻击模式、delta 会计、访问控制验证,以及完整的部署前审计清单。生成的 Hook 代码在完成此审查前绝不能部署。
  • viem-integration — 部署生成的 Hook 合约,并使用 viem/wagmi 与其交互
  • v4-sdk-integration — 通过 Uniswap v4 SDK 与已部署的 Hook 交互

评论

支持 Markdown