メインコンテンツへスキップ
このページは AI による自動翻訳です。すべての内容は英語版を正とします。英語版を表示 →
このページでは各アカウントのレイアウトと役割を説明します。シード値は正規のものであり、reference/program-addresses に一覧があります。CLMMプールはCPMMプールよりもアカウント数が多くなります。これはリクイディティがティック範囲にわたってスパースに格納されるためであり、そのスパース性の理解がこのページの中心的な内容です。

アカウント一覧

稼働中のCLMMプールは以下のアカウントファミリーで構成されます。2つのミントとそのボルトを除き、すべてCLMMプログラムが所有します。

PoolState

プールのライブ状態。スワップのたびにすべてのポジション変更のたびに参照されます。
実際に参照するフィールド:
  • sqrt_price_x64tick_current はプールの価格状態です。スワップのたびに同時に更新されます。tick_currentlog_{1.0001}(price) の切り捨て値です。
  • liquidityアクティブなリクイディティ、つまり tick_current を含む範囲のすべてのポジションの L 値の合計です。スワップがティックを跨ぐたびに、またポジションが開かれ・閉じられ・サイズ変更されるたびに変化します。
  • fee_growth_global_{0,1}_x64 は、プール全体の履歴にわたってリクイディティ単位あたりに累積された手数料です。ポジションはこれを参照して自分の取り分を計算します。
  • tick_spacing は初期化時に AmmConfig から固定され、変更されません。どのティックインデックスがポジションのエンドポイントとして許可されるかを決定します。
  • tick_array_bitmap はスポット価格周辺のよく使われるティック範囲をカバーするインラインビットマップです。ポジションが遠くまで届くプールでは、オーバーフロー追跡は別の TickArrayBitmapExtension アカウントに格納されます。
  • fee_on はプール作成時に固定されます。0(FromInput)はクラシックな Uniswap-V3 の動作を再現します。12 はスワップ手数料を板の片側にルーティングします。トレードオフについては products/clmm/fees を参照してください。
  • dynamic_fee_info は動的手数料サーチャージのボラティリティ状態を保持します。有効化されている場合、スワップのたびに AmmConfig.trade_fee_rate に加えて dynamic_fee_component が再計算されます。レイアウトは以下の DynamicFeeInfo に記載しています。動的手数料を使用しないプールではこの構造体全体がゼロになります。

AmmConfig

