如何开始你的第一个 Uniswap V4 Hook:要点、库与风险

  • zealynx
  • 发布于 2026-02-20 19:21
  • 阅读 16

这篇文章详细介绍了如何构建 Uniswap V4 hooks,包括所需的核心库、逐步的开发指南(附带代码示例),以及在开发过程中需要考虑的重要安全和性能问题。它旨在帮助开发者理解并实现自定义的流动性池行为,涵盖了从基础设置到复杂安全考量的全面内容。

你好,勇敢的DeFi探索者!你一定听说过这些新潮的 Uniswap V4 hooks 并心想,“嘿,我或许也能创造一个!” 那么,系好安全带,因为我们即将踏上激动人心的定制化流动性池行为冒险之旅。别担心,我将成为你值得信赖的向导,我们将一同应对这次旅程!

安营扎寨:必需品

在我们深入代码之前,先聊聊这次旅行我们要准备什么。你可能会问,“我需要什么才能开始呢?” 问得好!这是我们的基本装备:

Hooks library

把它想象成你的瑞士军刀——一种多功能工具,包含了定义你的hook能做的一切。

  • 有什么?这个库包含不同 hook 标志的常量(例如 BEFORE_SWAP_FLAGAFTER_SWAP_FLAG),以及用于验证和调用 hooks 的函数。
  • 你能做什么?通过它,你可以精确指定你的hook应该何时启动。想在交易前做点什么?在添加流动性之后?这是你的首选工具包。

PoolKey 和 PoolId

它们就像你的地图和指南针。它们能帮助你导航广阔的流动性池景观。

  • 它们是什么?PoolKey 是一个唯一标识池的结构体,而 PoolIdPoolKey 的一种更节省 Gas 的表示。
  • 你能做什么?你可以使用它们来定位特定的池,检索池信息,或创建带有你的hook的新池。

Currency library

这是你的通用翻译器,帮助你与原生代币(如 ETH)和 ERC20 代币进行沟通。

  • 有什么?用于转移代币、检查余额以及统一处理原生代币和 ERC20 代币的函数。
  • 你能做什么?你可以创建与任何代币类型无缝协作的 hook,为跨代币交互开辟了无限可能。

BaseHook contract

把它看作你的帐篷——一个坚实的基础,可以在智能合约开发的恶劣环境中为你提供庇护。

  • 它是什?一个抽象合约,实现了 Uniswap V4 hook 所需的基本结构。
  • 你能做什么?通过继承它,你可以在 hook 开发上领先一步。它处理了大量的样板代码,让你能够专注于 hook 的独特功能。

等等,我真的需要所有这些吗?”你可能会问。相信我,每一部分都在你的 hook 创建冒险中扮演着关键角色。让我们搭建好营地,看看它们是如何协同工作的!

制作你的第一个 hook:分步指南

步骤 1:奠定基础

首先,让我们设置好我们的合约。这是我们将要开始的基本结构:

1import {BaseHook} from "@uniswap/v4-periphery/contracts/BaseHook.sol";
2import {Hooks} from "@uniswap/v4-core/contracts/libraries/Hooks.sol";
3import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol";
4import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol";
5import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/contracts/types/PoolId.sol";
6import {Currency, CurrencyLibrary} from "@uniswap/v4-core/contracts/types/Currency.sol";
7import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol";
8

9contract MyAwesomeHook is BaseHook {
10    using StateLibrary for IPoolManager;
11    using PoolIdLibrary for PoolKey;
12    using CurrencyLibrary for Currency;
13    using FixedPointMathLib for uint256;
14

15    constructor(IPoolManager _poolManager) BaseHook(_poolManager) {}
16

17    // 更多精彩内容即将到来!
18}

让我们来分析一下这些 using 语句并理解它们的重要性:

  1. using StateLibrary for IPoolManager; — 这使得与池状态的交互更加高效。它允许你直接在 IPoolManager 对象上调用 StateLibrary 函数,从而简化了查询池流动性或交易数据等操作。
  2. using PoolIdLibrary for PoolKey; — 这有助于在 PoolKey 结构体和 PoolId 之间轻松转换。对于需要识别特定池的操作至关重要,例如将 hook 定位到特定的交易对。
  3. using CurrencyLibrary for Currency; — 此语句增强了你统一处理不同代币类型的能力。它允许你直接在 Currency 对象上使用 CurrencyLibrary 函数,简化了代币转账、余额检查以及其他与代币相关的操作。
  4. using FixedPointMathLib for uint256; — 这提供了 DeFi 应用程序所需精确数学运算的访问权限。它允许你对 uint256 数字执行定点算术,这对于准确的价格计算、费用计算以及其他金融操作至关重要。

这些 using 语句是编写高效、可读且 gas 优化的 hook 代码的关键。它们提供了语法糖(syntactic sugar),让你在使用这些复杂的 DeFi 概念时能够编写更直观的代码。

步骤 2:声明你的意图

接下来,我们需要告诉 Uniswap 我们的 hook 能做什么。这就像为你的露营活动填写许可证一样:

1function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
2    return Hooks.Permissions({
3        beforeInitialize: false,
4        afterInitialize: false,
5        beforeAddLiquidity: false,
6        afterAddLiquidity: false,
7        beforeRemoveLiquidity: false,
8        afterRemoveLiquidity: false,
9        beforeSwap: false,
10        afterSwap: false,
11        beforeDonate: false,
12        afterDonate: false,
13        beforeSwapReturnDelta: false,
14        afterSwapReturnDelta: false,
15        afterAddLiquidityReturnDelta: false,
16        afterRemoveLiquidityReturnDelta: false
17    });
18}

现在,你可能会挠头想,“等一下,我们真的需要这个函数吗?我以为 Uniswap 是根据合约地址来判断使用哪些 hook 的呢。

嗯,你完全正确,你这个聪明的露营者!Uniswap 确实是根据合约地址来决定调用哪个 hook 的。这个 getHookPermissions() 函数更像是我们人类的“视觉辅助”。它帮助开发者(比如我们)快速了解 hook 应该做什么,而无需深入研究 地址挖掘 的细节。

你可能会问,“那么,我应该费心实现它吗?” 答案是肯定的!虽然它对 Uniswap 的运行并非严格必要,但对于其他可能使用你代码的开发者(包括未来的你自己)来说,它非常有帮助。

要使用 hook,你需要将相应的权限设置为 true。例如,如果你希望你的 hook 在交易前后执行某些操作,你会将 beforeSwapafterSwap 设置为 true

Uniswap 如何从合约地址读取这些权限的复杂性是一个引人入胜的话题,但这有点像高级野外生存技术——我们把它留到下一次探险。现在,让我们专注于搭建好我们的基本营地!

步骤 3:添加你的独家秘方

现在到了有趣的部分——让我们添加一些自定义行为!我们将实现 beforeSwap 函数:

1function beforeSwap(
2    address sender,
3    PoolKey calldata key,
4    IPoolManager.SwapParams calldata params,
5    bytes calldata data
6)
7    external
8    override
9    returns (bytes4)
10{
11    // 你的魔法在此!
12    console.log("Ooh, a swap is about to happen from", sender);
13

14    // 别忘了这部分!
15    return BaseHook.beforeSwap.selector;
16}

那个 return 语句是怎么回事?”你问。好眼力!那是我们告诉 Uniswap,“是的,我们完成了我们的工作,你现在可以继续了。”

4:投入使用

恭喜你,勇敢的开发者!你刚刚创建了你的第一个 Uniswap V4 hook。但是你如何实际使用它呢?问得好!

  1. 将你的 hook 合约部署到区块链上。
  2. 在创建新的流动性池时,你需要指定你的 hook 的地址。
  3. 现在,每当有人尝试在该池中进行交易时,你的 beforeSwap 函数就会运行!

重要注意事项

