Skip to main content
Diese Seite wurde mit KI automatisch übersetzt. Maßgeblich ist stets die englische Version.Englische Version ansehen →
CPI („Cross-Program Invocation”) ist der Mechanismus, über den ein Solana-Programm ein anderes aufruft. Die meisten Raydium-Programme werden mit Anchor-CPI-Wrapper-Crates ausgeliefert, die die Aufrufstelle wie einen typisierten Funktionsaufruf aussehen lassen, mit Kontostrukturen, die validierte Feldnamen und cpi::<ix>()-Helfer haben. Diese Seite dokumentiert das allgemeine Muster einmal, dann die programmspezifischen Unterschiede. Für ausführbare TypeScript-Beispiele siehe die code-demos-Seite jedes Produktkapitels.

Welches Muster gilt für welches Programm

Wenn Sie CPMM, CLMM oder LaunchLab integrieren, lesen Sie zuerst das allgemeine Muster, dann springen Sie zum Abschnitt Ihres Programms für die Kontoliste und alle Unterschiede. Farm v6 und AMM v4 unterscheiden sich genug, um ihre Abschnitte eigenständig zu lesen.

Cargo-Abhängigkeiten

Der Abhängigkeitsschlüssel muss exakt dem [package] name des Ziel-Repos entsprechen, Bindestriche eingeschlossen. Cargo behandelt raydium_cp_swap nicht als äquivalent zu raydium-cp-swap beim Auflösen einer Git-Abhängigkeit.
branch = "master" verfolgt die neueste veröffentlichte Quelle; pinnen Sie auf einen spezifischen rev = "<commit>", wenn Sie einen reproduzierbaren Build benötigen. Dies wird empfohlen, sobald Sie über die Prototypisierung hinaus sind, da eine Upstream-Kontolayout-Änderung auf master Ihren Build ohne Warnung bricht. Das cpi-Feature-Flag lässt die Crates nur zur CPI-Oberfläche (Kontostrukturen + Invoker) kompilieren, anstatt das vollständige Programm zu kompilieren, sodass Ihre Binärdatei klein bleibt. anchor-lang / anchor-spl müssen dem entsprechen, was das Ziel-Crate pinnt:
Nehmen Sie beide Crates aus der gleichen Anchor-Linie. Beide Upgrade-Branches pinnen =1.0.2, daher kann ein Programm von einer einzigen Crate aus in CPMM und CLMM CPI aufrufen. Das Mischen von Linien bricht den Build: zum Beispiel raydium-cp-swap auf chore/upgrade-anchor mit raydium-clmm auf master. Cargo müsste zwei inkompatible Kopien von Anchors Traits in eine Binärdatei linken. Wenn Sie bei einem gemischten Paar stecken, teilen Sie das Programm in zwei auf, oder lassen Sie das typisierte CPI-Crate für eine Seite fallen und kodieren Sie diese Instruction manuell (das für AMM v4 gezeigte Muster funktioniert für jedes Programm). Überprüfen Sie beide Cargo.toml-Dateien vor dem Start, da die Branches irgendwann zu master wechseln werden.
Anchor 1.0 hat zwei Dinge geändert, die jede CPI-Aufrufstelle berührt. Wenn Sie eine funktionierende Integration von 0.3x verschieben:
  • CpiContext::new nimmt einen Pubkey, nicht einen AccountInfo. CpiContext::new(ctx.accounts.cpmm_program.to_account_info(), accts) wird zu CpiContext::new(*ctx.accounts.cpmm_program.key, accts). Gleiches für new_with_signer. Das Strukturfeld ist jetzt program_id: Pubkey.
  • Context hat eine Lebensdauer, nicht vier. Context<'_, '_, 'info, 'info, MyProxySwap<'info>> wird zu Context<'info, MyProxySwap<'info>>.
Auf der Client-Seite gibt anchor-client’s RequestBuilder::instructions() jetzt Vec<Instruction> statt Result<Vec<Instruction>> zurück (lassen Sie das ? weg), und CommitmentConfig wurde aus solana-sdk verschoben — nehmen Sie es stattdessen von anchor_client. spl-associated-token-account 8.0 re-exportiert seine Helfer aus dem neuen spl-associated-token-account-interface-Crate. get_associated_token_address und ID sind immer noch an der Crate-Root erreichbar (spl_associated_token_account::{get_associated_token_address, ID}), aber die Adress-Helfer sind dort veraltet — bevorzugen Sie die direkte Abhängigkeit von spl-associated-token-account-interface und importieren Sie spl_associated_token_account_interface::address::get_associated_token_address und spl_associated_token_account_interface::program::ID. Beachten Sie, dass ::address und ::program Module des Interface-Crates sind; spl_associated_token_account::address::… wird nicht aufgelöst.
Für funktionierende CPI-Beispiele, die die Kontostrukturen end-to-end verdrahten, siehe raydium-io/raydium-cpi-example (behandelt AMM v4, CPMM und CLMM). Sein neuester Branch ist anchor-0.31.0 — es gibt noch keinen Anchor-1.x-Branch, daher behandeln Sie dieses Repo als Referenz für Kontostruktur-Verdrahtung, nicht für die Versions-Pins, die diese Seite vorschreibt.

Das allgemeine Anchor-CPI-Muster

Dieser Abschnitt geht CPMM end-to-end als durchgearbeitetes Beispiel durch: Accounts-Struktur, CpiContext, cpi::<ix>(). CLMM folgt der identischen Form, mit einer anderen Kontoliste und einer Anforderung für verbleibende Konten. LaunchLab folgt der gleichen Mechanik, aber seine Kontoliste enthält mehrere Konten ohne CPMM/CLMM-Äquivalent (global_config, platform_config, event_authority, program), daher behandeln Sie es als das gleiche Muster, nicht die gleiche Form. Siehe stattdessen den eigenen Abschnitt jedes Programms, anstatt anzunehmen, dass die Kontoliste dieser Anleitung direkt übertragen wird.

Kontolisten-Konstruktion

Jeder Raydium-CPI erfordert eine Accounts-Struktur im aufrufenden Programm. Seine Felder sind alle Konten, die Ihre Instruction benötigt, mit Feld-Level-Validatoren; ihre Deklarationsreihenfolge muss nicht mit Raydiums eigener Instruction-Kontoordnung übereinstimmen, da Ihr eigener IDL-generierter Client sie nach Name adressiert, nicht nach Position:
Die meisten Raydium-seitigen Konten sind UncheckedAccount, weil der Aufgerufene (Raydium) die Validierung besitzt. Ihr aufrulendes Programm validiert nur streng Konten, die Sie besitzen, wie Benutzer-ATAs und Ihre eigenen PDAs. Der /// CHECK:-Dokumentationskommentar unterdrückt Anchors Warnung über fehlende Prüfungen. Die eine Raydium-seitige Ausnahme ist cpmm_program selbst: Es ist das aufgerufene Programm, nicht ein Datenkonto, das Raydium intern validiert, daher ist es typisiert als Program<T> und erhält Anchors automatische Adressprüfung statt einer manuellen /// CHECK:. Diese meist-UncheckedAccount-Form, bei der Raydium seine eigenen Konten validiert, ist die gleiche für CLMM und LaunchLab. Dieses Beispiel geht davon aus, dass beide Mints klassische SPL-Token sind; wenn eine Seite ein Token-2022-Mint sein kann, fügen Sie ein token_program_2022: Program<'info, anchor_spl::token_2022::Token2022>-Feld hinzu und übergeben Sie es als input_token_program/output_token_program dieser Seite im CPI-Aufruf unten statt token_program.

Den CPI-Aufruf aufbauen

Anchor generiert einen Helfer pro Instruction zusammen mit einer CPI-Kontostruktur (cpi::accounts::Swap, unten als CpmmSwap aliasiert). Anders als Ihre eigene MyProxySwap-Struktur oben sind die Feldnamen und Reihenfolge dieser Struktur durch raydium-cp-swap’s eigene IDL festgelegt und müssen exakt übereinstimmen:
cpi::swap_base_input wird aus der IDL generiert; seine Argumentliste spiegelt die Argumentliste der Anchor-Instruction wider. Jedes bestätigte Anchor-basierte Raydium-Programm (CPMM, CLMM, LaunchLab) generiert seine cpi::<ix>()-Helfer auf die gleiche Weise, wobei der Funktionsname dem Instruction-Namen in Snake-Case entspricht. Ob dies sich auf Farm v6 erstreckt, ist unbestätigt; siehe seinen Abschnitt.

Signer-Seeds (PDA-signierter CPI)

Wenn Ihr Programm den CPI im Namen einer PDA signiert (häufig für Vaults, Escrows usw.), verwenden Sie CpiContext::new_with_signer:
Die Signer-Seeds müssen der PDA-Ableitung entsprechen. Für jedes Konto, das als authority (oder ähnliche Signer-Rolle) übergeben wird, prüft die Solana-Runtime, dass die PDA über diese Seeds signiert.

Verbleibende Konten

Einige Raydium-Instructions nehmen verbleibende Konten, eine Liste variabler Länge, die nach den festen Konten angehängt wird. Anchors CPI-Helfer führen keine Typprüfung für verbleibende Konten durch; übergeben Sie sie über .with_remaining_accounts(...):
Die Reihenfolge ist immer wichtig, da das empfangende Programm verbleibende Konten in der Reihenfolge durchläuft, in der Sie sie übergeben. Zwei bestätigte Ordnungen:
  • CLMM SwapV2: Tick-Arrays, geordnet nach Richtung.
  • Farm v6: (reward_vault, user_reward_ata)-Paare, aber nur ab dem zweiten Reward-Stream an; siehe Farm v6 für das, was das Dekodieren einer echten Transaktion zeigt.

Anwendung des Musters: CLMM

SwapV2 folgt dem allgemeinen Muster oben mit einer anderen Kontoliste und einer Anforderung für verbleibende Konten für Tick-Arrays. Das #[program]-Modul des Crates heißt raydium_clmm, was auch sein Rust-use-Pfad ist.
Die CPI-Kontostruktur heißt SwapSingleV2, nicht SwapV2. SwapV2 ist der On-Chain-Instruction-Name.
Berechnen Sie die Tick-Array-Liste auf die gleiche Weise wie das SDK, über ein Quote gegen den aktuellen Pool-Status, anstatt eine feste Anzahl zu erraten; ein Swap, der die übergebenen Arrays überläuft, wird mit TickArrayNotFound zurückgewiesen (siehe products/clmm/instructions für die vollständige Kontotabelle und Fehlerliste). Übergeben Sie sie in der Richtung des Preis-Durchlaufs: erstes Array in Swap-Richtung zuerst.

Anwendung des Musters: LaunchLab

LaunchLab ist Anchor-basiert und IDL-veröffentlicht: raydium_launchpad/raydium_launchpad.json im öffentlichen raydium-idl-Repo. Die interne Metadaten-ID dieser IDL ist raydium_launchpad, ein technischer Name für das zugrunde liegende Programm, nicht ein alternativer Name für das Produkt. Anders als CPMM und CLMM ist jedoch die Programmquelle selbst nicht öffentlich verfügbar (siehe reference/program-addresses). Es gibt keine git = "..."-Abhängigkeit, auf die Cargo verweisen kann, und keine Quelle, um zu bestätigen, was der Rust-use-Pfad eines echten Crates wäre. Generieren Sie Bindings aus der veröffentlichten IDL mit Anchors declare_program!-Makro. Speichern Sie die IDL-JSON als idls/raydium_launchpad.json in Ihrem Crate (Cargo sucht nach einem idls/-Verzeichnis relativ zu CARGO_MANIFEST_DIR), dann generiert declare_program!(raydium_launchpad); raydium_launchpad::cpi::accounts::<Ix>-Strukturen und cpi::<ix>()-Funktionen direkt aus der IDL, ohne Programmquelle erforderlich. Der generierte Kontostruktur-Name ist immer der Instruction-Name in PascalCase (buy_exact_in → BuyExactIn), und Feldnamen entsprechen exakt den IDL-Kontonamen, der gleichen Kontoliste, die bereits in MyProxyBuy unten verwendet wird. Die CPI-Form folgt dem allgemeinen Muster. Die Kontoliste und Argumente unten stammen aus der On-Chain-IDL’s buy_exact_in-Instruction, nicht aus products/launchlab/instructions.mdx:
Nach der Graduation ist das Ziel-Programm CPMM oder AMM v4, je nach pool_state.migrate_type, das products/launchlab/accounts.mdx sagt, wird zur Initialize-Zeit gesetzt. Ihre CPI-Kontoliste muss für beide vorbereitet sein, oder Sie müssen migrate_type zuerst aus PoolState lesen und verzweigen.

Fehlerbehandlung

Jedes Anchor-basierte Raydium-Programm gibt sein eigenes Error-Enum zurück; Anchor umhüllt sie, daher sieht Ihr aufrulendes Programm sie als Err(ProgramError::Custom(code)). Um spezifische Fehler zu behandeln:
Tauschen Sie den relevanten Error-Typ für das Programm aus, das Sie aufrufen (raydium_clmm::error::ErrorCode für CLMM usw.). Error-Code-Nummern sind stabil pro IDL-Richtlinie (sdk-api/anchor-idl), daher können Sie gegen spezifische Codes testen, indem Sie gegen den numerischen Wert vergleichen. Vollständige Error-Tabellen: CPMM, CLMM, AMM v4, Farm v6 und LaunchLab.

Compute-Budget in zusammengesetzten CPIs

Jeder CPI-Frame hat Overhead, und die eigene CU-Verbrauch des Aufgerufenen stapelt sich auf Ihrem, daher benötigt eine Transaktion, die von innerhalb Ihres Programms in Raydium aufruft, ein explizites Compute-Budget, anstatt sich auf das 200k-CU-Standard zu verlassen.
Gemessen, nicht geschätzt. Ein CPMM swap_base_input auf Mainnet verbraucht ~23.000 CU im CPMM-Programm selbst — Stichprobe vom 2026-09-09 über acht Live-Swaps auf einem hochvolumigen Pool (22.721–23.052), gelesen aus der Program CPMMoo8… consumed N of M compute units-Protokollzeile. Zum Vergleich: AMM v4 Swap ~26.000; CLMM swap ~41.000; CLMM swap_v2 ~48.000 (43.838–52.887), steigt mit jedem Tick-Crossing.Eine frühere Überarbeitung dieser Seite meldete ~47.700 CU für einen Proxy-Swap-CPI. Diese Zahl war die ganze Transaktion (computeUnitsConsumed), die das aufgerufene Programm, den CPI-Frame und jedes ATA-Setup einschließt — nicht die Kosten des Aufgerufenen. Beide sind nützlich, aber sie sind nicht die gleiche Zahl, daher vergleichen Sie Gleiches mit Gleichem. Messen Sie Ihre eigene Transaktion, anstatt von einer dieser Dokumentation zu budgetieren.
CLMM- und LaunchLab-CPIs kosten mehr (CLMM durchläuft insbesondere zusätzliche Tick-Arrays über remaining_accounts, was CU pro Array hinzufügt), aber nur die CPMM-Zahl oben ist ein gemessener Wert. Setzen Sie immer ein explizites ComputeBudgetProgram::set_compute_unit_limit(...)-Instruction, das von Ihrer eigenen Messung dimensioniert ist, nicht eine Zahl, die aus der Dokumentation kopiert wurde, da das Standard-200k-CU-Limit stillschweigend erschöpft wird und die Pro-Instruction-Kosten sich verschieben, wenn Programme aktualisiert werden.

AMM v4: manuelle Instruction-Konstruktion

AMM v4 ist älter als Anchor und hat kein CPI-Crate, was es zum einzigen Programm in diesem Dokument macht, das nicht dem allgemeinen Muster oben folgt. Bauen Sie die Instruction manuell:
Siehe products/amm-v4/code-demos für die vollständige Kontoliste.

Farm v6

Verwenden Sie das TS SDK, wenn das eine Option für Ihre Integration ist. raydium.farm.deposit(...) (siehe products/farm-staking/code-demos) wird durch echte Demos ausgeübt und hängt nicht davon ab, ob ein Rust-Anchor-Crate für dieses Programm existiert.
Farm v6 bietet keinen Anchor-CPI-Pfad. Es gibt kein raydium_farm_v6-Crate auf crates.io, kein öffentliches Quell-Repository und keine On-Chain-IDL — das Programm hat weder ein Legacy-anchor:idl-Konto noch einen Eintrag im Program-Metadata-Programm (siehe sdk-api/anchor-idl). Behandeln Sie es als ein Nicht-Anchor-Programm und bauen Sie seine Instructions manuell, wie unten.
Wenn Sie trotzdem Rust-CPI benötigen, zum Beispiel um von einem anderen On-Chain-Programm zu komponieren, bauen Sie die Instruction manuell, auf die gleiche Weise wie AMM v4: Leiten Sie die echte Kontoliste und Instruction-Diskriminatoren unabhängig ab, zum Beispiel durch Dekodieren der TypeScript-Layouts des SDK (raydium-sdk-V2’s Farm-Modul), Dekodieren echter Transaktionen direkt (siehe unten) oder Dumpen und Disassemblieren des bereitgestellten Programms. Für die Null-Argument-Instruction-Form, die mit einem Harvest- oder Claim-Aufruf konsistent ist, ist die echte Kontoordnung ein festes Präfix (token_program, das Farm-Status-Konto, eine Vault-Authority-PDA, die erste Reward-Vault dieser PDA, eine zweite PDA, der Aufrufer und die ATA des Aufrufers für diesen ersten Reward-Mint), gefolgt von (reward_vault_i, user_reward_ata_i)-Paaren in remaining_accounts für jeden Reward-Stream nach dem ersten. Die Paarungskonvention ist real, aber sie beginnt erst beim zweiten Reward-Stream: Der erste Stream’s Vault und ATA sind feste Konten, nicht nebeneinander, und nicht Teil von remaining_accounts überhaupt.

Testen eines CPI-Flows

Lokale Entwicklung erfordert, dass die Raydium-Programme in Ihrem Test-Validator verfügbar sind. Drei Optionen:
  1. anchor test mit Programm-Klon. Zieht bereitgestellte Mainnet-Bytecode in Ihren lokalen Validator; siehe Programme in einen lokalen Validator klonen unten für die Anchor.toml-Konfiguration und zwei Dinge, die speziell Pool-Erstellungs-Tests verwirren.
  2. Devnet. Raydium stellt die meisten Programme auf Devnet bereit, aber unter unterschiedlichen Programm-IDs als Mainnet für jedes Programm (CPMM, CLMM, AMM v4, Stable AMM und LaunchLab haben jeweils eine unterschiedliche Devnet-Adresse; siehe die Devnet-Tabelle in reference/program-addresses). Farm v3/v5/v6 werden nicht zuverlässig auf Devnet veröffentlicht; die Live-API (https://api-v3-devnet.raydium.io/main/info) hat das aktuelle Bild. Wenn Sie raydium_clmm’s gebündelte DEVNET_PROGRAM_ID-Konstanten verwenden (oder das Äquivalent für andere Crates), gehen Sie nicht davon aus, dass eine Mainnet-ID auch auf Devnet funktioniert. Führen Sie anchor test --provider.cluster devnet aus, um Live-Code zu treffen, sobald Sie die richtigen Adressen haben.
  3. Lokale Bereitstellung. Klonen Sie die Raydium-Repos (CPMM, CLMM; LaunchLab’s Quelle ist für diese Option nicht verfügbar) und anchor deploy zu einem lokalen Validator. Fügt Test-Zyklus-Overhead hinzu, aber lässt Sie den Aufgerufenen zum Debuggen ändern.
Führen Sie mit anchor test aus, oder anchor build zuerst und anchor test --skip-build danach, wenn Sie die Test-Datei iterieren, ohne das Programm zu ändern.

Programme in einen lokalen Validator klonen

Dies funktioniert nach Programm-ID, unabhängig davon, ob die Programmquelle öffentlich ist, daher klont LaunchLab auf die gleiche Weise wie CPMM und CLMM, obwohl seine Quelle nicht verfügbar ist. reference/program-addresses ist die Quelle der Wahrheit für jede Adresse hier.
Das Klonen des Programms reicht nicht aus, wenn Ihr Test auch einen Pool erstellt (anstatt gegen einen zu tauschen, der bereits existiert). CPMMs initialize-Instruction validiert seine amm_config- und create_pool_fee-Konten gegen echte On-Chain-Daten, daher müssen Sie diese auch klonen, oder initialize schlägt sofort fehl. Speziell für CPMM: Klonen Sie die Fee-Tier AmmConfig, die Sie möchten (holen Sie sich ihre Adresse von GET https://api-v3.raydium.io/main/cpmm-config, Index 0 ist der 0,25%-Tier) und das Fee-Receiver-Token-Konto, validiert nach exakter Adresse, nicht on-the-fly erstellt, daher muss es bereits existieren.
Ein Pool, den Ihr Test gerade erstellt hat, ist nicht sofort tauschbar. CPMMs initialize überschreibt stillschweigend eine angeforderte open_time, die nicht streng in der Zukunft liegt (if open_time <= block_timestamp { open_time = block_timestamp + 1 }), daher lässt sogar startTime: 0 („sofort öffnen”, pro SDK) eine echte ≥1-Sekunden-Lücke, bevor der Pool Swaps akzeptiert. Ein Test, der einen Pool erstellt und sofort dagegen tauscht, wird NotApproved treffen. Ein kurzes await (1–2s) zwischen Pool-Erstellung und dem ersten Swap reicht aus. Dies ist spezifisch für Tests; ein Mensch, der zwei separate manuelle Befehle ausführt, würde normalerweise nichts bemerken, da Tippen und Prozessstart bereits mehr als eine Sekunde verbrauchen.

Zeiger

Quellen: