欢迎大家来参加技能进阶挑战!
在本帖下用回复的方式上传你的学习笔记完成打卡 ![]()
欢迎大家来参加技能进阶挑战!
在本帖下用回复的方式上传你的学习笔记完成打卡 ![]()
Uniswap V3 是 AMM 的“专业化版本”,核心在资本效率 + 灵活性。它从“被动池”升级为“主动做市商平台”,让 LP 更像专业交易员。理解 V3 的精髓,不仅要会公式,还要会管理 LP 策略。
一、V3 的核心创新
1.集中流动性 (Concentrated Liquidity)
在 V2 中,流动性在价格曲线上是 0 → ∞ 的全区间。
在 V3 中,LP 可以选择一个 价格区间 提供流动性,只在该区间内赚取手续费。
优势:资本效率提升最高可达 4000 倍
LP 更像 主动做市商 (Active Liquidity Provider)
2.价格刻度与 Tick
价格不再是连续曲线,而是离散的 “tick” 点。
LP 选择区间时,资金被分配到对应的 tick 范围。
3.多费率池 (Multiple Fee Tiers)**
V3 允许每个交易对有不同的费率池:0.05%、0.3%、1%。
适应不同波动性资产:
稳定币 → 低费率
山寨币 → 高费率
4.改进的预言机 (TWAP)
内置时间加权平均价格 (Time-Weighted Average Price)。
安全性比 V2 强,可被其他 DeFi 协议直接调用。
二. 合约架构
Factory 合约:创建新的池 (Pool)
Pool 合约:管理某一对 Token 的流动性与交易逻辑
NFT Position Manager:每个流动性提供者的头寸 (Position) 被表示为 NFT(因为区间不同,不能再用同质化的 LP Token 表示)
Router:执行 Swap 与多池路径交易
三. LP 机制与无常损失
V2:LP 被动覆盖全区间,风险较低但资本效率低。
V3:LP 可以选择 1.01 ~ 1.05 这样的窄区间,手续费收益更高,但如果价格脱离区间,LP 资金将 变成单一资产。
无常损失 (IL):在 V3 中更复杂,因为与区间选择强相关。
四. 高级功能
范围订单 (Range Orders):LP 在特定区间提供单边流动性,本质上类似 限价单。
闪电交换:延续 V2 的设计,允许先取代币后偿还。
套利与聚合:由于多费率池与区间流动性,套利机会更多,聚合器(如 1inch、Matcha)会选择最优路径。
五. 优缺点
1.优点
资本效率显著提升
LP 收益空间更大
灵活的费率机制
更安全的预言机
2.缺点
LP 管理复杂度增加,需要主动调整
普通用户难以掌握最佳区间
资金可能因为价格突破区间而闲置
流动性提供者(LP)被赋予在任意价格区间集中流动性的能力,将提高池子的资金利用率,并允许 LP 估算认可的价格曲线。超出范围的部分,增加无常损失(Impermanent Loss, IL)风险。
范围内恒定乘积:在 $[P_a, P_b]$ 区间内,流动性(L)是恒定的:$L=\sqrt{x\times y}$
无常损失:$IL = \frac{2 \cdot \sqrt{\frac{P_{\text{current}}}{P_{\text{initial}}}}}{1 + \frac{P_{\text{current}}}{P_{\text{initial}}}} - 1$
V3 为每个交易对引入了多个池子,允许分别设置不同的交易手续费。所有池子都使用相同的工厂合约创建,默认允许:0.01%, 0.05%, 0.3% 和 1%。流动性分配在离散的“ticks”中,使得 Uniswap 可以同时兼备 AMM 和中心化交易所的好处。
非复利的手续费。由于头寸的不可互换性,复利将不再可能。手续费将独立保存,且以支付手续费的代币形式持有。V2 流动性可视为 ERC-20 代币,而 V3 流动性可视为 NFT,用 ERC-721 表示。
移除原生流动性代币。任何人都可以创建 periphery ERC-20 合约使得流动性头寸变得更可互换,但需要额外的逻辑处理手续费的收发或再投资。
通过 NonfungiblePositionManager 管理。
无需预言机用户在外部记录历史累计价格,将累计检查点放到 core 合约中,允许外部合约直接计算最近时间的链上 TWAP。
记录 log 价格之和计算几何平均数 TWAP,这样受极端值的影响更小,并且无需为每种代币记录单独的累计价格。
增加了流动性累计数 secondsPerLiquidityCumulative,每秒累计 $\frac{1}{L}$,对于那些基于 Uniswap V3 实现流动性挖矿的外部合约很有用,可以被其他合约用于判断一个交易对的哪些池子具有最可信的 TWAP。
繼前面看完 Uniswap V2 後,我也花時間研究了下 V3,他給我的感覺是它在設計上更聰明、更彈性,但同時對 LP 的要求也更高;以下是一些筆記跟心得,分享給有興趣的人~
在 V2 裡,LP 把資金放進去,其實是全價位範圍都能被交易用到。這代表如果 ETH 從 1 美元漲到 10000 美元,LP 的流動性理論上都在「支撐」這整個價格區間。
而 V3 改變了這個邏輯,讓 LP 可以指定我只想在某個價格範圍內提供流動性。
舉例:假設我覺得 ETH/USDC 會在 2000~3000 美金之間震盪,我就只把流動性集中在這個範圍。
我覺得這個設計很像「做市商自己設定止盈止損區間」,比 V2 靈活很多,但同時 LP 需要更多判斷力。
V2 時期,手續費就是固定 0.3%。
V3 提供了不同的 Fee Tier:0.05%、0.3%、1%。
這樣的設計讓 LP 可以自己選擇風險報酬比,感覺更市場化。
V2 的 LP 很「被動」,放著就行。
V3 的 LP 幾乎變成「主動投資人」:
我覺得這是 V3 最不新手友善的地方,如果只是想被動賺手續費,V3 反而不如 V2;但如果願意花心思研究策略,那 V3 的優勢非常明顯。
學完 V3,我最大的感覺是:
一、核心创新:集中流动性(Concentrated Liquidity)
价格区间定制
流动性提供者(LP)可将资金限制在特定价格区间(如 ETH/USDC 在 1800−1800−2200),而非 V2 的「0 到无穷大」范围
作用机制:仅当市场价格处于设定区间时,该流动性才参与交易并赚取手续费;区间外的流动性处于闲置状态
优势:大幅提升资金效率。相同资金在活跃价格区间内可捕获更多交易手续费,最高达 V2 的 4000 倍
Tick 离散化定价模型
价格区间被拆解为离散化的 tick,每个 tick 对应一个精确价格点,公式为:
Price=1.0001tickPrice=1.0001tick
相邻 tick 的价差固定为 0.01% ,提供高精度价格锚定36。
例如:tick=0 时价格为 1,tick=1 时为 1.0001,tick=-1 时为 0.9999
二、技术实现与合约架构
LP Token NFT 化
流动性头寸转为 ERC-721 非同质化代币(NFT),由 NonfungiblePositionManager 合约管理
每张 NFT 记录:代币对、价格区间、流动性数量、手续费累积数据等。
多层合约架构
核心合约(v3-core) :
UniswapV3Factory.sol :部署并管理交易池,支持同一代币对创建多个费率池(如 0.05%、0.3%、1%)
UniswapV3Pool.sol :核心逻辑合约,实现 swap、mint(添加流动性)、burn(移除流动性)及价格计算
价格存储革新:当前价格以 sqrtPriceX96 存储(即 ��×296P×296),通过 slot0() 读取
外围合约(v3-periphery) :
NonfungiblePositionManager.sol :管理 NFT 头寸的生命周期(创建、增/减流动性、销毁)
回调模式(Callback) :mint 或 swap 操作后,池子主动回调调用者合约以索取代币,防止欠款
三、关键机制与优化
费用分级与动态分配
LP 可选择 0.05% (稳定币对)、0.3% (主流币对)或 1% (高波动资产)三级费率,匹配不同风险手续费按流动性在有效价格区间内的占比分配,价格波动可能使 LP 退出收益区间
预言机升级(TWAP 2.0)
继承 V2 的时间加权平均价格(TWAP),但基于 tick 系统实现更高精度,有效防御闪电贷操纵
闪电清算与套利工具
支持闪电贷:在同一交易内无抵押借出代币,需归还本金 + 0.09% 手续费,否则回滚
四、对比 V2:优势与挑战
| 维度 | Uniswap V2 | Uniswap V3 |
|---|---|---|
| 资金效率 | 低(流动性分布全价格区间) | 极高(集中活跃区间) |
| LP 操作复杂度 | 简单(存入即赚费) | 复杂(需主动管理价格区间) |
| 滑点控制 | 大额交易滑点高 | 同资金下滑点显著降低 |
| 无常损失风险 | 被动承担全区间波动 | 可规避区间外风险,但区间内更敏感 |
风险提示:若价格超出 LP 设定区间,流动性失效且无法赚取手续费,需主动调整头寸
Uniswap V3 通过集中流动性和可编程头寸重构了 AMM 模型,其核心价值在于:
资本效率跃升:激活「沉睡流动性」,释放 DeFi 资金潜力
风险精细化控制:LP 可定制风险敞口,专业投资者获得策略工具
基础设施升级:TWAP 预言机、多费率池、NFT 化头寸成为行业新标准
Uniswap V3 是自动化做市商(AMM)的 “专业化版本”,核心聚焦资本效率提升与操作灵活性增强。它从 V2 的 “被动流动性池” 升级为 “主动做市商平台”,让流动性提供者(LP)更接近专业交易员的角色 —— 不仅需要理解底层公式,更需主动制定和管理流动性策略,是 DeFi 领域 AMM 模型的重要进阶形态。
集中流动性是 Uniswap V3 最核心的突破,彻底改变了 V2 中流动性 “全区间分散” 的模式:
为适配集中流动性,V3 放弃了 V2 的 “连续价格曲线”,采用离散化 Tick 定价模型:
V3 为同一交易对引入多个费率池,解决了 V2 固定 0.3% 手续费无法适配不同风险资产的问题:
在 V2 时间加权平均价格(TWAP)基础上,V3 对预言机进行了安全性与实用性优化:
secondsPerLiquidityCumulative(每秒累计 (\frac{1}{L})),可帮助外部合约判断交易对中哪些池子的 TWAP 更可信(适用于流动性挖矿等场景)。Uniswap V3 延续模块化设计,但核心合约功能与 V2 差异显著,尤其引入 NFT 管理流动性头寸:
| 合约模块 | 核心功能 |
|---|---|
| UniswapV3Factory.sol(核心合约) | 部署并管理所有交易池(Pool),支持为同一代币对创建多个费率池(如 0.05%、1%)。 |
| UniswapV3Pool.sol(核心合约) | 每个交易对的核心逻辑合约,负责实现 swap(兑换)、mint(添加流动性)、burn(移除流动性),并存储当前价格(以 sqrtPriceX96 格式,即 (\sqrt{P} \times 2^{96}))。 |
| NonfungiblePositionManager.sol(外围合约) | 管理 LP 流动性头寸的生命周期(创建、增减流动性、销毁),将每个头寸封装为 ERC-721 NFT(因 LP 选择的价格区间不同,头寸无法用 V2 同质化的 LP Token 表示)。 |
| Router.sol(外围合约) | 简化用户交互,支持代币兑换(swap)、多池路径交易(如 ETH→USDC→DAI),自动匹配最优费率池。 |
| Callback 机制 | 用于 mint 或 swap 操作后,池子主动回调调用者合约索取代币,防止用户欠款,保障资金安全。 |
V3 彻底改变了 LP 的角色定位,操作复杂度与收益潜力同步提升,核心差异对比 V2 如下:
| 维度 | Uniswap V2 | Uniswap V3 |
|---|---|---|
| 流动性范围 | 全区间(0→∞),被动参与所有价格交易 | 自定义区间(如 2000-3000 美元),仅区间内生效 |
| 资本效率 | 低(大量资金闲置在非活跃价格区间) | 极高(资金集中在活跃区间,收益密度高) |
| 操作复杂度 | 简单(存入两种代币即可,无需后续管理) | 复杂(需判断价格区间、主动调仓 rebalance) |
| 无常损失风险 | 被动承担全区间波动,风险均匀但不可规避 | 区间内风险敏感,区间外资金变单一资产(风险集中) |
| 收益模式 | 固定 0.3% 手续费分成,收益稳定但上限低 | 多费率选择,窄区间手续费收益可达 V2 的数倍 |
| 头寸凭证 | ERC-20 同质化 LP Token | ERC-721 非同质化 NFT(每个头寸唯一) |
LP 在特定区间提供单边流动性(如仅存入 USDC,设定 ETH 跌至 1800 美元时参与交易),本质上等同于 “去中心化限价单”:
延续 V2 设计,允许用户在同一交易内无抵押借出代币:
由于多费率池与离散化流动性的存在,V3 中套利机会更多:
Uniswap V3 对 DeFi 的核心贡献在于:
Uniswap V3 是一个为专业用户打造的高级自动化做市商(AMM)。它的核心定位是最大化资本效率,将流动性提供者(LP)的角色从 V2 的“被动储户”转变为需要主动制定和管理策略的“主动做市商”。它不再是一个“一劳永逸”的工具,而是一个要求更高、收益潜力也更大的专业化平台。
(0, ∞) 的整个价格曲线上。| 特性维度 | Uniswap V2 (被动、普适) | Uniswap V3 (主动、专业) |
|---|---|---|
| 流动性模型 | 均匀流动性:资金分散在 (0, ∞) 整个价格曲线 |
集中流动性:资金集中在自定义的价格区间 [Pa, Pb] |
| 资本效率 | 低:大量资金在非活跃价格区间闲置 | 极高:资金利用率大幅提升,收益潜力更高 |
| LP 角色 | 被动储户:存入后无需管理,俗称“躺赚” | 主动做市商:需要持续监控市场并主动调仓 |
| 头寸凭证 | ERC-20 代币:同质化,易于在其他 DeFi 协议中组合 | ERC-721 NFT:非同质化,每个头寸都独一无二 |
| 手续费 | 固定 0.3%:所有交易对费率统一 | 多级费率:提供 0.05%, 0.3%, 1% 等选项,更灵活 |
Uniswap V3 的机制,比 V2 复杂得多。作为运营,我更关注这些机制如何影响用户行为,以及背后藏着的金融逻辑 —— 毕竟用户不会为技术本身买单,只会为能赚到的钱和能规避的风险买单。
V2 里,LP 注入的资产会均匀分布在 0 到无穷大的价格区间里。这就像用散弹枪打鸟,大部分子弹都浪费在没人交易的价格带。比如 ETH-USDC 池,假设日常交易价可能在 4300-4800 美元波动,但 V2 的 LP 资产连 1 美元或 10 万美元的极端价格区间都要覆盖,资金效率低得离谱。
V3 让 LP 可以自定义价格区间。比如我判断 ETH 会在 4300-4800 美元震荡,就把资产集中在这个区间内。这样一来,同样的资金量,在这个区间里的 “子弹密度”(实际能促成交易的流动性)是 V2 的几十倍。用户交易时滑点更低,LP 赚的手续费也更多。
这本质上是把传统做市商的 “报价策略” 下放给了普通用户。传统交易所里,专业做市商会在盘口挂密集的买卖单,V3 只是把这个过程代码化了。但对运营来说,问题来了:普通用户哪懂怎么选区间?我在社群里看到最多的提问是 “这个币该设多少到多少的价格范围”。后来发现,有人开始卖 “区间推荐工具”,按历史波动率算最优区间,这就是运营的机会 —— 与其自己做工具,不如链接这些第三方,在文档里嵌入他们的计算器,降低用户决策门槛。
V2 只有 0.3% 一种手续费率,V3 搞了 0.05%、0.3%、1% 三档。刚开始觉得这是多此一举,后来想明白,这是在用金融里的 “风险定价” 逻辑设计规则。
稳定币对(比如 USDC-USDT)价格波动极小,无常损失几乎可以忽略,所以用 0.05% 的低费率就能吸引 LP—— 反正风险低,薄利多销。而高波动的山寨币对,LP 要承担更大的价格偏离风险,就得用 1% 的高费率补偿。这和银行给高风险企业放贷款要收更高利息是一个道理。
但用户分不清这些。我测试时发现,很多人随便选个费率就加流动性,结果要么在低波动池里赚不到钱,要么在高波动池里被无常损失啃掉收益。运营能做的,不是教他们金融学,而是给数据:在帮助中心放一张表,统计过去 30 天不同代币对在各费率池的平均年化收益,再标上最大回撤。用户看不懂原理,但看得懂数字 —— 这比讲一百遍 “风险与收益匹配” 有用。
V3 的 LP 代币变成了 NFT,每个 NFT 对应一个特定价格区间的流动性头寸。V2 里的 LP 代币是同质化的,就像超市购物卡,谁拿着都一样;V3 里的 NFT 更像房产证,每套房子(每个区间的流动性)都独一无二。
这背后是权益的精细化分割。比如我在 4400-4500 美元加了 ETH 流动性,你在 4500-4800 美元加了同样金额的 ETH 流动性,我们的 NFT 完全不同,收益计算也分开。这让 LP 能更精准地管理风险 —— 想调整策略时,不用撤出全部资产,直接新增一个 NFT 头寸就行。
但运营层面的麻烦也来了:NFT 没法像同质化代币那样拆分转让。有人在社群里问 “我想把一半的 LP 权益转给朋友怎么办”,目前没好办法。这可能会限制流动性的二次流通,尤其是机构级 LP 入场时,他们需要更灵活的权益处置方式。或许未来会有平台做 NFT 碎片化服务,这是个值得关注的生态缺口。
V2 里,无常损失是悬在 LP 头上的剑,价格波动越大,损失越狠。V3 因为有了价格区间,情况变得更复杂。如果价格始终在我设定的区间内波动,无常损失会比 V2 小 —— 因为资产没有被过度稀释。但如果价格跳出区间,我的资产会变成单一币种(比如 ETH 涨到5000 美元,超出我 4800 美元的上限,池里的 ETH 会被兑换成 USDC,我手里就只剩 USDC 了),这时候再跌回来,损失可能比 V2 还大。
这让我想起传统金融里的 “止损” 和 “止盈”。V3 的价格区间本质上是一种自动执行的止损策略,只是用户常常意识不到。运营时,与其警告 “小心无常损失”,不如开发一个模拟工具:输入用户设定的区间和投入金额,用历史数据回测 “如果过去三个月按这个策略操作,会亏多少钱、赚多少手续费”。数字比概念更有冲击力。
现在很多项目用流动性挖矿吸引 LP,但 V3 出来后,挖矿规则得重新设计。以前算收益只看锁仓量,现在还得看区间集中度。同样锁 100 万刀,集中在交易活跃区间的 LP 对生态的实际贡献,可能是分散区间的 10 倍。如果挖矿奖励还按锁仓量发,就是鼓励低效资金,反而伤害真正做事的 LP。
我在想,或许可以把 “实际促成的交易量” 作为奖励依据,让贡献越大的 LP 赚越多。但这会增加合约复杂度,也可能引发刷量。金融里的 “激励相容” 难题,在这里同样存在 —— 运营的职责不是解决难题,而是找到当前阶段最不坏的方案。
学 V3 最大的感受是,它把做市商的专业活变得平民化了,但也把金融市场的复杂性暴露无遗。用户需要的不是更强大的工具,而是更清晰的 “操作指南”,什么场景下用什么策略,大概率会有什么结果。这可能就是 Web3和传统金融的共通之处:我们不替用户做决策,只帮他们理解决策背后的逻辑。
通過深入分析 Uniswap V3 核心合約代碼庫,本文對這個去中心化交易協議的關鍵技術實現進行解析。
Uniswap V3 採用三層架構:
fee = 500; // 0.05%, tickSpacing = 10
fee = 3000; // 0.3%, tickSpacing = 60
fee = 10000; // 1%, tickSpacing = 200
function createPool(address tokenA, address tokenB, uint24 fee) external returns (address pool) {
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(getPool[token0][token1][fee] == address(0));
pool = deploy(address(this), token0, token1, fee, tickSpacing);
getPool[token0][token1][fee] = pool;
getPool[token1][token0] = pool; // 雙向映射
}
技術特點:
struct Slot0 {
uint160 sqrtPriceX96; // 當前價格平方根(Q64.96 格式)
int24 tick; // 當前 tick
uint16 observationIndex; // 觀察索引
uint16 observationCardinality; // 觀察數組大小
uint16 observationCardinalityNext;
uint8 feeProtocol; // 協議費用
bool unlocked; // 重入鎖
}
存儲優化特點:
price = 1.0001^tick
sqrtPrice = 1.0001^(tick/2)
function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
// 使用位操作和預計算值快速計算
uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
// ... 更多位操作優化
if (tick > 0) ratio = type(uint256).max / ratio;
sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
}
技術優勢:
function nextInitializedTickWithinOneWord(
mapping(int16 => uint256) storage self,
int24 tick,
int24 tickSpacing,
bool lte
) internal view returns (int24 next, bool initialized) {
int24 compressed = tick / tickSpacing;
(int16 wordPos, uint8 bitPos) = position(compressed);
uint256 mask = (1 << bitPos) - 1 + (1 << bitPos);
uint256 masked = self[wordPos] & mask;
initialized = masked != 0;
next = initialized
? (compressed - int24(bitPos - BitMath.mostSignificantBit(masked))) * tickSpacing
: (compressed - int24(bitPos)) * tickSpacing;
}
位圖優勢:
// 價格編碼:sqrtPriceX96 = sqrt(price) * 2^96
uint160 sqrtPriceX96;
// 高精度運算庫
function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
// 512 位精度乘法實現
uint256 prod0; // 低位
uint256 prod1; // 高位
assembly {
let mm := mulmod(a, b, not(0))
prod0 := mul(a, b)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// 處理高位溢出的除法邏輯...
}
定點數系統特點:
function getAmount0Delta(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity,
bool roundUp
) internal pure returns (uint256 amount0) {
uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION;
uint256 numerator2 = sqrtRatioBX96 - sqrtRatioAX96;
return roundUp
? UnsafeMath.divRoundingUp(
FullMath.mulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96),
sqrtRatioAX96
)
: FullMath.mulDiv(numerator1, numerator2, sqrtRatioBX96) / sqrtRatioAX96;
}
數學原理:
L = sqrt(xy) 推導function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1) {
// 狀態初始化
SwapState memory state = SwapState({
amountSpecifiedRemaining: amountSpecified,
sqrtPriceX96: slot0.sqrtPriceX96,
tick: slot0.tick,
liquidity: liquidity
});
// 主要交換循環
while (state.amountSpecifiedRemaining != 0 && state.sqrtPriceX96 != sqrtPriceLimitX96) {
// 1. 找到下一個初始化的 tick
(int24 tickNext, bool initialized) = tickBitmap.nextInitializedTickWithinOneWord(
state.tick, tickSpacing, zeroForOne
);
// 2. 計算到下一個 tick 的交換
(state.sqrtPriceX96, amountIn, amountOut, feeAmount) = SwapMath.computeSwapStep(
state.sqrtPriceX96,
TickMath.getSqrtRatioAtTick(tickNext),
state.liquidity,
state.amountSpecifiedRemaining,
fee
);
// 3. 跨越 tick 時更新流動性
if (state.sqrtPriceX96 == TickMath.getSqrtRatioAtTick(tickNext)) {
if (initialized) {
int128 liquidityNet = ticks.cross(tickNext, /*...*/);
state.liquidity = LiquidityMath.addDelta(state.liquidity, liquidityNet);
}
state.tick = zeroForOne ? tickNext - 1 : tickNext;
}
}
// 回調和狀態更新...
}
交換算法特點:
contract NoDelegateCall {
address private immutable original;
constructor() { original = address(this); }
modifier noDelegateCall() {
require(address(this) == original);
_;
}
}
library SafeCast {
function toUint128(uint256 y) internal pure returns (uint128 z) {
require((z = uint128(y)) == y);
}
function toInt256(uint256 y) internal pure returns (int256 z) {
require(y < 2**255);
z = int256(y);
}
}
安全機制包括:
// UnsafeMath:已知安全情況下省略檢查
library UnsafeMath {
function divRoundingUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly { z := add(div(x, y), gt(mod(x, y), 0)) }
}
}
優化策略:
struct Observation {
uint32 blockTimestamp;
int56 tickCumulative;
uint160 secondsPerLiquidityCumulativeX128;
bool initialized;
}
function observe(uint32[] calldata secondsAgos) external view
returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s) {
return observations.observe(_blockTimestamp(), secondsAgos, slot0.tick, /*...*/);
}
Oracle 特點:
function flash(address recipient, uint256 amount0, uint256 amount1, bytes calldata data) external {
uint256 fee0 = FullMath.mulDivRoundingUp(amount0, fee, 1e6);
uint256 fee1 = FullMath.mulDivRoundingUp(amount1, fee, 1e6);
// 樂觀轉帳
if (amount0 > 0) TransferHelper.safeTransfer(token0, recipient, amount0);
if (amount1 > 0) TransferHelper.safeTransfer(token1, recipient, amount1);
// 回調執行
IUniswapV3FlashCallback(msg.sender).uniswapV3FlashCallback(fee0, fee1, data);
// 費用驗證
require(balance0() >= balance0Before + fee0, 'F0');
require(balance1() >= balance1Before + fee1, 'F1');
}
閃電貸改進:
mulDivRoundingUp 確保準確性| 特性 | V2 | V3 | 技術改進 |
|---|---|---|---|
| 流動性分佈 | 全價格範圍 | 集中流動性 | 資本效率提升 10-100 倍 |
| 費率結構 | 固定 0.3% | 多層級費率 | 0.05%/0.3%/1% 三檔選擇 |
| 頭寸管理 | 同質化代幣 | NFT 頭寸 | 個性化流動性管理 |
| Oracle 精度 | 基礎 TWAP | 增強 Oracle | 流動性加權 TWAP |
V2 交換(簡單):
uint amountOut = (amountIn * 997 * reserveOut) / (reserveIn * 1000 + amountIn * 997);
V3 交換(複雜):
通過分析 Uniswap V3,可以提取以下技術設計原則:
重大創新:集中流動性
V3 最大的突破是讓流動性提供者可以選擇價格區間。
具體改進:
Uniswap v3 的核心理念是集中流动性:在自定义价格范围内分配的流动性。在早期版本中,流动性沿着 0 到无穷大之间的价格曲线均匀分布。
先前的均匀分布允许在整个价格区间 (0, ∞) 进行交易,而不会造成任何流动性损失。然而,在许多资金池中,大部分流动性从未被使用过。
以稳定币对为例,两种资产的相对价格保持相对稳定。稳定币对典型价格区间之外的流动性很少被触及。例如,v2 DAI/USDC 对在 0.99 美元至 1.01 美元之间交易时,占用了总可用资金的约 0.50%,而流动性提供者 (LP) 预计在这个价格区间内交易量最大,因此手续费收入也最高。
在 v3 版本中,流动性提供者可以将其资金集中到小于 (0, ∞) 的价格区间。例如,在稳定币/稳定币对中,流动性提供者可以选择将资金仅配置在 0.99 - 1.01 的区间。这样一来,交易者可以在中间价附近获得更深的流动性,而流动性提供者也可以利用其资金赚取更多交易费。我们将集中到有限区间的流动性称为仓位。每个流动性池中的流动性提供者可能拥有许多不同的仓位,从而创建反映每个流动性提供者偏好的个性化价格曲线。
Active Liquidity
随着资产价格的上涨或下跌,它可能会超出流动性提供者在仓位中设定的价格区间。当价格超出仓位区间时,该仓位的流动性将不再活跃,也无法再赚取费用。
当价格朝一个方向波动时,流动性提供者会获得更多一种资产,因为交换者对另一种资产的需求增加,直到他们的全部流动性仅由一种资产组成。(在 v2 版本中,我们通常不会看到这种行为,因为流动性提供者很少达到两种资产价格的上限或下限,即 0 和 ∞)。如果价格重新进入该区间,流动性就会再次活跃,处于该区间的流动性提供者将再次开始赚取费用。
重要的是,流动性提供者可以自由创建任意数量的仓位,每个仓位都有各自的价格区间。集中流动性是一种机制,让市场决定合理的流动性分配,因为理性的流动性提供者有动力集中流动性,同时确保其流动性保持活跃。
为了实现集中的流动性,曾经连续的价格空间范围已被刻度所划分。
刻度是价格空间中离散区域之间的边界。刻度的间隔使得1个刻度的上升或下降代表价格空间中任意一点的价格上涨或下跌0.01%。
报价点是流动性仓位的边界。创建仓位时,提供者必须选择代表其仓位边界的最低报价点和最高报价点。
随着现货价格在互换过程中发生变化,资金池合约将持续将出账资产兑换为入账资产,逐步使用当前报价间隔1内的所有可用流动性,直到下一个报价到达。此时,合约将切换到新的报价,并激活在新报价范围内具有边界的仓位内所有处于休眠状态的流动性。
虽然每个池子都有相同数量的标的报价,但实际上只有一部分能够作为活跃报价。由于 v3 智能合约的性质,报价间隔与掉期费直接相关。较低的费用等级允许更接近的潜在活跃报价,而较高的费用等级允许相对较宽的潜在活跃报价间隔。
虽然非活跃报价对掉期交易成本没有影响,但跨越活跃报价确实会增加跨越该报价的交易成本,因为报价跨越将激活以给定报价为边界的任何新头寸内的流动性。
在资本效率至关重要的领域,例如稳定币对,较窄的刻度间距会增加流动性供应的粒度,并可能降低交换时的价格影响 - 结果是稳定币交换的价格显着提高。
在 Uniswap v2 中,流动性沿着 x*y=k 的价格曲线均匀分布,所有价格在 0 到无穷大之间的资产都会被预留。对于大多数资金池来说,这些流动性的大部分从未被使用过。例如,v2 版本的 DAI/USDC 交易对仅预留了约 0.50% 的资金用于 0.99 美元到 1.01 美元之间的交易,而流动性提供者 (LP) 预计在这个价格区间内交易量最大,因此手续费也最高。
V2 流动性提供者仅能从其资本的一小部分中赚取费用,这可能无法适当补偿他们因持有大量两种代币而承担的价格风险(“无常损失”)。此外,由于流动性在所有价格区间都较为分散,交易者通常会面临较高的滑点。
在 Uniswap v3 中,流动性提供者 (LP) 可以将其资金集中在自定义价格范围内,从而以期望的价格提供更大的流动性。这样,LP 就可以构建反映自身偏好的个性化价格曲线。
流动性提供者 (LP) 可以在一个池子内组合任意数量的不同集中仓位。例如,ETH/DAI 池中的 LP 可以选择将 100 美元配置到 1,000-2,000 美元的价格区间,并将 50 美元配置到 1,500-1,750 美元的价格区间。
通过这样做,LP 可以近似任何自动做市商或活跃订单簿的形状。
用户可以根据所有单条曲线的流动性组合进行交易,无需增加每个流动性提供者的 Gas 成本。在特定价格区间收取的交易费将由流动性提供者根据其在该区间贡献的流动性按比例分成。
通过集中流动性,流动性提供者 (LP) 可以在指定价格范围内提供与 v2 相同的流动性深度,同时降低资本风险。节省下来的资金可以存放在外部,投资于不同的资产,存放在 DeFi 的其他地方,或用于在指定价格范围内增加敞口以赚取更多交易费。
举个例子来说明一下:
Alice 和 Bob 都想在 Uniswap v3 上的 ETH/DAI 池中提供流动性。他们各自拥有 100 万美元。当前 ETH 的价格为 1,500 DAI。
Alice 决定将她的资金配置到整个价格区间(就像她在 Uniswap v2 中所做的那样)。她存入了 500,000 DAI 和 333.33 ETH(总价值 100 万美元)。
Bob 则建立了一个集中仓位,只在 1,000 到 2,250 的价格区间内进行入金。他存入了 91,751 DAI 和 61.17 ETH,总价值约 183,500 美元。剩下的 816,500 美元他自己留着,想怎么投资就怎么投资。
尽管 Alice 投入的资金是 Bob 的 5.44 倍,但只要 ETH/DAI 价格保持在 1,000 至 2,250 范围内,他们就能赚取相同数额的费用。
Bob 的自定义仓位也充当了其流动性的止损机制。如果 ETH 价格跌至 0 美元,Alice 和 Bob 的流动性都将完全以 ETH 计价。然而,Bob 的损失仅为 159,000 美元,而 Alice 的损失为 100 万美元。Bob 可以用这笔额外的 816,500 美元来对冲下行风险,或投资于任何其他可行的策略。
在 Uniswap V3 中,集中流动性是一种革新性的机制,它允许流动性提供者(LPs)将他们的资金分配到自定义的价格区间内。这与 Uniswap 早期版本中将流动性均匀分布在从 0 到无穷大价格曲线上的方式截然不同。
Uniswap V2 的一个主要问题是,大部分流动性资金从未被有效利用。例如,在 DAI/USDC 这样的稳定币交易对中,价格通常稳定在 1 美元附近。在 V2 中,LP 的资金被分散到所有可能的价位,但只有极小一部分(约 0.5%)的资金真正用于 0.99 美元到 1.01 美元之间的交易。这意味着大部分资本都处于闲置状态,无法赚取费用,也无法有效抵抗无常损失。
而 V3 的集中流动性解决了这个问题。LPs 可以选择将他们的资金集中在最有可能发生交易的价格区间内,从而:
当资产价格波动时,它可能会超出 LP 设定的价格区间。当这种情况发生时,该仓位的流动性将变为非活跃,无法再赚取费用。如果价格重新回到该区间,流动性则会再次变为活跃。
举例来说,一个 DAI/USDC 交易对的 LP 将资金集中在 0.99 美元到 1.01 美元之间。
为了实现集中流动性,Uniswap V3 将连续的价格空间划分为离散的刻度。
当交易发生时,流动性池合约会逐步使用当前刻度区间内的所有流动性,直到价格到达下一个刻度。此时,合约会切换到新的刻度,激活在该刻度范围内具有边界的所有非活跃流动性仓位。
虽然这种机制大大提高了资本效率,但它也引入了一个权衡:集中流动性使 LP 的头寸更容易受到无常损失的影响。由于 LP 将资金集中在较窄的区间,当价格大幅波动时,他们的头寸会更快地转换为单一资产,从而可能导致比 V2 中更大的损失。
以一个具体的例子来比较 V2 和 V3 的资本效率:
假设 Alice 和 Bob 都想在 ETH/DAI 池中提供流动性,当前 ETH 价格为 1,500 DAI,他们各自有 100 万美元。
在这种情况下,只要 ETH/DAI 的价格保持在 1,000 到 2,250 之间,Alice 和 Bob 就能赚取相同数额的费用,而 Bob 剩余的 816,500 美元则可以自由支配。这充分展示了 V3 集中流动性所带来的巨大资本效率优势。
总结:v3 流动性提供商可以选择以与 v2 流动性提供商相同的资本规模,提供更大的流动性深度,而不是像 v2 流动性提供商那样以更少的资本提供相同的流动性深度。这需要承担更大的价格风险(“无常损失”),同时支持更大的交易量并赚取更高的费用。