如何开始你的第一个 Uniswap V4 Hook:必备知识、库和风险

  • bloqarl
  • 发布于 2024-08-27 21:30
  • 阅读 46

本文介绍了如何创建 Uniswap V4 的第一个Hook,包括必需的库、合约结构和安全风险等内容。通过逐步引导,读者可以了解到如何实现自定义流动性池行为以及注意事项,并给出了完整的Hook模板代码。

如何开始你的第一个 Uniswap V4 Hook:基本要素、库和风险

你好,勇敢的 DeFi 探险者!所以你听说了这些新颖的 Uniswap V4 hooks,并且想:“嘿,我可能也可以做一个!”好了,系好安全带,因为我们即将踏上探索自定义流动性池行为的刺激之旅。别担心,我会成为你的可信赖向导,我们一起完成这段旅程!

设置营地:基本要素

在我们深入代码之前,让我们谈谈这次旅程中需要准备的东西。你可能在想:“我需要什么来开始?”好问题!以下是我们的基本装备:

Hooks 库

把它想象成你的瑞士军刀。它具有定义你的 hook 能做什么的各种工具。

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

PoolKey 和 PoolId

这些就像你的地图和指南针。它们帮助你在广阔的流动性池中导航。

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

Currency 库

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

  • 它包含什么?:用于转移代币、检查余额以及统一处理原生和 ERC20 代币的函数。
  • 你能做什么?:你可以创建与任何代币类型无缝协作的 hooks,为跨代币的交互打开一个可能的世界。

BaseHook 合约

把它看作是你的帐篷——一个坚实的基础来搭建并庇护你免受智能合约开发的恶劣环境。

  • 它是什么?:一个抽象合约,实现了 Uniswap V4 hook 所需的基本结构。
  • 你能做什么?:继承自这个合约,你可以更轻松地开始 hook 的开发。它处理了大量样板代码,让你专注于 hook 的独特功能。

“但等等,”你可能会问,“我真的需要所有这些吗?”相信我,每个部分在你的 hook 创作冒险中都扮演着至关重要的角色。让我们建立我们的基础营地,看看这一切是如何结合在一起的!

制作你的第一个 Hook:逐步指南

第一步:奠定基础

首先,让我们创建我们的 hook 合约。下面是我们将要开始的基本结构:

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

contract MyAwesomeHook is BaseHook {
    using StateLibrary for IPoolManager;
    using PoolIdLibrary for PoolKey;
    using CurrencyLibrary for Currency;
    using FixedPointMathLib for uint256;
    constructor(IPoolManager _poolManager) BaseHook(_poolManager) {}
    // 更多激动人心的内容在后面!
}

让我们分析这些 ‘using’ 语句并理解它们的意义:

  1. using StateLibrary for IPoolManager;:这使得与池状态的高效交互成为可能。它允许你直接在 IPoolManager 对象上调用 StateLibrary 函数,简化池流动性或交换数据的查询等操作。
  2. using PoolIdLibrary for PoolKey;:这简化了 PoolKey 结构与 PoolId 之间的转换。它对需要识别特定池的操作非常关键,例如,将 hooks 指向特定交易对。
  3. using CurrencyLibrary for Currency;:这一语句增强了你与不同代币类型一致交互的能力。它使得可以直接在 Currency 对象上使用 CurrencyLibrary 函数,从而简化代币转账、余额检查和其他代币相关操作。
  4. using FixedPointMathLib for uint256;:这提供了对精确数学操作的访问,对于 DeFi 应用至关重要。它允许你对 uint256 数字进行定点运算,这对于准确的价格计算、费用计算和其他财务操作至关重要。

这些 ‘using’ 语句是编写高效、可读和节省 gas 的 hook 代码的关键。它们提供了语法糖,使得你在处理这些复杂的 DeFi 概念时,能够编写更直观的代码。

第二步:声明你的意图

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

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: false,
        beforeDonate: false,
        afterDonate: false,
        beforeSwapReturnDelta: false,
        afterSwapReturnDelta: false,
        afterAddLiquidityReturnDelta: false,
        afterRemoveLiquidityReturnDelta: false
    });
}

现在,你可能会摸着头思考:“等一下,我们真的需要这个函数吗?我以为 Uniswap 会根据合约地址来判断使用哪个 hook。”

你说得没错,机智的露营者!Uniswap 确实会根据合约地址来决定调用哪个 hooks。这个 getHookPermissions() 函数更像是我们人类的“视觉辅助”。它帮助开发者(例如我们)快速查看 hook 应该做什么,而无需深入底层地址分析的细节。

你可能在想:“那么,我应该麻烦实现这个吗?”答案是肯定的!虽然它对 Uniswap 的操作不是严格必要,但对于其他开发者(包括你未来的自己)来说,它非常有用,可以更快速地了解你的代码。

要使用一个 hook,你需要将对应的权限设置为 true。例如,如果你希望你的 hook 在交换前后执行一些操作,你可以将 beforeSwapafterSwap 设置为 true

Uniswap 如何从合约地址读取这些权限的复杂性是一个有趣的话题,但这就像高级野外生存技巧——我们会将其留到另一次探险中。现在,让我们专注于搭建我们的基本营地!

第三步:添加你的特别调料

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

function beforeSwap(address sender, PoolKey calldata key, IPoolManager.SwapParams calldata params, bytes calldata data)
    external
    override
    returns (bytes4)
{
    // 你的魔法在这里实现!
    console.log("啊,有一笔交易即将发生,来自", sender);

    // 不要忘记这部分!
    return BaseHook.beforeSwap.selector;
}

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

第四步:尝试一下

恭喜你,勇敢的开发者!你刚刚创建了自己的第一个 Uniswap V4 hook。但你怎么实际使用它呢?好问题!

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

重要注意事项

在我们结束这次冒险之前,让我们谈谈在你开发 hooks 时需要注意的一些重要事项。即使在这个早期阶段,意识到潜在的陷阱和安全风险也是至关重要的:

  1. Gas 效率:在以太坊的世界里,每次计算都需要消耗 gas。要注意你的 hook 的复杂性。低效的代码会使你的 hook 使用成本过高。
  2. 重入风险:如果你的 hook 与外部合约交互,要小心重入攻击。始终遵循检查-效果-交互模式。
  3. 访问控制:请确保你的 hook 中敏感功能只能由授权地址调用。Uniswap V4 提供了一些内建保护,但仍需保持警惕。
  4. 状态管理:请记住,hooks 设计为在调用之间无状态。如果需要维护状态,请谨慎操作,考虑对 gas 成本和潜在攻击向量的影响。
  5. 小数精度:在处理代币金额和价格时,请特别注意小数精度。四舍五入错误可能导致财务计算中出现重大问题。
  6. 测试:在各种场景下彻底测试你的 hooks。Uniswap 提供了测试框架——在考虑部署到主网之前,广泛使用它。
  7. 可升级性:考虑你的 hook 是否需要可升级。如果是,请小心实现升级模式,以避免引入漏洞。
  8. MEV 意识:要意识到,复杂的参与者可能会试图利用你的 hook 进行 MEV(可挖掘的价值)。在设计你的 hooks 时要考虑这一点。
  9. 可组合性:你的 hook 可能与其他 DeFi 协议进行交互。始终考虑更广泛的生态系统和潜在的意外交互。
  10. 审计:对于任何计划投入生产使用的 hook,专业审计是必须的。即使是看似简单的代码也可能隐藏漏洞。

记住,在 DeFi 中,你的操作涉及到真正的价值。代码中的小错误可能会导致重大的财务损失。始终谨慎行事,并不断学习安全最佳实践。

总结

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

  1. 你设置了一个 Uniswap V4 hook 合约的基本结构。
  2. 你了解了驱动这些 hooks 的基本库和组件。
  3. 你实现了 getHookPermissions() 函数,这是定义你的 hook 能力的关键。
  4. 你创建了一个简单的 beforeSwap 函数,作为你 hook 逻辑的起点。

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

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

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

contract MyAwesomeHook is BaseHook {
    using PoolIdLibrary for PoolKey;
    using CurrencyLibrary for Currency;
    using FixedPointMathLib for uint256;

    constructor(IPoolManager _poolManager) BaseHook(_poolManager) {}

    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: true,
            afterSwap: false,
            beforeDonate: false,
            afterDonate: false,
            beforeSwapReturnDelta: false,
            afterSwapReturnDelta: false,
            afterAddLiquidityReturnDelta: false,
            afterRemoveLiquidityReturnDelta: false
        });
    }

    function beforeSwap(address sender, PoolKey calldata key, IPoolManager.SwapParams calldata params, bytes calldata data)
        external
        override
        returns (bytes4)
    {
        // 你的自定义逻辑在这里实现
        console.log("交易发起者是", sender);

        return BaseHook.beforeSwap.selector;
    }
}

这个模板包括所有必要的导入、基本合约结构和 beforeSwap hook 的简单实现。你可以根据需要对其进行修改和扩展,探索更复杂的 hook 行为。

在这里,可能性是巨大的:

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

Uniswap V4 生态系统是你可以探索和塑造的。你的下一个步骤可能会引领去涉及去中心化金融的下一个重大突破!

你接下来将构建什么?

让我们建立联系:

https://x.com/TheBlockChainer

https://www.linkedin.com/in/carlos-vendrell-felici/

https://linktr.ee/bloqarl

如果你需要帮助,请让我们合作:

  • 智能合约审计(Solidity,Rust,Cairo)
  • 高级安全测试套件(模糊测试、不可变性测试 + 形式化验证)
  • 智能合约开发
  • Web2 渗透测试

https://github.com/ZealynxSecurity

https://x.com/ZealynxSecurity

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

0 条评论

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