公開されている典型的な CLMM 手数料ティアのセット(GET https://api-v3.raydium.io/main/clmm-config で最新情報を確認してください): protocol_fee_ratefund_fee_rate は取引手数料に対する割合で、CPMM と同じ規則です。詳細は products/clmm/fees を参照してください。

TickArrayState

CLMMはティックごとに 1 つのレコードを格納しません。そうすると数十億のアカウントが必要になります。代わりに、TICK_ARRAY_SIZE 個の隣接する初期化済み・未初期化のティック(プログラムバージョンによって通常 60 または 88)を 1 つの TickArrayState にグループ化し、初めて使用されるときに遅延生成します。
指値注文関連の 4 つのフィールドは、一度も指値注文に使われていないティックではすべてゼロです。ティックに注文が開かれると、プログラムはそれをコホートの連続として追跡します。
  • order_phase はコホート ID です。コホートが「すべて未約定」から「一部約定済み」に遷移するたびにインクリメントされます。
  • orders_amount は現在(最新)のコホートの入力トークン合計です。
  • part_filled_orders_remaining は進行中のスワップによって約定されつつある直前のコホートを追跡します。
  • unfilled_ratio_x64 はコホートに対して保持される Q64.64 の乗数です。スワップがコホートの X% を約定すると、この比率は (1 − X) で乗算されます。各未決注文は開設時に独自の (order_phase, unfilled_ratio_x64) スナップショットを保存するため、決済の計算はスナップショット同士の比較に帰着します。
ルール:
  • ポジションのエンドポイントティック tt % tick_spacing == 0 を満たす必要があります。間隔外のポジションはプログラムに拒否されます。
  • ティックの配列の位置は floor(t / (TICK_ARRAY_SIZE * tick_spacing)) * (TICK_ARRAY_SIZE * tick_spacing) で求まります。
  • ティック配列は遅延初期化されます。未初期化の配列に最初に触れるポジションまたはスワップが、レントを支払って配列を作成します。
  • ティック配列はプログラムによってクローズされることはありません。一度割り当てられると、内部のすべてのティックが liquidity_gross == 0 に戻った後もプールの存続期間中は維持されます。後続のポジションやスワップは既存のアカウントを追加レントなしで再利用できます。ティック配列のクリーンアップを行う ClosePosition 主導のパスは存在しません。

TickArrayBitmapExtension

PoolState.tick_array_bitmap(インライン)は「スポット付近」の範囲(±1,024 ティック配列)をカバーします。その範囲外(極端なティック値)に対して、プログラムは拡張アカウントを管理します。
ポジションの範囲が「通常」であれば、拡張アカウントを意識する必要はありません。フルレンジポジション(例:(MIN_TICK, MAX_TICK))には必要ですが、SDK が自動的に解決します。

ポジション

CLMMのポジションは、ミントを含む3 つのアカウントのバンドルです。

ポジション NFT ミント

供給量 1 の SPL Token ミント。ミントのアドレスは決定論的な PDA であり、オーナーのウォレット内のポジション NFT はその単一トークンを保持する ATA に過ぎません。NFT を転送することでポジションが移転します。プログラムは、状態に格納された Pubkey ではなく、NFT の ATA 残高の現在の保有者に対してオーソリゼーションを紐付けます。

PersonalPositionState

未決ポジション 1 つにつき 1 つ。NFT ミントをキーとします。

ProtocolPositionState(非推奨)

古い CLMM リリースでは、(pool, tick_lower, tick_upper) ごとの集計ブックキーピングを ProtocolPositionState PDA に格納していました。新しいリリースではこのアカウントを作成も参照もしません。 OpenPosition / IncreaseLiquidity / DecreaseLiquidity のアカウントリストには ABI 互換性のために UncheckedAccount として残っていますが、プログラムは書き込みを行いません。オンチェーンに残っている既存のアカウントは残骸です。管理者は CloseProtocolPosition を呼び出してレントを回収できます。範囲集計のブックキーピングは現在、TickArrayState 内の 2 つのエンドポイントティック(liquidity_grossliquidity_net、ティックごとの fee_growth_outside_* / reward_growths_outside_x64)から直接導出されます。手数料グロースインサイドの計算式 fee_growth_inside = global − outside_lower − outside_upper は集計ポジションアカウントなしでも正しく機能します。

オブザベーション

CLMM のオブザベーションバッファは累積価格ではなく累積ティックを格納します。外部の利用者は (tick_cumulative[t1] − tick_cumulative[t0]) / (t1 − t0) から区間の幾何平均価格を計算し、price = 1.0001 ** tick で価格を求めます。詳細は algorithms/clmm-math を参照してください。

DynamicFeeConfigDynamicFeeInfo

動的手数料パラメータは 2 箇所に存在します。再利用可能なテンプレートである DynamicFeeConfig は管理者が管理し、オプトインしたプール間で共有されます。プールごとのランタイム状態である DynamicFeeInfoPoolState に埋め込まれ、スワップのたびに更新されます。

DynamicFeeConfig

PDA シード:["dynamic_fee_config", index.to_be_bytes()]create_dynamic_fee_config(管理者のみ)で作成し、update_dynamic_fee_config で変更します。enable_dynamic_fee = true で作成されたプールは、作成時にコンフィグの 5 つのキャリブレーションパラメータ(filter_perioddecay_periodreduction_factordynamic_fee_controlmax_volatility_accumulator)を自身の DynamicFeeInfo にスナップショットとして保存します。その後の DynamicFeeConfig への変更は既存のプールに遡及して影響しません。

DynamicFeeInfoPoolState に埋め込み)

下部 4 フィールドが状態、上部 5 フィールドが DynamicFeeConfig からコピーされたキャリブレーション値です。手数料の計算とデケイルールは products/clmm/math および products/clmm/fees に記載されています。 計算式で使用される定数:

LimitOrderState

未決の指値注文 1 つにつき 1 アカウント。
ライフサイクル:
  1. オープン — ユーザーが open_limit_order を呼び出し、入力トークンの total_amount を預け入れます。注文は TickState のコホートに紐付けられます。
  2. (任意)増減increase_limit_ordertotal_amount を追加し、decrease_limit_order は未約定トークン(およびその時点までの決済済み出力)を返還します。
  3. 決済 — コホートが全部または一部約定された場合、オーナーまたは運用キーパーが settle_limit_order を呼び出してオーナーの ATA に出力トークンを送付します。
  4. クローズunfilled_amount == 0 になった後、アカウントをクローズできます。レントは常に owner に返還されます。
PDA シード:[owner.as_ref(), limit_order_nonce.key().as_ref(), limit_order_nonce.order_nonce.to_be_bytes().as_ref()]。注文 PDA は (owner, nonce_index, order_nonce) ごとに一意です。

LimitOrderNonce

(wallet, nonce_index) ごとのカウンター。1 人のユーザーが PDA の衝突なしに複数の指値注文パイプラインを並行して実行できるようにします。
PDA シード:[user_wallet.as_ref(), &[nonce_index]]。ほとんどのクライアントは nonce_index = 0 を使用し、order_nonce でカーディナリティを管理します。

キーアカウントの導出

シード文字列は必ずオンチェーンの IDL および reference/program-addresses と照合して確認してください。

ライフサイクル早見表

TickArrayState アカウントはプログラムによってクローズされることはありません。プールの存続期間中ずっとオンチェーンに残ります。一度初期化されたティック配列は、内部のすべてのティックが liquidity_gross == 0 に戻った後も存続します。既存のティック配列の再利用は無料で、追加レントが発生するのは一度も初期化されていない配列に最初に触れるポジションのみです。

参照先ガイド

ソース: