メインコンテンツへスキップ

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のリクイディティは価格範囲に集中しています。範囲をオンチェーンで扱いやすくするために、価格は整数ティックに量子化されます。各ティックは前のティックの定数倍です: price(i)=1.0001i\text{price}(i) = 1.0001^{\,i} 1つのティックは0.01%の価格変動、つまり約1ベーシスポイントに対応しています。マッピングは以下の通りです:
ティック指数 i価格倍率
01.0000
1001.0100 (≈ +1.00%)
-1000.9900 (≈ −0.99%)
100002.7181 (≈ e)
MAX_TICK = 4436361.84e19
MIN_TICK = -4436365.42e-20
MIN_TICKMAX_TICKは、sqrt_price_x64が両端でu128に収まるように選択されています。すべてのプールはtick_lower >= MIN_TICKtick_upper <= MAX_TICKを強制しています。実際には、ウェブUIはユーザーがリクイディティを到達不可能なティックにロックするのを防ぐために、範囲をより狭いものにクランプします。

ティック間隔

プールのAmmConfigティック間隔を固定します。これはポジションがエンドポイントとして使用できる唯一のティックです。tick_spacing = 60の場合、…, −120, −60, 0, 60, 120, …のティックのみが有効です。エンドポイント31を持つポジションを開く試みは、InvalidTickIndexでリバートします。 一般的に公開されている間隔:
フィアティアtrade_fee_rateティック間隔ティックポジションごとの最粗の価格ステップ
0.01%10010.01%
0.05%500100.10%
0.25%2500600.60%
1.00%100001201.21%
間隔が粗いほど、初期化するティック配列が少なくなり、広いポジションを開くコストが安くなり、価格境界がぼやけます。ボラティリティの高いペアは通常120間隔のティアに存在し、安定資産は1間隔のティアに存在します。

ティック配列

プールはティックごとのステートを別個のアカウントに保存しません。代わりに、隣接したTICK_ARRAY_SIZE個のティック(現在のRaydium CLMMでは60)が単一のTickArrayStateにパッキングされます。配列の最初のティックはstart_tick_indexであり、ちょうどTICK_ARRAY_SIZE * tick_spacing個の整数ティック単位をカバーしています。 tick_spacing = 60TICK_ARRAY_SIZE = 60の場合:
  • 各ティック配列は60 × 60 = 3600個の整数ティックをスパンします。
  • start_tick_indexは3600の倍数です:…, -7200, -3600, 0, 3600, 7200, …
tick_spacing = 60のときのポジションエンドポイントt = 2040は、start_tick_index = 0のティック配列に存在します。ポジションエンドポイントt = 4200は、start_tick_index = 3600の配列に存在します。

配列が作成される時期

ティック配列は遅延的です。その中のティックを参照する最初のポジションが配列を初期化し、レントを支払います。スワップはティック配列を初期化しません。ビットマップを使用して未初期化配列をスキップします。SDKのオープンポジションフローは、選択された範囲を検査し、それが触れるティック配列のリストを計算し、欠落している場合はOpenPositionと同じトランザクション内にinit_tick_array命令を追加します。

ティック配列は閉じられない

ティック配列が初期化されると、プールの有効期間中存続します。プログラムは、initialized_tick_countがゼロに戻った後でも、ティック配列を閉じるパスを公開しません。ティック配列のレント回復はありません。配列に触れる最初のポジションが支払ったレントはそのアカウントに永久的にロックされます。これは意図的なトレードオフです。既存のティック配列を再利用することは、その後のすべてのポジションについて無料なので、ヘビーに取引されるプールは、チャーン に関係なく、(pool, start_tick_index)スロットごとに1回だけレントコストを支払います。

ビットマップ

「現在のティックの左/右の次に初期化されたティックを見つける」ことは高速である必要があります。スワップは多くのティックを越える可能性があります。プールは、ティック0の周囲±1,024配列の範囲に対して、1ティック配列あたり1ビットのビットマップをPoolState内にインラインで保存します。その範囲外(フルレンジポジション、異国風設定)では、TickArrayBitmapExtensionがオーバーフロー提供します。 スワップはビットマップを歩みます。lowest_set_bit_above(tick_current_array_index)は、スワップがクロスしている側の次の初期化ティックを持つ配列を提供します。その配列内では、同様のビットスキャンが次に初期化されたティックを見つけます。

liquidity_grossliquidity_net

すべての初期化されたティックは2つのリクイディティ値を保存します:
  • liquidity_gross — このティックをエンドポイントとして参照するすべてのポジション上のLの合計。liquidity_grossがゼロに達すると、ティックは未初期化になり、ビットマップから削除できます。
  • liquidity_net — 価格がこのティック上向き(ティック空間で左から右)をクロスするときのプール レベルliquidityへの符号付き変更。このティックがサイズLのポジションの下限である場合、+Lに寄与します。そのポジションの上限である場合、−Lに寄与します。
動作例:同じプール上の2つのポジション。
  • ポジションA:tick_lower = -120tick_upper = 0、リクイディティL_A = 100
  • ポジションB:tick_lower = -60tick_upper = 60、リクイディティL_B = 50
ティックごとのステート:
ティックタッチ対象liquidity_grossliquidity_net
-120A下限100+100
-60B下限50+50
0A上限100−100
60B上限50−50
異なるtick_current値に対するプール レベルliquidity
  • tick_current = -180liquidity = 0(ポジション前)
  • tick_current = -90liquidity = 100(Aのみ内)
  • tick_current = -30liquidity = 150(AとB内)
  • tick_current = 30liquidity = 50(Bのみ内)
  • tick_current = 90liquidity = 0(両者を超過)
スワップ中のティッククロス毎に、プログラムはliquidity_net(負の可能性あり)をPoolState.liquidityに追加します。これはUniswap-v3の正確なメカニズムです。

NFTとしてのポジション

RaydiumのCLMMポジションはNFTです。ポジションを開くことで、供給1の真新しいミントをコーラーのウォレットにミントし、そのミントの権限はCLMMプログラムです。プログラムはポジション所有権を、CPI時点でそのミントのATAに残高を保有している誰でもにキー付けします。 結果:
  • ポジションは転送可能です。 ウォレットはNFTを転送することでポジションを販売またはエアドロップできます。新しい保有者はCollectRewardsIncreaseLiquidityなどを呼び出すことができます。
  • ポジションはCLMM外でアドレス指定可能です。 マーケットプレイスとウォレットは他のNFTのようなポジションを表示します。SDKはミントメタデータに合理的なname/symbolを設定します。
  • ポジションのPDAはNFTミントから導出されます。 現在それを保有しているかを知らなくてもPersonalPositionStateを見つけることができます。

Token-2022ポジション

より新しいCLMMプールはクラシックSPL Tokenの代わりにToken-2022の下でポジションをミントできます。プログラムは2つの並列オープン命令 — OpenPositionOpenPositionWithToken22Nft — を公開します。これらの命令は、どのトークンプログラムがNFTミントを所有するかを除いて、同じセマンティクスを持ちます。ウォレットとマーケットプレイスの互換性は異なります。RaydiumのUIは両方を追跡します。

許可された範囲ルール

OpenPosition時点で、プログラムは以下を強制します:
  1. tick_lower < tick_upper
  2. tick_lower % tick_spacing == 0tick_upper % tick_spacing == 0
  3. MIN_TICK <= tick_lowertick_upper <= MAX_TICK
  4. コーラーはtick_lowertick_upperを含むティック配列を提供しています — 既に初期化済みか、同じトランザクション内のinit_tick_array経由。
  5. このポジションが拡張範囲に拡張する場合、ビットマップ拡張アカウント。
いずれかのチェックが失敗した場合、命令は制約に応じてInvalidTickIndexNotApproved、またはInsufficientLiquidityでリバートします。reference/error-codesを参照してください。

「イン・レンジ」対「アウト・オブ・レンジ」

ポジションはtick_lower <= tick_current < tick_upperのときにイン・レンジです。イン・レンジポジションのみがPoolState.liquidityに寄与するため、スワップフィーを獲得するのはこれらのみです。 アウト・オブ・レンジポジション:
  • 1つのトークン(範囲が過ぎ去ったトークン)の100%を保有します。具体的には、tick_current < tick_lowerの場合、ポジションはtoken1のみを保有します(価格が離れることで既に「売却」されています)。tick_current >= tick_upperの場合、token0のみを保有します。
  • スワップフィーを獲得しません。
  • プールのリワード ストリームがアウト・オブ・レンジリクイディティに放出する場合、リワードの蓄積を継続します — しかし、RaydiumのデフォルトBehaviorは「イン・レンジのみに放出」で、Uniswap v3の慣習に合わせています。products/clmm/feesを参照してください。
CLMMポジションを管理するLPは、価格が動くときにポジションをイン・レンジのままに保つことに多くの注意を費やしています。

一般的な統合の落とし穴

  • オフスペーシング エンドポイント。 ターゲット価格からティックを計算するコードは、OpenPositionに渡す前にtick_spacingの倍数にスナップする必要があります。SDKヘルパー(TickUtils.getTickWithPriceAndTickspacing)はこれを行います。自作の数学ではしばしば行われません。
  • 欠落しているティック配列。 広いポジションを開くと、複数のティック配列を初期化する必要がある場合があります。書き込み可能アカウントとして渡すのを忘れると、リバートします。SDKのopenPositionFromBaseはリストを返します。
  • スワップ後の古いティック。 tick_currentは1つのスワップで多くのティックをクロスできます。1つのRPC呼び出しから「現在のティック」をUXで表示し、その後の別のティックでポジションを開く場合、ライブ価格に対する相対的なポジションは数十のティックずれる可能性があります。署名する直前に再取得します。
  • 追加メタデータを持つポジションNFT。 RaydiumポジションをHTMLするウォレットを構築する場合、ハードコードされたメタデータフィールドではなく、ミント権限(= CLMMプログラムのPDA)で検出します。

次に進む場所

  • Math — スワップステップスルーとティック境界が参加するフィー成長導出。
  • AccountsTickArrayStatePositionStateレイアウト。
  • フィーとリワード — イン・レンジネスがフィー蓄積をゲートする方法。
  • algorithms/clmm-math — 集中リクイディティ公式の共有導出。
ソース: