Documentation Index
Fetch the complete documentation index at: https://docs.raydium.io/llms.txt
Use this file to discover all available pages before exploring further.
本页内容由 AI 自动翻译,所有内容以英文版本为准。查看英文版 →
本页整合了 CLMM 背后的推导过程。如需了解链上实现,请查看
products/clmm/math(引用本页)和 products/clmm/ticks-and-positions(说明跳价格子的设计)。为什么是 sqrt-price,而不是 price
Uniswap v3 系列的 CLMM 将价格表示为其平方根,以定点Q64.64 形式存储:
- 线性流动性数学。 价格范围内 token0 或 token1 的金额恰好是
sqrt_price的线性函数,而不是price的线性函数。存储sqrt_price让交换步骤可以直接计算这些线性公式,无需计算平方根。 - 溢出控制。
sqrt_price · L在所有合理参数下都适应u256;price · L可能更早溢出。 - 跳价格数学统一。 由于跳价格定义为
1.0001^i,所以sqrt(price) = 1.00005^i也是 1.00005 梯级的精确幂。每次跳价格穿越在sqrt_price_x64空间中转化为一个小的乘法。
price = (sqrt_price_x64 / 2^64)^2。
跳价格格子
价格被离散化到一个网格上:tick_i 是一个 i32。活跃范围是 [MIN_TICK, MAX_TICK] = [−443636, 443636],对应的价格范围约为 [2^−128, 2^128]。每个池的 tick_spacing 由其费用等级设定:紧密交易对使用较小间距(例如稳定币 0.01% 等级使用间距 1),波动性交易对使用较大间距(0.25% 等级使用 60,1% 等级使用 120)。
头寸必须使其 tick_lower 和 tick_upper 与 tick_spacing 对齐。池中的活跃跳价格(那些在该处开始或结束流动性的跳价格)是交换步骤关心的唯一跳价格。
流动性到金额的转换
对于流动性为L 且价格范围为 [sqrt_lo, sqrt_hi] 的头寸(均为 sqrt_price 值):
| 池状态 | token0 金额 | token1 金额 |
|---|---|---|
价格在范围上方(sqrt_p ≥ sqrt_hi) | 0 | L · (sqrt_hi − sqrt_lo) |
| 价格在范围内 | L · (sqrt_hi − sqrt_p) / (sqrt_p · sqrt_hi) | L · (sqrt_p − sqrt_lo) |
价格在范围下方(sqrt_p ≤ sqrt_lo) | L · (sqrt_hi − sqrt_lo) / (sqrt_lo · sqrt_hi) | 0 |
(x_v, y_v) 被选择使得池当前的 (sqrt_p, L) 符合 L = sqrt(x_v · y_v)。从 sqrt_p 积分到范围边界得出上述金额。
逆向公式(用于为给定的 amount0 或 amount1 创建头寸时):
单跳价格交换步骤
在单个跳价格范围内,池的行为类似 CPMM。给定当前sqrt_p 和目标 sqrt_target:
精确输入步骤
给定Δin_remaining:
0→1 交换会降低 sqrt_p(当我们出售 token0 时价格下跌)。1→0 交换会提高它。公式在 sqrt_p 和 sqrt_target 交换时是对称的。
精确输出步骤
结构相同,但求解Δin 而不是输出。
多跳价格交换循环
交换会遍历跳价格直到输入耗尽或达到价格限制:single_step 使用池的当前 L。L 仅在穿越初始化的跳价格时改变。跳价格间的流动性是恒定的,这正是单步数学具有闭式解的原因。
跳价格处的 liquidity_net 是在该跳价格处开始的头寸流动性的有符号总和减去在该处结束的头寸流动性。向上穿越会加上 liquidity_net;向下穿越会减去它。
当池在跳价格处有限价单打开时,穿越跳价格步骤也会机会性地消耗部分交换输入来填补这些订单(按队列在集群间)。匹配算法和可能在基本步骤之上应用的动态费用附加费在 products/clmm/math 中有文档说明;它们不改变上述闭式单步公式。
费用增长累加器
CLMM 按活跃流动性单位跟踪费用,每侧、全局和每跳价格:single_step 上:
fee_growth_global 在本步骤不移动,因为该侧没有 token 作为输入支付。)
穿越跳价格时,程序会翻转 fee_growth_outside:
tick_current 而言的。当 tick_current 在跳价格上方时,外侧意味着”下方”。当 tick_current 在下方时,外侧意味着”上方”。翻转会交换这种解释。
头寸的 fee_growth_inside
给定一个头寸 [tick_lower, tick_upper] 和当前 tick_current:
s 的未收取费用为:
IncreaseLiquidity、DecreaseLiquidity、CollectFees)。
工作示例——穿越一个跳价格
池(简化):sqrt_p_x64 = 2^64 · 1.0 = 2^64(价格 = 1.0)L = 1_000_000tick_current = 0- 下方的下一个初始化跳价格:
tick = −60,sqrt_price = 1.0001^(−30) ≈ 0.99700,liquidity_net = −400_000(此跳价格结束一个头寸,向下穿越移除 400k) - 费率:0.25%
Δin = 10_000 token0,方向 = 0→1。
步骤 1——至 sqrt_target = 0.99700 · 2^64:
L = 600_000:
下一个初始化跳价格(比如 tick = −120)位于 sqrt = 0.99402。重新计算 amount_in_to_target:
Δin_remaining。再次穿越。继续直到 Δin_remaining 变为零。
完整的 Δout 序列累积到最终交换输出。
初始化和溢出保护
MIN_SQRT_PRICE_X64和MAX_SQRT_PRICE_X64对应tick = ±443636。任何会将sqrt_p推出此范围的交换都会失败。- 用户的
sqrt_price_limit参数必须在同一区间内;程序会检查。 L · Δsqrt的乘积在u256中计算,然后移位回u128以避免溢出。
与 Uniswap v3 的差异
- 预言机。 Raydium 的
ObservationState存储(block_timestamp, tick_cumulative, seconds_per_liquidity_cumulative)环形缓冲;与 Uniswap 的格式略有不同,但 TWAP 数学相同。 - Token-2022。 Raydium CLMM 支持 Token-2022 mints;转账费变体需要额外的交换前后金额调整。见
algorithms/token-2022-transfer-fees。 - 跳价格位图。 Raydium 将初始化跳价格位图打包成每个池的
[u64; 16]以加快find_next_initialized_tick;Uniswap 使用每字的链上映射。权衡是租金与查找成本。 - 奖励槽。 Raydium 支持 3 个每池奖励流,每个流有单独的
reward_growth_global_x64计数器;与费用增长累加器结构相同。
指针
products/clmm/math——链上实现和使用实际 CLMM 结构字段的工作示例。products/clmm/ticks-and-positions——跳价格格子、liquidity_net/gross、活跃范围语义。products/clmm/fees——费用增长累加器的实际应用。
- Uniswap v3 白皮书(sqrt-price 数学的规范推导)。
- Raydium CLMM 程序源代码。