在我们结束冒险之前,让我们谈谈在开发 hook 时需要牢记的一些重要注意事项。即使在早期阶段,也务必了解潜在的陷阱和安全风险:

  1. Gas 效率 — 在以太坊的世界里,每一次计算都会消耗 Gas。请注意你的 hook 的复杂性。效率低下的代码会使你的 hook 使用成本过高。

  2. 重入风险 — 如果你的 hook 与外部合约交互,请警惕重入攻击(reentrancy attacks)。始终遵循检查-效果-交互模式(checks-effects-interactions pattern)

  3. 访问控制 — 确保你的 hook 中敏感功能只能由授权地址调用。Uniswap V4 提供了一些内置保护,但保持警惕仍然很重要。Cork Protocol 中发现的一个关键漏洞——它使用了类似 V4 的 hook 架构——就是由于 缺乏访问控制,允许攻击者直接调用 hook 的函数。

  4. 状态管理 — 请记住,hook 被设计为在调用之间是无状态(stateless)的。如果你需要维护状态,请小心操作,并考虑对 Gas 成本和潜在攻击向量的影响。

  5. 小数精度 — 在处理代币数量和价格时,要特别小心小数精度。四舍五入误差可能导致金融计算中出现重大问题。

  6. 测试 — 在各种场景下彻底测试你的 hook。Uniswap 提供了一个测试框架——在考虑部署到主网之前广泛使用它。

  7. 可升级性 — 考虑你的 hook 是否需要可升级。如果需要,请仔细实施 升级模式 以避免引入漏洞。

  8. MEV 意识 — 请注意,老练的参与者可能会试图利用你的 hook 来获取 MEV(最大可提取价值)。在设计 hook 时要考虑到这一点。

  9. 可组合性 — 你的 hook 可能会与其他 DeFi 协议交互。始终考虑更广泛的生态系统和潜在的意外交互。

  10. 审计 — 对于任何用于生产的 hook,专业审计是必须的。即使看起来简单的代码也可能存在隐藏的漏洞。

请记住,在 DeFi 中,你通常处理的是真实价值。代码中的一个小错误可能会导致重大的财务损失。始终谨慎行事,永远不要停止学习安全最佳实践。

完整模板

为了帮助你快速上手,这里是你的第一个 Uniswap V4 hook 的完整模板。你可以将其复制并粘贴到你的环境中作为起点:

1// SPDX-License-Identifier: MIT
2pragma solidity ^0.8.19;
3

4import {BaseHook} from "@uniswap/v4-periphery/contracts/BaseHook.sol";
5import {Hooks} from "@uniswap/v4-core/contracts/libraries/Hooks.sol";
6import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol";
7import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol";
8import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/contracts/types/PoolId.sol";
9import {Currency, CurrencyLibrary} from "@uniswap/v4-core/contracts/types/Currency.sol";
10import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol";
11

12contract MyAwesomeHook is BaseHook {
13    using PoolIdLibrary for PoolKey;
14    using CurrencyLibrary for Currency;
15    using FixedPointMathLib for uint256;
16

17    constructor(IPoolManager _poolManager) BaseHook(_poolManager) {}
18

19    function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
20        return Hooks.Permissions({
21            beforeInitialize: false,
22            afterInitialize: false,
23            beforeAddLiquidity: false,
24            afterAddLiquidity: false,
25            beforeRemoveLiquidity: false,
26            afterRemoveLiquidity: false,
27            beforeSwap: true,
28            afterSwap: false,
29            beforeDonate: false,
30            afterDonate: false,
31            beforeSwapReturnDelta: false,
32            afterSwapReturnDelta: false,
33            afterAddLiquidityReturnDelta: false,
34            afterRemoveLiquidityReturnDelta: false
35        });
36    }
37

38    function beforeSwap(
39        address sender,
40        PoolKey calldata key,
41        IPoolManager.SwapParams calldata params,
42        bytes calldata data
43    )
44        external
45        override
45        returns (bytes4)
46    {
47        // 你的自定义逻辑在这里
48        console.log("交易由", sender, "发起");
49

50        return BaseHook.beforeSwap.selector;
51    }
52}

此模板包含了所有必要的导入、基本的合约结构以及 beforeSwap hook 的一个简单实现。你可以在探索更复杂的 hook 行为时修改和扩展它。

总结

恭喜!你刚刚迈出了进入 Uniswap V4 hooks 世界的第一大步。让我们回顾一下你所完成的:

  1. 你已经搭建了 Uniswap V4 hook 合约的基本结构。
  2. 你已经了解了驱动这些 hook 的基本库和组件。
  3. 你已经实现了 getHookPermissions() 函数,它对于定义 hook 的功能至关重要。
  4. 你已经创建了一个简单的 beforeSwap 函数作为 hook 逻辑的起点。

从这里开始,可能性是巨大的:

  • 你可以扩展 beforeSwap 函数。
  • 你可以探索 afterSwapbeforeAddLiquidity 等其他 hook 函数,以影响交易的不同方面。
  • 你可以深入研究我们介绍的库,以创建与池和代币之间更复杂的交互。

Uniswap V4 生态系统任你探索和塑造。你的下一步可能会引领 DeFi 的下一个重大突破!

那么,接下来你会构建什么呢?

联系我们

在 Zealynx,我们深入理解复杂的 AMM 设计,从集中流动性(concentrated liquidity)到新兴的 hook 架构,以及 Uniswap 等协议的安全挑战。无论你是在构建新的 DeFi 协议、审计现有协议,还是需要关于 AMM 项目安全性的专家指导,我们的团队都随时准备提供帮助——请联系我们

想获取更多像这样的深入分析,保持领先地位吗?订阅我们的时事通讯,确保你不会错过未来的洞察。

常见问题

  1. Uniswap V4 hooks 是什么? Uniswap V4 hooks 是外部智能合约,它们在池生命周期的特定点(例如交易前后、流动性增加或移除前后)执行自定义逻辑。它们充当扩展核心协议的插件,无需修改核心 PoolManager 合约即可实现动态费用、链上限价订单、自定义 AMM 曲线和 MEV 保护等功能。
  2. 构建 Uniswap V4 hook 需要哪些库? 必需的库包括:Hooks library(用于 hook 标志和验证)、PoolKey 和 PoolIdLibrary(用于识别池)、CurrencyLibrary(用于处理原生 ETH 和 ERC20 代币)、FixedPointMathLib(用于精确的 DeFi 数学计算),以及 BaseHook 抽象合约(它提供了 hook 的样板结构)。
  3. getHookPermissions() 的作用是什么,它是否必需? getHookPermissions() 函数声明了你的合约实现了哪些 hook 回调(例如,beforeSwapafterSwap)。虽然 Uniswap V4 实际上是从合约的已部署地址的位中确定活动 hook,但此函数充当人类可读的声明,帮助开发者和审计员快速了解 hook 的功能。实现它是最佳实践
  4. Uniswap V4 hooks 的地址挖掘是什么? 地址挖掘是寻找一个 CREATE2 部署盐值的过程,该盐值生成一个合约地址,其最低有效位编码了正确的 hook 权限。Uniswap V4 使用位运算(而不是存储读取)从 hook 地址读取权限以提高 Gas 效率。开发者在部署前使用 HookMiner 等工具来查找有效的盐值。
  5. 构建 hook 时最大的安全风险是什么? 主要的安全风险包括:来自对不可信合约(untrusted contracts)的外部调用的重入攻击(reentrancy attacks)访问控制(access control)失败(hook 必须验证 msg.sender 是 PoolManager)、由于无边界循环(unbounded loops)导致的基于 Gas 的拒绝服务(denial of service)、当 hook 为多个池服务时的状态管理(state management)错误以及金融计算中的小数精度误差。在任何主网部署之前,强烈建议进行专业审计。
  6. Uniswap V4 hook 部署后可以升级吗? hook 在池创建后不能更改——hook 地址永久绑定到池。但是,你可以实现代理模式(proxy patterns)来使 hook 的底层逻辑可升级。这会引入中心化风险(centralization risk),必须通过时间锁(timelocks)多重签名钱包(multi-signature wallets)等强大的治理机制(governance mechanisms)进行保护。开发者应在其 hook 的文档中透明地说明可升级性。

词汇表

本文中使用的关键术语的快速参考:

术语 定义
Hooks 在 Uniswap V4 中,在特定池生命周期点执行自定义逻辑的外部智能合约。
Pool Manager Uniswap V4 中管理所有池、流动性和交易的单例合约(singleton contract)
Address Mining 寻找具有特定位标志(bit flags)的部署地址以配置 hook 权限的过程。
MEV 最大可提取价值(Maximal Extractable Value)——通过重新排序或在区块中插入交易来提取的利润。
Proxy Pattern 智能合约设计模式,可实现可升级逻辑,同时保留状态和地址。
ERC-6909 Uniswap V4 中使用的最小多代币接口(Minimal Multi-Token Interface)标准,用于 Gas 高效的代币记账。

查看完整词汇表 →

  • 原文链接: zealynx.io/blogs/uniswap...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
zealynx
zealynx
江湖只有他的大名,没有他的介绍。