Skip to content
落叶的博客
Go back

Uniswap V4 开始收协议费了:怎么用 Hook 池规避收费

Table of contents

Open Table of contents

一、背景介绍:V4 协议费从哪天开始收

收费时间线

Uniswap 在 2026 年 7 月 27 日 执行了第一批治理提案,正式在以下链上开启 V4 协议费:

也就是说,从 2026 年 7 月 27 日起,这些链上符合条件的 V4 池就开始收协议费了。

协议费 vs LP 费:不是一回事

交易者付的 swap fee 里,其实拆成了两块:一部分给协议层(Protocol Fee),一部分给流动性提供者(LP Fee)。

V4 core 是先对输入金额收 protocol fee,再对剩余金额收 LP fee,所以合成公式不是简单的相加:

swapFee = protocolFee + lpFee - (protocolFee × lpFee / 1,000,000)

举个数感上的例子:一个 0.30% LP fee + 0.05% protocol fee 的池子,交易 10,000 USDC 时,协议大约拿 5 USDC,LP 大约拿 29.985 USDC,总手续费约 34.985 USDC,换算下来约 0.34985%——比直接 0.35% 略低一点点,因为两种费率是顺序作用的。

V4 的两个特殊点

第一,protocol fee 可以按交易方向分别设置。比如 token0→token1 收 5 bps、token1→token0 收 3 bps,这两个值编码在同一个协议费配置里。当然,V4 core 对单个方向的协议费有上限,MAX_PROTOCOL_FEE 是 1000 pips = 0.1% = 10 bps。

第二,要区分三个容易搞混的概念——LP fee 是 LP 提供流动性的收入,Protocol fee 是协议层抽走的收入,Hook fee 是 Hook 自己额外设计的收费机制。Hook fee 是 V4 的扩展能力,跟 core 层面的 LP fee / protocol fee 不在一个维度。

关键:不是所有池子都收

这次收费有明确的 pool family 限定,不是给所有 V4 池统一打开 fee switch。具体来说,目前开启协议费的是三类:

而其他普通 Hook pools 默认不收(除非治理后续把它加进收费名单或单独 override);Dynamic fee Hook pools 也不一定收,要具体看它的 Hook 是否属于收费 family。

对于最常见的无 Hook static pool,协议费大致按这个曲线对应(LP fee → Protocol fee):

0.03 bps  → 0.01 bps
0.75 bps  → 0.20 bps
1 bps     → 0.25 bps
3.75 bps  → 1 bps
5 bps     → 1.25 bps
25 bps    → 4 bps
30 bps    → 5 bps(0.05%)
≥83.34 bps → 10 bps(0.10%,封顶)

协议费上限仍是 10 bps。

所以一个很实用的判断:Ethereum 上一个 USDC/ETH、0.30% LP fee、没有 Hook 的普通池,从 7 月 27 日起就要交 0.05% 的协议费,交易者有效手续费约 0.34985%。

二、实操:怎么用 Hook 池规避协议费

核心思路

既然协议费只对”无 Hook 的 static pool”等少数 family 收,那理论上就能这么干:

建池时挂一个几乎什么都不干的 Hook,让池子变成”普通 Hook pool”,就能不进收费范围。

极端对比如下:

Pool A(要收费)

Pool B(可能不收)

只要 Pool B 的路由、gas、流动性体验和 A 差不多,理性的 LP 和 integrator 就有搬过去的动力。

实操要点:Hook 怎么部署

V4 的 Hook 不是随手部署个合约就能用——Hook 合约地址的低位编码了它启用的权限。要部署一个启用 beforeSwap(权限位 0x4000)的 Hook,部署地址必须满足:

uint160(hookAddress) & 0x3fff == 0x4000

这就是为什么部署 Hook 通常要 CREATE2:靠不断换 salt 提前算出地址,直到找到一个低位满足权限要求的。这跟我之前那篇《如何实现 Uniswap V4 流动性的白名单添加控制》用的是同一套路,只是那边是 beforeAddLiquidity(0x0800),这里换成 beforeSwap(0x4000)。

一个”空 Hook”的最小骨架大概长这样:

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

contract EmptyBeforeSwapHook {
    // 部署地址需满足 address & 0x3fff == 0x4000(beforeSwap 权限位)
    address public immutable poolManager;

    constructor(address poolManager_) {
        poolManager = poolManager_;
    }

    function beforeSwap(
        address,
        PoolKey calldata,
        Pool.SwapParams calldata,
        bytes calldata
    ) external returns (bytes4, int128, int128) {
        // 什么都不做,只返回需要的 selector
        return (this.beforeSwap.selector, 0, 0);
    }
}

(PoolKey、Pool.SwapParams 这些类型定义在 V4 的库里,实际项目直接 import 即可。)

但这不是”稳赚”的终局方案

话说回来,如果”无 Hook 池收费、挂个 Hook 就不收费”这么简单地写死,那确实会产生很强的规避激励。现实的机制其实是:

从机制设计角度看,这其实就是经典的 tax-base leakage / regulatory arbitrage(税基泄漏 / 规则套利):协议费越高,绕费的 Hook 越值得开发,流动性就越容易迁移,最终实际可征税的基数反而可能变小。所以 Uniswap 得把费率控制在”懒得为这几个 bps 绕路”的程度,或者把收费规则做得足够普适。

还有一层:Hook 不见得非得是”空”的。开发者完全可以挂一个很轻的功能(比如 TWAP 检查、限价逻辑、动态费率),顺手也拿到协议费优势。到时候治理再说”这个 Hook 是假的,我要收费”,分类就开始主观了。

小结

这次 V4 协议费上线,我更倾向于理解为第一阶段 rollout,而不是已经解决机制设计问题的终局方案。它明确只激活了三个 pool family,也保留了以后改分类规则的空间。

跑得快的能吃到这个时间差,但把它当成长期确定性方案,风险不小。

如果你对 PoolManager.swap() 里 protocol fee 具体怎么入账、ProtocolFeeLibrary.calculateSwapFee() 那几行怎么算感兴趣,也可以再展开聊聊。Hook 部署的更多细节,欢迎看我之前的《如何实现 Uniswap V4 流动性的白名单添加控制》,权限位和 CREATE2 的套路是通用的。


Share this post:

Next Post
IntentTrade:一个解析推特交易意图的实验项目