Skip to main content
このページは AI による自動翻訳です。すべての内容は英語版を正とします。英語版を表示 →

セットアップ

このページのすべてのデモは、raydium-sdk-V2-demo/src/clmm 内のファイルに対応しています。各セクションの横に GitHub へのリンクがあります。初期化処理はデモリポジトリの config.ts.template に従います(ソース)。本格的な連携では、disableFeatureCheck: true を設定することを推奨します。

CLMM プールを作成する

ソース:src/clmm/createPool.ts
SDK は次の処理を行います:
  • 導出の前に、mint1/mint2 をバイト順でソートします。
  • sqrt_price_x64 = floor(sqrt(initialPrice × 10^(dB−dA)) × 2^64) を計算します。
  • observation と tick_array_bitmap_extension アカウントを作成します。
  • ammConfig で定義されたプール作成手数料を支払います。

任意の価格帯でポジションをオープンする

ソース:src/clmm/createPosition.ts
SDK は、その範囲がどの tick 配列に触れるかを計算し、それらをアカウントとして渡します。初期化用の命令をバンドルする必要はありません。init-tick-array 命令は存在せず、OpenPosition* が不足している tick 配列を支払者の負担で自動的に割り当てます。

既存のポジションにリクイディティを追加する

ソース:src/clmm/increaseLiquidity.ts

リクイディティを減らす(同時にフィーを回収)

ソース:src/clmm/decreaseLiquidity.ts および src/clmm/closePosition.ts
フィーとリワードのみを回収するには、liquidity = new BN(0) で decreaseLiquidity を呼び出します。この命令の副作用として、token_fees_owed_{0,1} と reward_amount_owed が精算され、外部に送金されます。どちらかを回収する方法は、これonly です。 流動性とフィーをゼロにした後にポジションを完全にクローズするには、最後の decreaseLiquidity 呼び出しで ownerInfo: { closePosition: true } を渡します。SDK は ClosePosition を追加し、NFT をバーンします。
制限付き発行者のポジションには、対応するクローズビルダーが必要です。 これらのポジションでは NFT のトークンアカウントが凍結されています。CLMM がバーンの前にアカウントを解凍できるよう、ClosePosition はポジションのプール ID を残りのアカウントの先頭に追加する必要があります。プログラムのソースブランチには SDK の変更は含まれていません。制限付き発行者のポジション作成を有効にする前に、お使いの SDK リリースが凍結状態でのクローズに明示的に対応していることを確認してください。
Anchor クライアントを直接使う場合は、宣言済みのアカウントはそのままにして、プールを追加します:
クローズのたびに poolId を渡しても構いません。CLMM が読み取るのは positionNftAccount が凍結されている場合のみです。そのため、1 つのクライアントの処理で古いポジションと新しいポジションの両方に対応できます。

リワードを回収する

ソース:src/clmm/harvestAllRewards.ts
harvestAllRewards は、渡されたすべてのプールのすべてのポジションを走査し、フィーとリワードを精算する残高ゼロの DecreaseLiquidity 呼び出し(および必要に応じて UpdateRewardInfos)をまとめます。必要な場合は、それらを複数のトランザクションに分割します。

スワップ

ソース:src/clmm/swap.ts このサンプルは src/clmm/swap.ts を再現したものです。PoolUtils.computeAmountOutFormat ではなく swapInternal を使ってシミュレーションを行います。
シミュレーションは、オンチェーンプログラムと同じロジックでティックマップをオフチェーン上で走査し、出力量(amountCalculated)と、スワップが触れる正確なアカウント一覧(accounts)を返します。 シミュレーションが返した remainingAccounts は必ず渡してください。数が足りないとスワップは走査の途中で NotEnoughTickArrayAccount によりリバートします。古いアカウントを渡した場合はリバートはしませんが、計算リソースを無駄に消費します。
PoolUtils.computeAmountOutFormat も引き続き存在しますが、ComputeClmmPoolInfo(API のプールオブジェクトではなく、getPoolInfoFromRpc が返す computePoolInfo)と、さらに 2 つの必須引数(tickarrayBitmapExtension と blockTimestamp)が必要です。また、raydium.clmm.fetchTickArrays メソッドは存在しません。fetchTickArrays はフリー関数で、モジュールレベルのヘルパーは PoolUtils.fetchMultiplePoolTickArrays と、getPoolInfoFromRpc が返す tickData / tickArrays です。

カスタマイズ可能な CLMM プールの作成

createCustomizablePool は、プール作成時に動的手数料と片側手数料のトグルを指定できるエントリーポイントです。引数は createPool と同じ形に、2 つの項目を追加したものになります。
enableDynamicFee、dynamicFeeConfigId、startTime のパラメータは存在しません。動的手数料を有効にするのは dynamicFeeConfig の指定です。 省略するとエラーは出ずに、固定手数料のプールが作成されます。また、SDK の列挙型のメンバーは TokenOnlyA / TokenOnlyB ですが、オンチェーンの Rust 列挙型では Token0Only / Token1Only と綴られます。数値は一致しており(FromInput = 0)、違いは名前だけです。
デフォルト手数料で動的手数料を使わない場合は、引き続き createPool を利用できます。どちらかの設定が必要な場合は createCustomizablePool を使用してください。オンチェーンのアカウント一覧は products/clmm/instructions を参照してください。

指値注文

指値注文は、ユーザーの入力資産を単一のティックに預けておき、スワップがそのティックを横切ったときに先入れ先出し(FIFO)で約定させる仕組みです。出力はセトルの時点で所有者の ATA に送られるため、約定のために所有者がオンラインである必要はありません。

指値注文の作成

プールごとの指値注文設定アカウントや getClmmLimitOrderConfigs() ヘルパーは存在しません。注文はティックをキーとして管理されます。
SDK は (owner, nonce PDA, order nonce) から LimitOrderState PDA を導出し、ウォレットごとの LimitOrderNonce を更新して、注文をそのティックの FIFO コホートに挿入します。

未約定の注文を増額・減額する

decreaseLimitOrder で減額できるのは、注文の未約定部分のみです。約定済みの部分は、セトルされるまでロックされます。注文がすでに全量約定している場合、どちらの命令も InvalidOrderPhase によりリバートします。

約定済み注文の決済

settleLimitOrder は、注文の unfilled_ratio_x64 をコホートのトラッカーと照合して約定済みの出力を計算し、所有者の ATA に送金します。所有者は自分で呼び出せます。オフチェーンの運用キーパーである limit_order_admin も、所有者の代わりに呼び出せます。その場合も出力は所有者に送られます。 完全に決済された注文のレントを回収するには、closeLimitOrder(単一)または closeAllLimitOrder(一括)を使用します。複数の注文をまとめて決済する場合は、settleAllLimitOrder が v0 トランザクションに収まる範囲で SettleLimitOrder の呼び出しをまとめます。

ウォレットの未約定注文の一覧取得(オフチェーン)

有効な注文のエンドポイントは、未約定と一部約定の両方の注文を 1 つのペイロードで返します。totalAmount / filledAmount / pendingSettle で状態を区別できます。クローズ済み注文の履歴は /limit-order/history/order/list-by-user?wallet=…(ウォレットごと、nextPageId によるページング)で取得し、特定の注文のイベントログ全体は /limit-order/history/event/list-by-pda?pda=… で取得します。

Rust CPI のスケルトン

SwapV2 の残りアカウントの順序は次のとおりです。
スワップでビットマップ拡張が不要な場合は省略してください。必要な場合は、残りアカウントの先頭に配置します。

よくある落とし穴

  • ティック範囲の端点が間隔に合っていない → TickAndSpacingNotMatch。必ず TickUtil.getPriceAndTick を使ってスナップしてください(TickUtil は単数形)。
  • SwapV2 に供給するティック配列が不足している → NotEnoughTickArrayAccount。一覧は swapInternal(...).accounts から取得してください。
  • ビットマップ拡張なしでフルレンジのポジションを作成している → 拡張の PDA は書き込み可能である必要があります。SDK がこれを自動的に処理します。
  • sqrt_price_x64 を price と取り違えている → ここでの 2 倍の誤差は特に厄介です。迷ったら、人が読める価格から SDK に計算させてください。
  • 報酬の回収が頻繁すぎる → 回収のたびにゼロ流動性の DecreaseLiquidity が実行され、トランザクションが 1 件ずつ発生します。複数のポジションをまとめて処理するには harvestAllRewards を使い、その execute には { sequentially: true } が必要な点に注意してください。
  • NFT アカウントを自分でクローズしている → ClosePosition は NFT をバーンし、その ATA もクローズします。Token-2022 の NFT ミントもクローズされます。一方、従来の SPL Token ミントは、そのプログラムではミントをクローズできないため、供給量ゼロのまま残ります。対応しているアカウントを個別にクローズしないでください。そうすると命令がリバートします。
  • ティック間隔に合っていない位置で指値注文を開いている → TickAndSpacingNotMatch。必ず、エクスポートされた getOrderTick ヘルパーでティックを量子化してください。
  • 完全に約定済みの注文に対して decreaseLimitOrder を呼び出している → InvalidOrderPhase。代わりに settleLimitOrder を実行してから closeLimitOrder を実行してください。
  • enableDynamicFee フラグがあると思い込んでいる → そのようなフラグは存在しません。dynamicFeeConfig を省略すると、エラーも出ずに静的手数料のプールが作成されるだけです。ダイナミック手数料を使いたい場合は、/main/clmm-dynamic-config から選んだ設定アカウントの PublicKey を渡してください。

次に読むページ

出典: