Uniswap V3 AMM核心原理:集中流动性与Tick数学
Uniswap V3 AMM核心原理集中流动性与Tick数学一、引言Uniswap V3是DeFi史上最重要的创新之一——通过集中流动性(Concentrated Liquidity),LP可以将资金集中在特定价格区间,资本效率比V2提升4000倍。但代价是复杂的数学和LP策略。二、从V2恒定乘积到V3集中流动性// V2: x * y k (全价格曲线均匀分配) // 问题: 99%的资金在极端价格下闲置 // V3: 虚拟储备量(Virtual Reserves) // 在区间[P_low, P_high]内: (x x_virtual) * (y y_virtual) L² // L √k, 是流动性的度量 // 核心公式推导: // 价格 P y / x // 在时刻t, x * y L² → x L/√P, y L√P // 当价格从P_a移到P_b: // Δx L * (1/√P_b - 1/√P_a) // Δy L * (√P_b - √P_a)三、Tick数学价格的对数空间3.1 为什么用Tick// V3将连续价格离散化为Tick空间 // tick ∈ [-887272, 887272] // P(tick) 1.0001^tick // tick0: P1.0001^0 1 // tick1000: P1.0001^1000 ≈ 1.105 (USDC/ETH涨10.5%) // tick-1000: P1.0001^-1000 ≈ 0.905 (跌9.5%) // tick887272: P1.0001^887272 ≈ 2^128(最大价格)3.2 SqrtPriceX96避免浮点运算// EVM没有浮点数 → 用Q64.96定点数 // sqrtPriceX96 √P * 2^96 library TickMath { int24 internal constant MIN_TICK -887272; int24 internal constant MAX_TICK 887272; // tick → sqrtPriceX96 function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160) { uint256 absTick tick 0 ? uint256(-int256(tick)) : uint256(tick); // 利用1.0001的二进制分解快速计算 uint256 ratio absTick 0x1 ! 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000; if (absTick 0x2 ! 0) ratio (ratio * 0xfff97272373d413259a46990580e213a) 128; if (absTick 0x4 ! 0) ratio (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) 128; if (absTick 0x8 ! 0) ratio (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) 128; // ... 更多位移计算 if (absTick 0x20000 ! 0) ratio (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) 128; if (tick 0) ratio type(uint256).max / ratio; return uint160((ratio 32) (ratio % (1 32) 0 ? 0 : 1)); } }四、Position管理4.1 Mint添加流动性contract UniswapV3Pool { struct Position { uint128 liquidity; // L int24 tickLower; // P_low对应的tick int24 tickUpper; // P_high对应的tick uint256 feeGrowthInside0LastX128; uint256 feeGrowthInside1LastX128; uint128 tokensOwed0; uint128 tokensOwed1; } mapping(bytes32 Position) public positions; // ★ 核心:铸造流动性 function mint( address owner, int24 tickLower, int24 tickUpper, uint128 amount ) external returns (uint256 amount0, uint256 amount1) { // 1. 计算需要存入的两种Token数量 (amount0, amount1) _calculateAmounts( slot0.sqrtPriceX96, // 当前价格的√P tickLower, tickUpper, amount // ΔL ); // 2. 更新Position Position storage position positions[ keccak256(abi.encodePacked(owner, tickLower, tickUpper)) ]; position.liquidity amount; position.tickLower tickLower; position.tickUpper tickUpper; // 3. 记录入场时的费用增长基数 (position.feeGrowthInside0LastX128, position.feeGrowthInside1LastX128) _getFeeGrowthInside( tickLower, tickUpper ); // 4. 更新Tick位图(标记哪些tick有流动性) if (amount 0) { flipTick(tickLower, true); flipTick(tickUpper, true); } // 5. 转账代币到池子 if (amount0 0) token0.transferFrom(msg.sender, address(this), amount0); if (amount1 0) token1.transferFrom(msg.sender, address(this), amount1); } // 计算给定ΔL时需要存入的Δx和Δy function _calculateAmounts( uint160 sqrtPriceX96, int24 tickLower, int24 tickUpper, uint128 liquidity ) internal pure returns (uint256, uint256) { uint160 sqrtRatioAX96 TickMath.getSqrtRatioAtTick(tickLower); uint160 sqrtRatioBX96 TickMath.getSqrtRatioAtTick(tickUpper); if (sqrtPriceX96 sqrtRatioAX96) { // 当前价格 ≤ 下界: 全部存Token0 return ( FullMath.mulDiv( uint256(liquidity) 96, sqrtRatioBX96 - sqrtRatioAX96, sqrtRatioBX96 * sqrtRatioAX96 / (1 96) ), 0 ); } else if (sqrtPriceX96 sqrtRatioBX96) { // 当前价格 ≥ 上界: 全部存Token1 return ( 0, FullMath.mulDiv( uint256(liquidity) * (1 96), sqrtRatioBX96 - sqrtRatioAX96, 1 96 ) ); } else { // 价格在区间内: 按比例分配两种Token return ( // Token0: 对应(P → P_high)部分 FullMath.mulDiv( uint256(liquidity) 96, sqrtRatioBX96 - sqrtPriceX96, sqrtRatioBX96 * sqrtPriceX96 / (1 96) ), // Token1: 对应(P_low → P)部分 FullMath.mulDiv( uint256(liquidity), sqrtPriceX96 - sqrtRatioAX96, 1 96 ) ); } } }4.2 Swap跨Tick执行// Swap执行流程(Go实现,原合约是Solidity)func(pool*Pool)Swap(zeroForOnebool,amountSpecified*big.Int,sqrtPriceLimitX96*big.Int)(amount0,amount1*big.Int){varexactInput,exactOutputboolifamountSpecified.Sign()0{exactInputtrue// 我要卖出确定数量的Token0}else{exactOutputtrue// 我要买入确定数量的Token1}state:SwapState{amountSpecifiedRemaining:amountSpecified,amountCalculated:new(big.Int),sqrtPriceX96:pool.sqrtPriceX96,tick:pool.tick,liquidity:pool.liquidity,}// ★ 核心循环:逐Tick跨越forstate.amountSpecifiedRemaining.Sign()!0state.sqrtPriceX96.Cmp(sqrtPriceLimitX96)!0{// 1. 找到下一个有流动性的Tickstep:StepComputations{}step.tickNextpool.nextInitializedTick(state.tick,zeroForOne)// 2. 计算该Tick的目标价格step.sqrtPriceNextX96TickMath.GetSqrtRatioAtTick(step.tickNext)// 3. 计算到达下一个Tick所需的Amount Instep.amountInpool.computeSwapStep(state.sqrtPriceX96,targetSqrtPrice(step.sqrtPriceNextX96,sqrtPriceLimitX96,zeroForOne),state.liquidity,state.amountSpecifiedRemaining,)// 4. 累积手续费(V3每笔Swap收取0.05%/0.3%/1%)feeAmount:step.amountIn*pool.fee/1_000_000state.feeGrowthGlobalfeeAmount*(1128)/state.liquidity// 5. 更新状态state.sqrtPriceX96step.sqrtPriceNextX96 state.amountSpecifiedRemaining.Sub(step.amountInfeeAmount)state.amountCalculated.Add(step.amountOut)// 6. 如果到达Tick边界,更新liquidityifstate.sqrtPriceX96.Cmp(step.sqrtPriceNextX96)0{// 跨越Tick → 净流动性该Tick的流动性liquidityDelta:pool.getLiquidityDelta(step.tickNext)state.liquidityliquidityDelta state.tickstep.tickNext}}// 7. 更新池子全局状态pool.sqrtPriceX96state.sqrtPriceX96 pool.tickstate.tick pool.liquiditystate.liquidityreturnamount0,amount1}五、手续费累积机制// V3的手续费累积是精髓: // 全局累积器 f_g Σ(fee_i / L_i) × 2^128 // Position在[t1,t2]应得手续费 L_position × (f_g(t2) - f_g(t1)) contract FeeAccumulator { // 全局累积器(Growth) uint256 public feeGrowthGlobal0X128; uint256 public feeGrowthGlobal1X128; // 每个Tick的外部累积器(区间边界) mapping(int24 uint256) public feeGrowthOutside0X128; mapping(int24 uint256) public feeGrowthOutside1X128; // 计算区间[tickLower, tickUpper]的手续费Growth function getFeeGrowthInside( int24 tickLower, int24 tickUpper, int24 tickCurrent, uint256 feeGrowthGlobal0X128 ) internal view returns (uint256, uint256) { uint256 feeGrowthBelow0X128; uint256 feeGrowthAbove0X128; if (tickCurrent tickLower) { feeGrowthBelow0X128 feeGrowthOutside0X128[tickLower]; } else { feeGrowthBelow0X128 feeGrowthGlobal0X128 - feeGrowthOutside0X128[tickLower]; } if (tickCurrent tickUpper) { feeGrowthAbove0X128 feeGrowthGlobal0X128 - feeGrowthOutside0X128[tickUpper]; } else { feeGrowthAbove0X128 feeGrowthOutside0X128[tickUpper]; } // 全局 - below - above inside! return ( feeGrowthGlobal0X128 - feeGrowthBelow0X128 - feeGrowthAbove0X128, 0 // token1同理 ); } // Position应得手续费 function collectFees(Position storage position) internal returns (uint128, uint128) { (uint256 feeGrowthInside0, uint256 feeGrowthInside1) getFeeGrowthInside( position.tickLower, position.tickUpper, slot0.tick, feeGrowthGlobal0X128 ); // 手续费 L × (当前Growth - 上次收取时的Growth) uint128 tokensOwed0 uint128( FullMath.mulDiv( feeGrowthInside0 - position.feeGrowthInside0LastX128, position.liquidity, FixedPoint128.Q128 ) ); position.feeGrowthInside0LastX128 feeGrowthInside0; return (tokensOwed0, tokensOwed1); } }六、TWAP预言机// V3内置TWAP预言机,每个池子存65536个价格观测点 struct Observation { uint32 blockTimestamp; // 观测时间 int56 tickCumulative; // tick * seconds 累积 uint160 liquidityCumulative; bool initialized; } // 查询TWAP function consult(address pool, uint32 period) external view returns (int24) { Observation memory then observe(pool, 0); // 最早的有效观测 Observation memory now observe(pool, period); // 当前 // tickCumulative是tick×时间的积分 → (now - then) / period 平均tick int56 tickCumulativesDelta now.tickCumulative - then.tickCumulative; int24 timeWeightedAverageTick int24(tickCumulativesDelta / int56(int32(period))); return timeWeightedAverageTick; // TWAP操纵成本 (流动性×时间) → 30分钟TWAP几乎不可能被操纵 }七、V3 vs V2 资本效率对比// 假设ETH/USDC池,当前价格$2000 // V2: 存入 $2000 USDC 1 ETH $4000 TVL // V3: 同样$4000 TVL,集中区间[$1900, $2100] // 当价格在区间内: $4000资金≈V2的$16M资金效率(4000x!) // 计算: // V2: L_v2 √(2000 * 1) 44.72 // V3 narrow: L_v3 $4000/(√2100 - √1900) ≈ 1789 // 效率比: (1789/44.72)² ≈ 1600x (在区间内) // 但区间外流动性0,需要主动管理!八、总结Uniswap V3三大创新:集中流动性— 区间内效率4000x,区间外为0Tick数学— Q64.96定点数 1.0001对数空间,精确无浮点误差手续费累积— 全局Growth→Tick外累积→Position内差分,一键claim复杂度的代价是LP需要主动管理仓位——催生了Arrakis/Gamma等自动化LP协议。

相关新闻

钉钉虚拟定位怎么设置?XposedRimetHelper 三步实操避坑指南

钉钉虚拟定位怎么设置?XposedRimetHelper 三步实操避坑指南

钉钉虚拟定位怎么设置?XposedRimetHelper 三步实操避坑指南 【免费下载链接】XposedRimetHelper Xposed 钉钉辅助模块,暂时实现模拟位置。 项目地址: https://gitcode.com/gh_mirrors/xp/XposedRimetHelper 如果你正在搜"钉钉虚拟定位"…

2026/10/1 1:06:23 阅读更多 →
GIF文件太大?搞懂颜色压缩原理,不用缩尺寸也能瘦身一半

GIF文件太大?搞懂颜色压缩原理,不用缩尺寸也能瘦身一半

目录 第一部分:减少帧数——最直接但有限 第二部分:统一每帧画布尺寸——最关键的一步 第三部分:主动降色——性价比最高的手段 第四部分:颜色距离计算——量化算法的底层逻辑 第五部分:颜色数选择的参考表 第六…

2026/10/13 4:03:05 阅读更多 →
中级开发者用 AI,最容易掉进的 5 个坑

中级开发者用 AI,最容易掉进的 5 个坑

文章目录开篇一、为什么中级开发者更容易踩坑二、这 5 个坑的共同问题是什么三、中级开发者最容易掉进的 5 个坑1. 需求只说一句话,就让 AI 直接写代码2. 不提供项目上下文,却期待 AI 写出可直接合并的代码3. 看到 AI 代码能运行,就跳过审查和…

2026/10/10 17:57:22 阅读更多 →

最新新闻

darknet运行报错libopencv_highgui.so.3.2缺失?动态库排查与解决全攻略

darknet运行报错libopencv_highgui.so.3.2缺失?动态库排查与解决全攻略

直接跑./darknet就报错error while loading shared libraries: libopencv_highgui.so.3.2,这种动态库缺失的问题,估计每个搞深度学习目标检测的人都被它堵过一阵子。明明编译都过了,运行却翻车,查了半天也不知道到底哪里没对上。如…

2026/10/13 4:02:58 阅读更多 →
AnyPS5:面向PS5主机的本地化系统工具链设计与实现

AnyPS5:面向PS5主机的本地化系统工具链设计与实现

项目标题本身“AnyPS5”未提供足够上下文,但结合命名惯例、技术社区常见实践及合规安全边界,可明确判断:这是一个面向 PlayStation 5 主机的本地化工具类项目代号,聚焦于主机端系统级功能增强、本地环境适配或用户侧体验优化&…

2026/10/13 4:02:58 阅读更多 →
并查集动态维护连通块大小:‘星球联盟‘题解与易错点

并查集动态维护连通块大小:‘星球联盟‘题解与易错点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 4:02:58 阅读更多 →
AI原生IDE与插件深度对比:Cursor、Trae、通义灵码能力边界与选型指南

AI原生IDE与插件深度对比:Cursor、Trae、通义灵码能力边界与选型指南

这两年AI编程工具的变化速度,快得有点不讲道理。我回想最早用插件式AI补全的时候,代码行预测已经够惊艳了;但现在的AI原生IDE和新一代编程插件,已经把范围从“猜你下一个单词”扩展到了“替你改文件、跑命令、做收尾”。Cursor、T…

2026/10/13 4:02:58 阅读更多 →
GEO优化实战:让DeepSeek、Qwen、豆包、Kimi主动引用你的内容

GEO优化实战:让DeepSeek、Qwen、豆包、Kimi主动引用你的内容

上周我把同一个问题同时丢给 DeepSeek、Qwen、豆包、Kimi,问的是某工业软件厂商的产品优势。四个助手给出的答案里,只有两个提到了这个品牌,引用来源几乎没有交集;其中一个完整转述了官网页面上的一句话,另一个却把品牌…

2026/10/13 4:02:58 阅读更多 →
基于三菱PLC的自动配料控制系统设计:双速给料与落差补偿实战

基于三菱PLC的自动配料控制系统设计:双速给料与落差补偿实战

做自动配料控制系统,绕不开两件事:PLC的选型,和配料流程里那些让人头疼的细节——飞料、秤漂、配方切换、粘度变化导致的给料差异。这个“基于三菱PLC的自动配料控制系统的设计”项目,从需求拆解、硬件选型、控制逻辑到现场调试完…

2026/10/13 4:01:58 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →