このページは AI による自動翻訳です。すべての内容は英語版を正とします。英語版を表示 →
L = sqrt(x · y) が重要なのか)については、algorithms/clmm-math を参照してください。このページは、そちらを読んでいることを前提としています。
Sqrt-price 表現
CLMM は価格をsqrt_price_x64 として保存します。これは token1-per-token0 価格の平方根を Q64.64 固定小数点数で表したものです:
ここで p = token1_amount / token0_amount です。p の代わりに sqrt で計算することで、スワップ数学が線形化されます(トークン量のデルタが Δsqrt_price に対して線形になります)。また x64 固定小数点により、多くのティックにわたるスワップでも精度が保たれます。
ティック ↔ sqrt-price 変換は bit-by-bit ログ近似を使用して事前計算されます:
これは tick_math::get_sqrt_price_at_tick でルックアップベースの指数計算として実装されています。
リクイディティを正規単位として
範囲[sqrt_a, sqrt_b](sqrt_a < sqrt_b)内のポジションで、リクイディティ L はトークン量に次のようにマップされます。sqrt_c = sqrt_price_x64 をプールの現在の価格とします。
3 つの恒等式すべては、集中流動性が範囲内で満たす不変式
x = L / sqrt_p、y = L · sqrt_p から導出されます。
インテグレーターは通常、逆を求めます。amount0 / amount1 のデポジットが与えられたとき、範囲に収まる最大の L を計算します。SDK の LiquidityMath.getLiquidityFromTokenAmounts がこれを行います。範囲内ケースの公式は:
どちらかが制約になるかで、実際に消費される比率が決まります。もう一方は余剰が残る可能性があります。
単一ティック スワップ ステップ
スワップは ステップ で進行します。各ステップは (a) 現在のティック範囲内で利用可能なすべての入力を消費してティックを越えないか、(b) 価格を次の初期化されたティックに正確に移動させます。 現在の状態(sqrt_c, L) と 下向き スワップ(token0 入力、token1 出力、sqrt_price 減少 — 価格は token1/token0 として引用されるため、token0 を追加すると価格が低下します)が与えられたとき、次の初期化されたティックは sqrt_t < sqrt_c に位置します。このマイクロ区間内で、入力と価格の関係は:
および
token1 入力スワップはミラーイメージです。sqrt_price は次のティック上に向かって上昇し、2 つの公式はどちらのエンドポイントが減算されるかが入れ替わります。プログラムは方向を zero_for_one(入力ミントが token_mint_0 の場合は true)としてエンコードし、zero_for_one スワップは MIN_SQRT_PRICE_X64 に向かってクランプされます。
プログラムは次の 2 つのいずれかを実行します:
-
入力全体が収まるか? フィー後の残りの入力が
sqrt_tに到達するためのΔamount0より少ない場合、新しいsqrt_c'を正確に解きます: (正確入力token0 → token1スワップの場合)。スワップはこのステップで完了し、ティックを越えません。 -
入力が
Δamount0を超えるか?sqrt_c' = sqrt_tを設定し、ティックを越えて(liquidity_netを適用)、残りの入力をΔamount0だけ減らし、出力をΔamount1だけ増やし、繰り返します。
token1 → token0、価格が下がる)の場合、公式は sqrt_c と sqrt_t が入れ替わり、反転が別のスロットにあります。
完全な Rust 実装は raydium-clmm/programs/amm/src/libraries/swap_math.rs にあります。そこのロジックは Uniswap v3 の SwapMath.computeSwapStep と 1 対 1 で一致します。
各ステップのフィー
トレードフィーは各ステップの 入力 量から取られます。CPMM と同じ規約です:L_i のポジションは、後で L_i · Δfee_growth_global / 2^{64} の支払いトークンを読み取ります。
プロトコルとファンド ポーションは、それぞれ PoolState.protocol_fees_token_{0,1} と PoolState.fund_fees_token_{0,1} に発生します。これは CPMM と同じです。これらは CollectProtocolFee / CollectFundFee によってスイープされます。
外部および内部のフィー成長
CLMM フィー会計の難しい部分:ポジションは、プールの価格がその範囲 内 にある間だけフィーを獲得します。プールはグローバルに累積フィーを追跡します。ポジションは、その特定の範囲 内 の累積フィーを知る必要があります。 解決策は ティックベース のアキュムレーターです。各ティックは以下を保存します:- プールの価格がこのティック 上 にある場合(
tick_current >= this_tick)、fee_growth_outside = fee_growth_global。(これまでに獲得したすべてが「外部」、つまり、現在の価格に対してこのティック下にあります。) - そうでない場合、
fee_growth_outside = 0。
fee_growth_outside を 反転 します:
これが保持する不変式:任意のティック t に対して、fee_growth_outside(t) は tick_current が t の反対側にあった間に発生したフィーに等しい。
範囲 [tick_lower, tick_upper] 内のフィー成長 は次のように導出されます:
ポジションが保存するもの、読み取るもの
PersonalPositionState は fee_growth_inside_0_last_x64 と fee_growth_inside_1_last_x64 を保存します。これらはポジションが最後にタッチされたときの fee_growth_inside 値です。
その後のタッチ(増加、減少、収集)では、プログラムは:
- 上記の公式を使用して現在の
fee_growth_inside_{0,1}_x64を計算します。 Δ = fee_growth_inside_now − fee_growth_inside_last(u128 上のモジュラー減算)を計算します。Δ × position.liquidity / 2^{64}をtokens_fees_owed_{0,1}に追加します。fee_growth_inside_lastを新しい値に更新します。
CollectFees / DecreaseLiquidity でのみ、tokens_fees_owed に対してボールトから移動します。
リワード
プールの最大 3 つのリワード ストリームは、それぞれ独自のreward_growth_global_x64 アキュムレーターで同じ成長内部メカニズムを使用します。エミッション時:
— エミッションはアクティブ リクイディティに反比例してスケーリングされるため、より密度の高いプールは各ポジションに 1 秒あたり比例して少なく支払いますが、合計でより多くのポジションに支払います。ポジションあたりのリワード支払いは
で、DecreaseLiquidity / DecreaseLiquidityV2 によって支払われます。スタンドアロンの収集リワード命令はありません。products/clmm/fees を参照してください。
実例:正確入力スワップ
次を想定します:tick_spacing = 60sqrt_price_x64 = 1 × 2^{64}— 価格 = 1.0、したがってtick_current = 0。- アクティブ リクイディティ
L = 1_000_000 × 2^{64}。 - 次の初期化されたティック下:
t = −60(sqrt_price_b ≈0.997005 × 2^{64})。token0 入力スワップは 下 に移動するため、上のティックはここでは関係ありません。 - トレード フィー レート:500(0.05%)。
SwapBaseInput 正確入力 1,000 token0。
ステップ 1 — フィー:
999 < 3004.4 なので、入力全体はティックを越えずに収まります。
ステップ 3 — 新しい価格:
sqrt_c' は sqrt_c より わずかに下 に着地します。これは正しい方向です。token0 → token1 スワップはプールに token0 を追加するため、token1/token0 価格を低下させます。
ステップ 4 — 出力量:
trade_fee_rate × protocol_fee_rate / 1e6(ファンドも同様)によって LP、プロトコル、ファンド間で分割されます。LP ポーションは fee_growth_global_0_x64 に流れます。
スワップ中のリミットオーダー マッチング
スワップ ステップがオープン リミットオーダーを保持するティックを越えるとき、これらのオーダーはティックの正確な価格で LP 曲線 前に スワップ入力を消費します。マッチングはorder_phase コホート内でティック内で FIFO です。
TickState のコホートごとの状態
orders_amount に参加し、次の order_phase を継承します。前のコホートが完全に消費されるまで埋めることはできません。
マッチング ステップ
スワップ中の各ティック交差で発生するマッチングの疑似コード:unfilled_ratio_x64 を介してコホートがどの程度埋められたかを追跡します。各 LimitOrderState はオープン時に独自の (order_phase, unfilled_ratio_x64) スナップショットを保存するため、決済は以下に帰着します:
LP 曲線との相互作用
スワップ ステップでは、リミットオーダー マッチングはティック で 発生します(ゼロΔsqrt_price)。LP 曲線消費はティック 間 で発生します。したがって順序は:
- ティック
t_crossを越えます(LPliquidity_net変更を最初に適用します。これは Uniswap-V3 がどのように行うかです)。 t_crossに座っているリミットオーダーを埋めます。- LP 曲線に沿って次の初期化されたティックまたは
swap_input枯渇まで続行します。
動的フィー導出
PoolState.dynamic_fee_info はボラティリティ状態を保持します。各スワップ ステップは、ステップごとのフィー レートを次のように計算します:
ここで:
- —
DYNAMIC_FEE_CONTROL_DENOMINATOR - —
VOLATILITY_ACCUMULATOR_SCALE vol_accは以下の更新ルール後のスワップごとのアキュムレーターtick_spacingはPoolState.tick_spacingから
アキュムレーター更新
2 つのルールが各スワップで順番に適用されます: 減衰。 参照フロアは最後の更新からの経過時間に基づいて減衰します: 蓄積。 新しいアキュムレーターは参照プラス前の参照インデックス以降に走査されたティック距離です:tick_spacing_index_reference()はティック間隔単位です。生のティックではありません:。
ティック距離で放物線である理由
アキュムレーターを二乗することは、フィーが価格が参照ポイントから歩いた距離の 二乗 として上昇することを意味します。経験的には、これはランダムウォーク圧力下での価格の分散スケーリングと一致します。2 倍のティック偏差は 4 倍の暗黙のボラティリティを意味するため、4 倍のサーチャージを請求します。dynamic_fee_control パラメーターは絶対レベルを調整します。
filter_period ウィンドウは、小さなサブ秒振動(例:MEV ボットのサンドイッチング)がアキュムレーターを膨らませるのを防ぎます。decay_period ウィンドウは、単一の過去のスパイクが市場が落ち着いた後も無期限にフィーを請求するのを防ぎます。
数値堅牢性
- すべての中間積は
u128またはu256形状の算術を通過します。CLMM はU128SqrtヘルパーとFullMath::mulDivパターンを Uniswap v3 から直接移植して使用します。 - 除算丸めは、不変式
k' ≥ kをローカルに強制するためにステップごとに選択されます。SwapBaseInputは出力を 下 に丸めます。SwapBaseOutputは入力を 上 に丸めます。 PoolState.liquidityをゼロにドロップするティック交差は許可されます(価格は「リクイディティ ホール」を走査できます)。ただし、スワップは単に次の初期化されたティックに進み、入力を消費せず、フィーを請求しません。- オーバーフロー ガード:
sqrt_price_x64は[MIN_SQRT_PRICE_X64, MAX_SQRT_PRICE_X64]の包括的範囲内に保たれます。これは[MIN_TICK, MAX_TICK]に対応します。どちらかの境界を越えるスワップはSqrtPriceLimitOverflowで戻ります。
次に進む場所
products/clmm/ticks-and-positionsティック マップがウォークにどのように参加するか。products/clmm/feesフィー/リワード側の数学の詳細。algorithms/clmm-mathL = sqrt(x · y)と範囲対リクイディティ公式の背後にある導出。
raydium-io/raydium-clmm—libraries/swap_math.rs,libraries/tick_math.rs- “Uniswap v3 Core” ホワイトペーパー、§6–7

