什么是 Hooks
Hooks,即 Hook 编程(Hook Programming),是一种编程模式,其中通过 Hook,也就是预定义的函数或代码块,允许开发者在一个系统、应用程序或库的执行路径中插入自定义代码,而不需要修改原本的代码。Hooks 经常被用于许多编程环境和框架中,例如操作系统、框架和库、Web开发、以及插件系统。
通过使用 Hooks,开发者可以增加程序的可扩展性和可定制性,不必为了每一个变化或拓展需求去修改原有的代码,有助于保持代码的清洁和稳固。Hooks 为软件的扩展提供了一种优雅的实现方式,是软件设计中一种非常有用的编程模型。
特别的,AOP(Aspect-oriented Programming, 面向切面编程)经常和 Hook 编程拿来比较,AOP 是实现横切关注点(cross-cutting concerns)的模块化的编程范式,目标也是在不更改主要业务逻辑的情况下增强或修改功能。这里不详细展开 AOP,可以简单认为 AOP 是一种抽象层次更高的 HooK 编程。
Uniswap V4:Hooks 革命
2023 年 6 月,Uniswap 宣布并公开了 Uniswap V4 白皮书的草稿版本,Uniswap V4 的一个重要特性是引入了 Hooks。
其实,Hooks 在 Web2 的金融系统中已经有着广泛的应用,因为这些系统通常需要高度的定制化和可扩展性。定制化的场景例如在处理交易时,通过 Hooks 在交易执行前后插入额外的验证逻辑,如二次验证、风控检测和反洗钱(AML)策略。可扩展性的场景例如通过 Hooks 与外部 API 或微服务集成,在金融系统中拓展新的功能,如身份验证服务、汇率转换、支付网关等。但将 Hooks 引入 DeFi,Uniswap 还是创下了先河。
Uniswap V4 Hooks 本质是一个由开发者创建和定义的外部合约,流动性池被创建时可以选择绑定一个 Hook 合约。之后,流动性池会在生命周期的不同阶段调用之前绑定的 Hook 合约执行指定的操作,提供了高度的自定义性。开发者可以基于 Uniswap 的 Hooks 满足更个性化的交易场景,并构建出功能更丰富的 DApp,例如:
- 动态费用:通过 Hooks,流动性池可以根据市场波动性或其他输入参数动态调整费用,以更好地适应市场情况;
- 链上限价单(On-chain Limit Orders):Hooks 可以实现在链上创建和执行限价订单,使用户能够以指定价格进行交易;
- 时间加权平均做市商 (TWAMM):利用 Hooks 机制创建支持 TWAMM 策略的流动性池,以在一段时间内平均分散大额订单的交易。
目前 Uniswap V4 支持四组 Hook 回调,每组包含一对回调:
- beforeInitialize/afterInitialize:初始化流动性池;
- beforeModifyPosition/afterModifyPosition :添加/减少/移除流动性;
- beforeSwap/afterSwap :交换;
- beforeDonate/afterDonate :捐赠(Uniswap V4 引入的新功能,给予位于交易范围内的流动性提供者小费)。
下图是白皮书中展示的 beforeSwap/afterSwap Hook 的流程,可以看到在执行交换的前后,会先检查流动性池对应的 Hook 是否开启了相应的 flag,如果开启了,才会调用 Hook 合约的相应函数。
这些 Hooks 可以在交易开始开始前和交易结束后执行,从而实现类似于链上限价订单的功能。用户在 Hook 合约上下限价订单,随后在 afterSwap 的回调里根据自定义或托管预言机判断价格是否满足这个限价,如果满足,就执行交易,如果不满足,就取消交易。
Uniswap V4 通过 Hooks 将流动性与 DApp 自身的发展深度绑定,增强 DApp 功能的同时也增强了 Uniswap 的网络效应,使其成为整个 DeFi 生态系统的底层基础设施。
Uniswap V4 Hooks 的安全问题
BlockSec 团队曾经探究过 Uniswap V4 中 Hooks 机制的安全风险,除了 Hook 合约本身就是恶意的外,良性的 Hook 合约也极其容易存在漏洞。BlockSec 团队分析了Awesome Uniswap v4 Hooks 仓库(提交哈希为 3a0a444922f26605ec27a41929f3ced924af6075),并发现仓库中超过30%的项目存在漏洞。这些漏洞主要源于 Hook、PoolManager 以及外部第三方之间的风险交互,主要可以分为两类:
- 访问控制问题:主要关注的是 Uniswap V4 中的回调函数,这些函数应该只能被 PoolManager 调用,不能被其他地址(包括 EOA 和合约)调用。例如,在奖励由资金池密钥分发的情况下,如果相应的函数可以由任意账户调用,那么奖励可能会被错误地领取。因此,对于 Hook 来说,建立强大的访问控制机制是至关重要的,尤其是它们可以被除了池子本身之外的其他方调用;
- 输入验证问题:由于在一些易受攻击的 Hook 实现中输入验证不当而导致的各种类型的攻击,包括我们熟知的重入攻击。最常见的情况是在某些关键 Hook 函数里调用了不受信任的外部合约,为了攻击这些易受攻击的 Hook,攻击者可以为自己的虚假代币注册一个恶意资金池,然后调用 Hook 在资金池执行操作。在与资金池交互时,恶意代币逻辑劫持控制流以便进行不良行为。
即使适当执行对敏感的外部/公共函数的必要访问控制,并对输入参数进行验证,降低了以上两类 Hook 相关的安全风险,但合约漏洞本身还是无法完全规避的,特别是 Hook 如果作为可升级合约实现的,那么还可能会遇到类似于 OpenZeppelin 的 UUPSUpgradeable 漏洞的相关问题。
究其原因,还是因为 Hook 编程会增加智能合约的复杂度,从而加大攻击向量。对于普通智能合约,OpenZeppelin 会有系列最佳实践类库,让基于它开发出来的合约是安全的,但它本质上还是给开发者添加了“安全使用约束”。而 Hook 合约与普通合约相比,需要更严格的“安全使用约束”。因此,Hook 编程要广泛应用,还需要一个全面的框架:需要有安全执行环境、适用 Hook 的编程范式,和更严格的使用约束。
Artela Aspect:协议级支持 Hook 编程
Uniswap V4 Hooks 是通过智能合约实现的,它的安全性问题也是由于智能合约的局限性带来的,那有没有一种从协议级别支持 Hook 编程的方案呢?Artela Aspect 给了我们答案!
Artela 是一个高扩展性高性能的 EVM 兼容 Layer 1 区块链网络,专为开发人员构建模块化、功能丰富、可扩展且可定制的应用程序。Artela 中定义了一个新的可编程模块作为原生扩展,称为 Aspect,创新性地把 AOP 引入到了区块链网络中。Aspect 需要指定连接点,即在整个交易处理生命周期中执行 Aspect 的位置,类似于 Hook 的回调,连接点包括:
- Block Init:区块初始化;
- Transaction Verification:交易验证;
- Pre Execute:执行前;
- Post Execute:执行后;
- Block Finalize:区块最终确定。
Aspect 目前只支持 Typescripts,其代码被编译为 WebAssembly (WASM) 字节码并部署到 Artela 网络。Aspect 部署完成后,智能合约所有者可以将合约与 Aspect 绑定。智能合约所有者是指其外部账户(EOA)地址能够通过智能合约isOwner(address) returns (bool)的检查。
随后,调用智能合约的后续交易将由 Aspect 处理,如下图所示:
Artela Aspects 作为协议级别的 Hooks 实现,相比于 Uniswap V4 Hooks 有非常大的优势:
首先 Artela Aspects 使用 WASM 执行其代码,执行效率比 EVM 高出几个数量级;
其次,Artela Aspects 可以 Hook 整个交易的生命周期,而不只是 DeFi 核心逻辑,可以构建功能更丰富的 DApp;
最后,也是最重要的,Artela Aspects 独立运行在一个安全的沙盒环境中,这种隔离可确保 Aspects 的执行不会影响到合约执行的安全性。
Artela Aspects 的隔离性限制了 Hook 合约作为一个普通合约与外部其他合约间的相互调用,解决了 Uniswap V4 Hooks 访问控制和输入验证的痛点。对于类似 Uniswap 这样的 DeFi 合约部署到 Artela 可以享受到更快更强更安全的 Hook 体验。
总结
Uniswap 作为 DeFi 行业的重要参与者和领导者,在推动行业进步和完善功能方面发挥了至关重要的作用,此次 Uniswap V4 引入的 Hooks,毫无疑问也会引领 DEX 的发展方向,被后继者争相模仿。
但 Uniswap V4 Hooks 受限于智能合约本身的局限性,无论协议上设计得多牢固,工具库做的多完善,也无法从根源上阻止 Hook 合约和外部其他合约之间的相互调用,存在潜在的安全漏洞。
Artela 作为一个高性能 EVM 兼容 Layer 1 区块链网络,从一开始的协议上,就设计了独立运行于 WASM 中的 Aspect 来原生支持 Hooks 编程,极大提升了安全性。这给将安全视为生命的 DeFi 协议提供了一个进阶的解决方案。