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

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

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

Cargo 依存関係

依存関係キーは、ターゲット リポジトリの [package] name と完全に一致する必要があります。ハイフンを含めて。 Cargo は、git 依存関係を解決する際に raydium_cp_swap を raydium-cp-swap と同等に扱いません。
branch = "master" は最新の公開ソースを追跡します;再現可能なビルドが必要な場合は、特定の rev = "<commit>" にピンしてください。プロトタイピングを終えたら推奨されます。master 上のアップストリーム アカウント レイアウト変更により、警告なしにビルドが破損する可能性があるためです。 cpi フィーチャー フラグにより、クレートはフル プログラムではなく CPI サーフェス(アカウント構造体 + インボーカー)のみにコンパイルされるため、バイナリが小さく保たれます。 anchor-lang / anchor-spl はターゲット クレートがピンしているものと一致する必要があります:
両方のクレートを同じ Anchor ラインから取得してください。 両方の master ブランチは =1.0.2 をピンしているため、1 つのプログラムから CPMM と CLMM に CPI できます。ラインを混ぜるとビルドが破損します。例えば、master の raydium-cp-swap と Anchor 1.0 アップグレード前の rev にピンされた raydium-clmm。Cargo は 1 つのバイナリに 2 つの互換性のない Anchor トレイトのコピーをリンクする必要があります。混合ペアに固執している場合は、プログラムを 2 つに分割するか、一方の型付き CPI クレートをドロップして、その命令を手動でエンコードしてください(AMM v4 に示されているパターンはすべてのプログラムで機能します)。
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 も同じ形式に従いますが、アカウント リストが異なり、残りのアカウント(remaining accounts)が必要です。LaunchLab も同じメカニズムを使いますが、アカウント リストに CPMM/CLMM にはない複数のアカウント(global_config、platform_config、event_authority、program)が含まれるため、同じパターンとして扱いますが、同じ形式ではありません。このチュートリアルのアカウント リストが直接転用できると仮定せず、各プログラムのセクションを参照してください。

アカウント リストの構築

すべての Raydium CPI には、呼び出し元プログラムに Accounts 構造体が必要です。そのフィールドは、あなたの命令が必要とするアカウントであり、フィールドレベルのバリデータを持ちます。フィールドの宣言順序は Raydium の命令アカウント順序と一致する必要はありません。あなた自身の IDL 生成クライアントが位置ではなく名前でアドレス指定するためです:
Raydium 側のアカウントのほとんどは UncheckedAccount です。呼び出し先(Raydium)がバリデーションを所有しているためです。呼び出し元プログラムは、ユーザー ATA やあなた自身の PDA など、あなたが所有するアカウントのみを厳密にバリデーションします。/// CHECK: ドキュメント コメントは、チェックが欠落していることについての Anchor の警告を抑制します。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 呼び出しでそちら側の input_token_program/output_token_program として 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>() ヘルパーを生成し、関数名は命令名をスネーク ケースで表したものと一致します。これが Farm v6 に拡張されるかどうかは未確認です。そのセクションを参照してください。

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

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

残りのアカウント

一部の Raydium 命令は残りのアカウント(remaining accounts)を取ります。これは固定アカウントの後に追加される可変長リストです。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 で戻ります(完全なアカウント テーブルとエラー リストについては /ja/products/clmm/instructions を参照)。価格ウォークの方向で渡してください。スワップ方向の最初の配列を最初に渡します。

パターンの適用:LaunchLab

LaunchLabはAnchorベースで、IDLが公開されています:公開リポジトリ raydium-idl の raydium_launchpad/raydium_launchpad.json。このIDLの内部メタデータ識別子は raydium_launchpad で、これは製品の別名ではなく、基盤となるプログラムの技術名です。ただし、CPMMやCLMMとは異なり、プログラムのソースコード自体は公開されていません(reference/program-addresses を参照)。Cargoが指すような git = "..." 依存関係もなく、実際のクレートのRust use パスが何であるかを確認するソースもありません。 公開されているIDLからAnchorの declare_program! マクロを使用してバインディングを生成します。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年9月9日に高ボリュームプール上の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設定を含みます。呼び出し先のコストではありません。どちらも有用ですが、同じ数値ではないため、同じ基準で比較してください。ドキュメントからコピーした数値ではなく、独自の測定から予算を立ててください。
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 のfarmモジュール)をデコードする、実際のトランザクションを直接デコードする(以下を参照)、またはデプロイされたプログラムをダンプして逆アセンブルします。 ハーベストまたはクレーム呼び出しと一致するゼロ引数命令形状の場合、実際のアカウント順序は固定プレフィックス(token_program、ファームの状態アカウント、ボルト権限PDA、そのPDAの最初のリワードボルト、2番目のPDA、呼び出し元、その最初のリワードミント用の呼び出し元のATA)の後に、最初の後のすべてのリワードストリームについて remaining_accounts の (reward_vault_i, user_reward_ata_i) ペアが続きます。ペアリング規則は実際のものですが、2番目のリワードストリームからのみ開始されます。最初のストリームのボルトとATAは固定アカウントで、互いに隣接していなく、remaining_accounts の一部ではありません。

CPI フローのテスト

ローカル開発では、Raydium プログラムをテスト バリデーターで利用可能にする必要があります。3 つのオプションがあります:
  1. プログラム クローンを使用した anchor test。 メインネットにデプロイされたバイトコードをローカル バリデーターにプルします。以下の「ローカル バリデーターへのプログラムのクローン」で Anchor.toml の設定と、プール作成テストで特に注意が必要な 2 つの点を参照してください。
  2. Devnet。 Raydium はほとんどのプログラムを devnet にデプロイしていますが、すべてのプログラムで mainnet とは異なるプログラム 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 定数(または他のクレートの同等物)を使用する場合、mainnet 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 秒以上かかるためです。

ポインター

ソース: