尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
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协议。
RELATED

相关推荐

NLP 评测代码评审,先排数据泄漏和口径漂移

NLP 评测代码评审,先排数据泄漏和口径漂移

NLP 评测代码评审,先排数据泄漏和口径漂移NLP 评测最危险的错误往往不会让程序报错:先全局清洗再切分、标签映射漂移、度量实现不一致,都能制造虚假的改进。1. 先画出样本进入指标的路径 NLP 评测要先定义任务边界、样本来源、分词或编码版本…

📅 2026/9/5 1:15:24
自学嵌入式第23天(Linux系统编程篇——文件编程)

自学嵌入式第23天(Linux系统编程篇——文件编程)

Linux系统编程由网络编程,文件编程,多任务编程组成。在这一篇我们主要学习的是函数的使用,函数又有内核函数和库函数两种,库函数是别人把内核函数封装好后使用的函数一、Linux系统基础概念1.Linux系统分层架构我们平时写的.c&…

📅 2026/9/13 15:51:17
Kimi    LeetCode 3906. 统计网格路径中好整数的数目 C语言实现

Kimi LeetCode 3906. 统计网格路径中好整数的数目 C语言实现

以下是 LeetCode 3906 的 C 语言实现&#xff0c;采用数位 DP 思路。由于 C 没有内置的递归记忆化&#xff0c;使用静态数组手动实现记忆化搜索。c #include <stdio.h> #include <stdlib.h> #include <string.h>// 全局/静态变量用于 DFS static bool key[16…

📅 2026/10/21 17:06:12
MORE NEWS

更多资讯

📰

自学AI应用开发半年后,我为什么还是报了训练营?

1. 半年自学AI应用开发&#xff0c;我卡在了“能跑通”和“能交付”之间去年年初&#xff0c;我给自己定了个目标&#xff1a;用半年时间自学AI应用开发&#xff0c;争取能独立做出一个能拿得出手的项目。当时我的底气来自哪里&#xff1f;一是网上教程铺天盖地&#xff0c;从大…

📰

AI应用开发学习路径:先懂RAG与Agent原理再动手做项目

1. 为什么我不建议你上来就做项目1.1 一个很常见的误区&#xff1a;把“做项目”当成学习路径这两年AI应用开发的热度不用我多说&#xff0c;RAG、Agent、LangChain、ReAct这些词几乎天天在技术社区刷屏。我身边不少做Java后端的、做前端的、甚至做测试的朋友&#xff0c;都动了…

📰

从零搭建神经网络开发环境:TensorFlow与Keras实战指南

1. 从零搭建神经网络开发环境&#xff1a;工具链选型与安装实操很多人学神经网络卡在第一步——环境装不上。不是缺这个库就是版本冲突&#xff0c;折腾两三天热情就磨没了。我带过不少新人&#xff0c;发现八成以上的环境问题都出在“版本不匹配”和“装错包”这两件事上。这一…

📰

三月CV顶会观察:多模态、3D重建与模式识别落地实操

1. 三月的学术界在忙什么1.1 大模型之外&#xff0c;CV圈的真实热点又到三月中旬&#xff0c;这大概是计算机视觉方向最热闹的一段时间。CVPR 的投稿周期刚过&#xff0c;NeurIPS 的摘要提交还没开始&#xff0c;大家手里攒着的实验数据刚好到了一个能拿出来晒的阶段&#xff0…

📰

嵌入式工程师的端侧AI重构:从CNN物理层开始

1. 这不是“重学CNN”&#xff0c;而是嵌入式工程师的端侧AI能力重构我拆过不下二十块工业级ARM Cortex-M7开发板&#xff0c;写过裸机驱动、移植过RT-Thread、在Zynq上跑过PL端加速的OpenCV流水线——但第一次把ResNet-18量化后部署到RK3399上跑通实时目标检测时&#xff0c;盯…

📰

传统PID、BP与RBF神经网络自适应PID对比:原理、实现与选型指南

1. 项目缘起与核心思路拆解1.1 为什么还要折腾PID做控制这行的&#xff0c;没人不知道PID。比例、积分、微分三个环节&#xff0c;结构简单、物理意义明确、调参经验成熟&#xff0c;工业现场里超过八成的回路还是PID在扛。但问题也恰恰出在这里——固定参数的PID&#xff0c;本…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