本文介绍了如何创建 Uniswap V4 的第一个Hook,包括必需的库、合约结构和安全风险等内容。通过逐步引导,读者可以了解到如何实现自定义流动性池行为以及注意事项,并给出了完整的Hook模板代码。
你好,勇敢的 DeFi 探险者!所以你听说了这些新颖的 Uniswap V4 hooks,并且想:“嘿,我可能也可以做一个!”好了,系好安全带,因为我们即将踏上探索自定义流动性池行为的刺激之旅。别担心,我会成为你的可信赖向导,我们一起完成这段旅程!
在我们深入代码之前,让我们谈谈这次旅程中需要准备的东西。你可能在想:“我需要什么来开始?”好问题!以下是我们的基本装备:
Hooks 库:
把它想象成你的瑞士军刀。它具有定义你的 hook 能做什么的各种工具。
BEFORE_SWAP_FLAG
、AFTER_SWAP_FLAG
),以及用于验证和调用 hooks 的函数。PoolKey 和 PoolId:
这些就像你的地图和指南针。它们帮助你在广阔的流动性池中导航。
PoolKey
是一个结构,唯一标识一个池,而 PoolId
是 PoolKey
的更节能的表示。Currency 库:
这是你的通用翻译器,帮助你与原生代币(如 ETH)和 ERC20 代币进行交流。
BaseHook 合约:
把它看作是你的帐篷——一个坚实的基础来搭建并庇护你免受智能合约开发的恶劣环境。
“但等等,”你可能会问,“我真的需要所有这些吗?”相信我,每个部分在你的 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’ 语句并理解它们的意义:
using StateLibrary for IPoolManager;
:这使得与池状态的高效交互成为可能。它允许你直接在 IPoolManager 对象上调用 StateLibrary 函数,简化池流动性或交换数据的查询等操作。using PoolIdLibrary for PoolKey;
:这简化了 PoolKey 结构与 PoolId 之间的转换。它对需要识别特定池的操作非常关键,例如,将 hooks 指向特定交易对。using CurrencyLibrary for Currency;
:这一语句增强了你与不同代币类型一致交互的能力。它使得可以直接在 Currency 对象上使用 CurrencyLibrary 函数,从而简化代币转账、余额检查和其他代币相关操作。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 在交换前后执行一些操作,你可以将 beforeSwap
和 afterSwap
设置为 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。但你怎么实际使用它呢?好问题!
beforeSwap
函数将会被执行!在我们结束这次冒险之前,让我们谈谈在你开发 hooks 时需要注意的一些重要事项。即使在这个早期阶段,意识到潜在的陷阱和安全风险也是至关重要的:
记住,在 DeFi 中,你的操作涉及到真正的价值。代码中的小错误可能会导致重大的财务损失。始终谨慎行事,并不断学习安全最佳实践。
恭喜你!你刚刚迈出了进入 Uniswap V4 hooks 世界的第一步。让我们回顾一下你所取得的成就:
getHookPermissions()
函数,这是定义你的 hook 能力的关键。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
函数。afterSwap
或 beforeAddLiquidity
,以影响交易的不同方面。Uniswap V4 生态系统是你可以探索和塑造的。你的下一个步骤可能会引领去涉及去中心化金融的下一个重大突破!
你接下来将构建什么?
https://www.linkedin.com/in/carlos-vendrell-felici/
https://github.com/ZealynxSecurity
- 原文链接: medium.com/@bloqarl/how-...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!