Skip to main content
本頁內容由 AI 自動翻譯,所有內容以英文版本為準。查看英文版 →

為什麼是 sqrt 價格,而不是價格

Uniswap v3 系列 CLMM 將價格表示為其平方根,存儲在定點 Q64.64 格式中:
有三個理由:
  1. 線性流動性數學。 價格範圍內的 token0 或 token1 數量實際上是 sqrt_price 的線性函數,而不是 price 的函數。存儲 sqrt_price 可以讓交換步驟計算這些線性公式時無需計算平方根。
  2. 溢出控制。 sqrt_price · L 在所有合理的參數下都能放入 u256price · L 可能會更早溢出。
  3. 跳點數學均勻。 由於跳點定義為 1.0001^isqrt(price) = 1.00005^i 也是 1.00005 梯級的精確冪。每次跳點穿越轉換為 sqrt_price_x64 空間中的小乘法。
價格和 sqrt 價格是一一對應的;轉換公式是 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_lowertick_upper 對齐到 tick_spacing。池的活躍跳點(那些在其處有流動性開始或結束的跳點)是交換步驟唯一關心的跳點。

流動性轉金額

對於流動性為 L 和價格範圍 [sqrt_lo, sqrt_hi] 的頭寸(所有 sqrt_price 值): 推導:對 CPMM 不變量在局部進行微分。在任何單個跳點範圍內,頭寸的行為類似於 CPMM,虛擬儲備為 (x_v, y_v),選擇使得池的當前 (sqrt_p, L)L = sqrt(x_v · y_v) 一致。從 sqrt_p 積分到範圍邊界得到上面的金額。 逆向公式(用於為給定的 amount0amount1 鑄造頭寸時):

單跳交換步驟

在單個跳點範圍內,池的行為類似於 CPMM。給定當前 sqrt_p 和目標 sqrt_target

精確輸入步驟

給定 Δin_remaining
0→1 交換降低 sqrt_p(當我們賣出 token0 時價格下降)。1→0 交換提高它。公式在 sqrt_psqrt_target 互換時是對稱的。

精確輸出步驟

相同結構,但改為求解 Δin

多跳交換循環

交換遍歷跳點直到輸入耗盡或價格限制被觸及:
每個 single_step 使用池的當前 LL 只在穿越初始化跳點時改變。跳點之間的流動性是常數,這正是使步驟數學為封閉形式的原因。 跳點處的 liquidity_net 是在該跳點開始的頭寸流動性減去在該跳點結束的頭寸流動性的有符號和。向上穿越添加 liquidity_net;向下穿越減去它。 當池在跳點處有限價訂單打開時,穿越跳點步驟也會機會性地消耗部分交換輸入來填充這些訂單(按群組跨越 FIFO)。匹配算法和可能在基本步驟之上應用的動態費用附加費在 products/clmm/math 中記錄;它們不改變上面的封閉形式單步公式。

費用增長累加器

CLMM 跟蹤每單位活躍流動性的費用,按側,全局和每跳點:
在每個 single_step 上:
(另一側的 fee_growth_global 在此步驟上不移動,因為該側沒有代幣作為輸入支付。) 穿越跳點時,程序翻轉 fee_growth_outside
「Outside」相對於 tick_current。當 tick_current 在跳點上方時,outside 表示「下方」。當 tick_current 在下方時,outside 表示「上方」。翻轉交換了解釋。

頭寸的 fee_growth_inside

給定頭寸 [tick_lower, tick_upper] 和當前 tick_current
頭寸對於代幣側 s 的未收集費用為:
此更新在與頭寸的每次交互時運行(IncreaseLiquidityDecreaseLiquidityCollectFees)。

實例演練 — 穿越一個跳點

池(簡化):
  • sqrt_p_x64 = 2^64 · 1.0 = 2^64(價格 = 1.0)
  • L = 1_000_000
  • tick_current = 0
  • 下方下一個初始化跳點:tick = −60sqrt_price = 1.0001^(−30) ≈ 0.99700liquidity_net = −400_000(此跳點結束一個頭寸,所以向下穿越移除 400k)
  • 費用率:0.25%
交換:Δin = 10_000 token0,方向 = 0→1。 步驟 1 — 直到 sqrt_target = 0.99700 · 2^64
3,009 < 10,000,所以我們完全填充此步驟:
步驟 2 — 使用新的 L = 600_000 下一個初始化跳點(例如 tick = −120)位於 sqrt = 0.99402。重新計算 amount_in_to_target
仍然少於 Δin_remaining。再次穿越。繼續直到 Δin_remaining 達到零。 Δout 的完整序列累積到最終交換輸出。

初始化和溢出防護

  • MIN_SQRT_PRICE_X64MAX_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 鑄幣;轉移費用變體需要額外的交換前/後金額調整。見 algorithms/token-2022-transfer-fees
  • 跳點位圖。 Raydium 將初始化跳點位圖打包到每個池的 [u64; 16] 中以快速 find_next_initialized_tick;Uniswap 使用每字映射。權衡是租金 vs 查找成本。
  • 獎勵槽。 Raydium 支持每個池 3 個獎勵流,有單獨的 reward_growth_global_x64 計數器;與費用增長累加器的結構相同。

指針

資料來源:
  • Uniswap v3 白皮書(sqrt 價格數學的規範推導)。
  • Raydium CLMM 程式源代碼。