Skip to main content
このページは AI による自動翻訳です。すべての内容は英語版を正とします。英語版を表示 →
CPI(「クロスプログラム呼び出し」)は、1 つの Solana プログラムが別のプログラムを呼び出すメカニズムです。Raydium のほとんどのプログラムは Anchor CPI ラッパークレートを提供しており、呼び出し側は型付き関数呼び出しのように見え、検証されたフィールド名を持つアカウント構造体と cpi::<ix>() ヘルパーを備えています。このページでは一般的なパターンを一度説明し、その後プログラムごとの違いを説明します。実行可能な TypeScript については、各製品章の code-demos ページを参照してください。

どのパターンがどのプログラムに適用されるか

CPMM、CLMM、または LaunchLab を統合する場合は、まず一般的なパターンを読み、その後プログラムのセクションにジャンプしてアカウントリストと違いを確認してください。Farm v6 と AMM v4 は十分に異なるため、それぞれのセクションを独立して読む価値があります。

Cargo 依存関係

依存関係キーはターゲットリポジトリの [package] name と完全に一致する必要があります。ハイフンを含めて。 Cargo は raydium_cp_swap を raydium-cp-swap と同等として扱いません。git 依存関係を解決する場合。
branch = "master" は最新公開ソースを追跡します。再現可能なビルドが必要な場合は、特定の rev = "<commit>" にピンしてください。プロトタイピングを過ぎたら推奨されます。上流のアカウントレイアウト変更が master で警告なしにビルドを破壊するためです。 cpi フィーチャーフラグにより、クレートはフルプログラムではなく CPI サーフェス(アカウント構造体 + インボーカー)のみにコンパイルされるため、バイナリは小さいままです。 anchor-lang / anchor-spl はターゲットクレートがピンしているものと一致する必要があります:
両方のクレートを同じ Anchor ラインから取得してください。 両方のアップグレードブランチは =1.0.2 をピンしているため、1 つのプログラムは CPMM と CLMM の両方に CPI できます。ラインを混ぜるとビルドが破壊されます。例えば、raydium-cp-swap を chore/upgrade-anchor で、raydium-clmm を master で。Cargo は 1 つのバイナリに Anchor の特性の 2 つの互換性のないコピーをリンクする必要があります。混合ペアに固執している場合は、プログラムを 2 つに分割するか、型付き CPI クレートを 1 つ側にドロップして、その命令を手動でエンコードしてください(AMM v4 に示されているパターンはすべてのプログラムで機能します)。ブランチは最終的に master に移動するため、開始前に両方の Cargo.toml ファイルを再確認してください。
Anchor 1.0 は CPI 呼び出しサイトが触れる 2 つのことを変更しました。 0.3x から動作する統合を移動する場合:
  • CpiContext::new は AccountInfo ではなく Pubkey を取ります。 CpiContext::new(ctx.accounts.cpmm_program.to_account_info(), accts) は CpiContext::new(*ctx.accounts.cpmm_program.key, accts) になります。new_with_signer も同じです。構造体フィールドは program_id: Pubkey です。
  • Context は 1 つのライフタイムを持ち、4 つではありません。 Context<'_, '_, 'info, 'info, MyProxySwap<'info>> は Context<'info, MyProxySwap<'info>> になります。
クライアント側では、anchor-client の RequestBuilder::instructions() は Result<Vec<Instruction>> ではなく Vec<Instruction> を返すようになりました(? をドロップしてください)。CommitmentConfig は solana-sdk から移動しました — 代わりに anchor_client から取得してください。spl-associated-token-account 8.0 は新しい spl-associated-token-account-interface クレートからヘルパーを再エクスポートします。get_associated_token_address と ID はクレートルート(spl_associated_token_account::{get_associated_token_address, ID})で到達可能ですが、アドレスヘルパーはそこで非推奨です — spl-associated-token-account-interface に直接依存し、spl_associated_token_account_interface::address::get_associated_token_address と spl_associated_token_account_interface::program::ID をインポートすることを推奨します。::address と ::program はインターフェースクレートのモジュールです。spl_associated_token_account::address::… は解決されません。
アカウント構造体をエンドツーエンドで配線する実行可能な CPI 例については、raydium-io/raydium-cpi-example(AMM v4、CPMM、CLMM をカバー)を参照してください。最新ブランチは anchor-0.31.0 です — Anchor 1.x ブランチはまだないため、そのリポジトリをアカウント構造体配線の参照として扱い、このページが要求するバージョンピンではありません。

一般的な Anchor CPI パターン

このセクションでは、CPMM をエンドツーエンドで説明します。これが実装例です:Accounts 構造体、CpiContext、cpi::<ix>()。CLMM は同じ形状に従いますが、異なるアカウントリストと残りのアカウント要件があります。LaunchLab は同じメカニクスに従いますが、そのアカウントリストは CPMM/CLMM と同等のアカウントがいくつかあります(global_config、platform_config、event_authority、program)。同じパターンとして扱い、同じ形状ではありません。各プログラムの独自セクションを参照してください。このチュートリアルのアカウントリストが直接転送されると仮定しないでください。

アカウントリスト構築

すべての Raydium CPI には、呼び出しプログラムの Accounts 構造体が必要です。そのフィールドは、あなたの命令が必要とするアカウントであり、フィールドレベルのバリデーター付きです。それらの宣言順序は Raydium 自身の命令アカウント順序と一致する必要はありません。あなた自身の IDL 生成クライアントはそれらを位置ではなく名前でアドレス指定するためです:
Raydium 側のほとんどのアカウントは UncheckedAccount です。呼び出し先(Raydium)が検証を所有しているためです。呼び出しプログラムは、ユーザー ATA やあなた自身の PDA など、あなたが所有するアカウントのみを厳密に検証します。/// CHECK: ドックコメントは、チェックの欠落に関する Anchor の警告を抑制します。1 つの Raydium 側の例外は cpmm_program 自体です:Raydium が内部で検証するデータアカウントではなく、呼び出されるプログラムです。Program<T> として型付けされ、手動の /// CHECK: の代わりに Anchor の自動アドレスチェックを取得します。この主に UncheckedAccount の形状(Raydium が独自のアカウントを検証する)は CLMM と LaunchLab でも同じです。この例は両方のミントが古典的な SPL Token であると仮定しています。どちらかが Token-2022 ミントである可能性がある場合は、token_program_2022: Program<'info, anchor_spl::token_2022::Token2022> フィールドを追加し、下の CPI 呼び出しで token_program の代わりに input_token_program/output_token_program として渡してください。

CPI 呼び出しの構築

Anchor は命令ごとに 1 つのヘルパーを生成し、CPI アカウント構造体(cpi::accounts::Swap、下で CpmmSwap としてエイリアス)と共に生成します。上記の独自の MyProxySwap 構造体とは異なり、このフィールド名と順序は raydium-cp-swap の独自の IDL によって固定され、完全に一致する必要があります:
cpi::swap_base_input は IDL から生成されます。その引数リストは Anchor 命令の引数リストを反映しています。確認されたすべての Anchor ベースの Raydium プログラム(CPMM、CLMM、LaunchLab)は同じ方法で cpi::<ix>() ヘルパーを生成し、関数名は snake_case の命令名と一致します。これが Farm v6 に拡張されるかどうかは未確認です。そのセクションを参照してください。

署名者シード(PDA 署名 CPI)

プログラムが PDA に代わって CPI に署名する場合(ボルト、エスクロー等で一般的)、CpiContext::new_with_signer を使用します:
署名者シードは PDA の導出と一致する必要があります。authority(または同様の署名者ロール)として渡されるアカウントについて、Solana ランタイムは PDA がこれらのシードを介して署名することを確認します。

残りのアカウント

一部の Raydium 命令は残りのアカウントを取ります。固定アカウントの後に追加される可変長リストです。Anchor の CPI ヘルパーは残りのアカウントを型チェックしません。.with_remaining_accounts(...) 経由で渡してください:
順序は常に重要です。受信プログラムは渡した順序で残りのアカウントを反復処理するためです。2 つの確認された順序:
  • CLMM SwapV2:ティック配列、方向順。
  • Farm v6:(reward_vault, user_reward_ata) ペア。ただし 2 番目の報酬ストリーム以降のみ。Farm v6 を参照して、実際のトランザクションのデコードが何を示すかを確認してください。

パターンの適用:CLMM

SwapV2 は上記の一般的なパターンに従いますが、異なるアカウントリストとティック配列の残りのアカウント要件があります。クレートの #[program] モジュールは raydium_clmm という名前で、これは Rust use パスでもあります。
CPI アカウント構造体は SwapV2 ではなく SwapSingleV2 という名前です。 SwapV2 はオンチェーン命令名です。
ティック配列リストは SDK と同じ方法で計算します。現在のプール状態に対する見積もりを使用し、固定数を推測するのではなく。配列を超えるスワップは TickArrayNotFound で戻ります(products/clmm/instructions を参照して、完全なアカウントテーブルとエラーリストを確認してください)。価格ウォークの方向で渡してください:スワップ方向の最初の配列が最初。

パターンの適用:LaunchLab

LaunchLab は Anchor ベースで IDL 公開です:raydium_launchpad/raydium_launchpad.json。パブリック raydium-idl リポジトリ内。その IDL の内部メタデータ識別子は raydium_launchpad です。製品の技術名であり、代替名ではありません。CPMM と CLMM とは異なり、プログラム自体のソースは公開されていません(reference/program-addresses を参照)。Cargo が指すべき git = "..." 依存関係はなく、実際のクレートの Rust use パスが何であるかを確認するソースもありません。 Anchor の declare_program! マクロを使用して、公開された IDL からバインディングを生成します。IDL JSON を idls/raydium_launchpad.json としてクレートに保存します(Cargo は CARGO_MANIFEST_DIR に相対的な idls/ ディレクトリを探します)。その後 declare_program!(raydium_launchpad); は IDL から直接 raydium_launchpad::cpi::accounts::<Ix> 構造体と cpi::<ix>() 関数を生成します。プログラムソースは不要です。生成されたアカウント構造体名は常に PascalCase の命令名です(buy_exact_in → BuyExactIn)。フィールド名は IDL のアカウント名と完全に一致します。下の MyProxyBuy で既に使用されているのと同じアカウントリストです。 CPI 形状は一般的なパターンに従います。下のアカウントリストと引数は products/launchlab/instructions.mdx ではなく、オンチェーン IDL の buy_exact_in 命令から来ています:
卒業後、ターゲットプログラムは pool_state.migrate_type に応じて CPMM または AMM v4 です。products/launchlab/accounts.mdx は Initialize 時に設定されると言っています。CPI アカウントリストは両方に対応するか、最初に PoolState から migrate_type を読み取り、分岐する必要があります。

エラー伝播

各 Anchor ベースの Raydium プログラムは独自のエラー列挙型を返します。Anchor はそれらをラップするため、呼び出しプログラムは Err(ProgramError::Custom(code)) として表示されます。特定のエラーを処理するには:
呼び出しているプログラムの関連エラー型を入れ替えてください(CLMM の場合は raydium_clmm::error::ErrorCode など)。エラーコード番号は IDL ポリシーごとに安定しています(sdk-api/anchor-idl)。数値と比較することで特定のコードをテストできます。完全なエラーテーブル:CPMM、CLMM、AMM v4、Farm v6、LaunchLab。

構成 CPI のコンピュート予算

各 CPI フレームはオーバーヘッドを持ち、呼び出し先の独自の CU 消費はあなたの上に積み重なります。プログラム内から Raydium に呼び出すトランザクションには、200k CU デフォルトに依存するのではなく、明示的なコンピュート予算が必要です。
推定ではなく測定。 メインネット上の CPMM swap_base_input は CPMM プログラム自体で約 23,000 CU を消費します — 2026-09-09 にサンプリングされた高ボリュームプール上の 8 つのライブスワップ(22,721–23,052)。Program CPMMoo8… consumed N of M compute units ログラインから読み取られます。比較:AMM v4 スワップ約 26,000;CLMM swap 約 41,000;CLMM swap_v2 約 48,000(43,838–52,887)。各ティック交差で上昇します。このページの以前のリビジョンはプロキシスワップ CPI に約 47,700 CU を報告していました。その数字は全トランザクション(computeUnitsConsumed)でした。呼び出し側のプログラム、CPI フレーム、ATA セットアップを含みます — 呼び出し先のコストではありません。両方が有用ですが、同じ数字ではないため、同じものを比較してください。ドキュメントからコピーされた数字ではなく、独自の測定から予算を立ててください。デフォルト 200k CU 制限は静かに枯渇し、プログラムがアップグレードされるにつれて命令ごとのコストが変わります。
CLMM と LaunchLab CPI はより多くのコストがかかります(CLMM は特に remaining_accounts を介して追加のティック配列を歩き、配列ごとに CU を追加します)。ただし、上記の CPMM 数字のみが測定値です。常に独自の測定から計算された明示的な ComputeBudgetProgram::set_compute_unit_limit(...) 命令を設定してください。ドキュメントからコピーされた数字ではなく。デフォルト 200k CU 制限は静かに枯渇し、プログラムがアップグレードされるにつれて命令ごとのコストが変わります。

AMM v4:手動命令構築

AMM v4 は Anchor より前の時代で、CPI クレートがないため、このドキュメント内の唯一のプログラムで一般的なパターンに従いません。Instruction を手動で構築します:
完全なアカウントリストについては、products/amm-v4/code-demos を参照してください。

Farm v6

統合のオプションが TS SDK である場合は、それを使用してください。 raydium.farm.deposit(...) (products/farm-staking/code-demos を参照)は実際のデモで実行され、このプログラムに Rust Anchor クレートが存在するかどうかに依存しません。
Farm v6 は Anchor CPI パスを提供しません。 crates.io に raydium_farm_v6 クレートはなく、パブリックソースリポジトリもなく、オンチェーン IDL もありません — プログラムはレガシー anchor:idl アカウントも Program Metadata プログラムのエントリも持ちません(sdk-api/anchor-idl を参照)。非 Anchor プログラムとして扱い、下のように手動で命令を構築してください。
それでも Rust CPI が必要な場合、例えば別のオンチェーンプログラムから構成する場合は、AMM v4 と同じ方法で Instruction を手動で構築します:実際のアカウントリストと命令ディスクリミネーターを独立して導出します。例えば、SDK の TypeScript レイアウト(raydium-sdk-V2 のファームモジュール)をデコードしたり、実際のトランザクションを直接デコードしたり(下を参照)、デプロイされたプログラムをダンプして逆アセンブルしたりします。 ゼロ引数命令形状(ハーベストまたはクレーム呼び出しと一貫性がある)の場合、実際のアカウント順序は固定プレフィックス(token_program、ファームの状態アカウント、ボルト権限 PDA、その PDA の最初の報酬ボルト、2 番目の PDA、呼び出し元、その最初の報酬ミント用の呼び出し元の ATA)の後に、最初の後のすべての報酬ストリームの (reward_vault_i, user_reward_ata_i) ペアが remaining_accounts に続きます。ペアリング規約は実際ですが、2 番目の報酬ストリームからのみ開始されます:最初のストリームのボルトと ATA は固定アカウントであり、互いに隣接しておらず、remaining_accounts の一部ではありません。

CPI フローのテスト

ローカル開発には、Raydium プログラムがテストバリデーターで利用可能である必要があります。3 つのオプション:
  1. プログラムクローン付き anchor test。 デプロイされたメインネットバイトコードをローカルバリデーターにプルします。下のローカルバリデーターへのプログラムクローンで Anchor.toml 設定と、プール作成テストを特に引っかかる 2 つのことを参照してください。
  2. Devnet。 Raydium はほとんどのプログラムを devnet にデプロイしますが、すべてのプログラムでメインネットと異なるプログラム ID(CPMM、CLMM、AMM v4、Stable AMM、LaunchLab はそれぞれ異なる devnet アドレスを持ちます。reference/program-addresses の Devnet テーブルを参照)。Farm v3/v5/v6 は devnet で確実に公開されていません。ライブ API(https://api-v3-devnet.raydium.io/main/info)が現在の状況を持っています。raydium_clmm のバンドルされた DEVNET_PROGRAM_ID 定数(または他のクレートの同等物)を使用する場合、メインネット ID も devnet で機能すると仮定しないでください。正しいアドレスを取得したら、anchor test --provider.cluster devnet を実行してライブコードにヒットしてください。
  3. ローカルデプロイ。 Raydium リポジトリをクローン(CPMM、CLMM;LaunchLab のソースはこのオプションでは利用できません)し、ローカルバリデーターに anchor deploy します。テストサイクルのオーバーヘッドを追加しますが、デバッグのために呼び出し先を変更できます。
anchor test で実行するか、プログラムを変更しないでテストファイルを反復処理している場合は、最初に anchor build を実行してから anchor test --skip-build を実行してください。

ローカルバリデーターへのプログラムクローン

これはプログラム ID に関係なく機能するため、LaunchLab はソースが利用できなくても CPMM と CLMM と同じ方法でクローンされます。reference/program-addresses はここのすべてのアドレスの信頼できる情報源です。
プログラムをクローンするだけでは、テストがプールを作成する場合は不十分です(既存のプールに対してスワップするのではなく)。CPMM の initialize 命令は、その amm_config と create_pool_fee アカウントをリアルなオンチェーンデータに対して検証するため、それらもクローンする必要があります。そうしないと initialize は直ちに失敗します。CPMM 固有:希望するフィー層 AmmConfig をクローンします(GET https://api-v3.raydium.io/main/cpmm-config からそのアドレスを取得します。インデックス 0 は 0.25% ティア)とフィー受信トークンアカウント。正確なアドレスで検証され、オンザフライで作成されないため、既に存在する必要があります。
テストが作成したばかりのプールは同じ瞬間にスワップ可能ではありません。 CPMM の initialize は、厳密に将来ではない要求された open_time を静かにオーバーライドします(if open_time <= block_timestamp { open_time = block_timestamp + 1 })。startTime: 0(SDK ごとに「すぐに開く」)でも、プールがスワップを受け入れる前に実際の ≥1 秒のギャップが残ります。プールを作成し、ゼロ遅延でそれに対してスワップするテストは NotApproved にヒットします。プール作成と最初のスワップの間の短い await(1–2 秒)で十分です。これはテスト固有です。人間が 2 つの別々の手動コマンドを実行する場合、通常は気付きません。入力とプロセス起動は既に 1 秒以上を消費するためです。

ポインター

ソース: