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 zunächst das allgemeine Muster, dann springen Sie zum Abschnitt Ihres Programms für die Kontoliste und eventuelle 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 gleichwertig mit raydium-cp-swap beim Auflösen einer Git-Abhängigkeit.
branch = "master" verfolgt die neueste veröffentlichte Quelle; fixieren Sie einen spezifischen rev = "<commit>", wenn Sie einen reproduzierbaren Build benötigen. Dies wird empfohlen, sobald Sie über die Prototyping-Phase hinaus sind, da eine Upstream-Kontostruktur-Änderung auf master Ihren Build ohne Warnung bricht. Das cpi-Feature-Flag lässt die Crates nur zur CPI-Oberfläche (Kontostrukturen + Invoker) kompilieren, statt zum vollständigen Programm, sodass Ihre Binärdatei klein bleibt. anchor-lang / anchor-spl müssen dem entsprechen, was das Ziel-Crate fixiert:
Nehmen Sie beide Crates aus der gleichen Anchor-Linie. Beide master-Branches fixieren =1.0.2, daher kann ein Programm von einem einzigen Crate aus in CPMM und CLMM aufrufen. Das Mischen von Linien bricht den Build: zum Beispiel raydium-cp-swap auf master mit raydium-clmm fixiert auf einen rev von vor seinem Anchor-1.0-Upgrade. 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 verzichten Sie auf das typisierte CPI-Crate für eine Seite und kodieren Sie diese Anweisung manuell (das für AMM v4 gezeigte Muster funktioniert für jedes Programm).
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 exportiert seine Helfer aus dem neuen spl-associated-token-account-interface-Crate neu. get_associated_token_address und ID sind immer noch an der Crate-Wurzel (spl_associated_token_account::{get_associated_token_address, ID}) erreichbar, 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 führt Sie CPMM von Anfang bis Ende durch als praktisches Beispiel: Accounts-Struct, CpiContext, cpi::<ix>(). CLMM folgt der identischen Struktur, 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 Struktur. Lesen Sie stattdessen den jeweiligen Abschnitt jedes Programms, anstatt anzunehmen, dass die Kontoliste aus dieser Anleitung direkt übertragbar ist.

Konstruktion der Kontoliste

Jeder Raydium-CPI erfordert einen Accounts-Struct im aufrufenden Programm. Seine Felder sind alle Konten, die Ihre Anweisung benötigt, mit Validatoren auf Feldebene; ihre Deklarationsreihenfolge muss nicht mit Raydiums eigener Anweisungskontoreihenfolge ü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 übernimmt. Ihr aufruferendes Programm validiert nur streng Konten, die Sie besitzen, wie Benutzer-ATAs und Ihre eigenen PDAs. Der /// CHECK:-Dokumentationskommentar unterdrückt Anchors Warnung über fehlende Überprüfungen. Die eine Raydium-seitige Ausnahme ist cpmm_program selbst: Es ist das aufgerufene Programm und nicht ein Datenkonto, das Raydium intern validiert, daher wird es als Program<T> typisiert und erhält Anchors automatische Adressprüfung statt einer manuellen /// CHECK:. Diese überwiegend UncheckedAccount-Struktur, 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 im CPI-Aufruf unten als input_token_program/output_token_program dieser Seite statt token_program.

Aufbau des CPI-Aufrufs

Anchor generiert einen Helper pro Anweisung zusammen mit einem CPI-Accounts-Struct (cpi::accounts::Swap, unten als CpmmSwap aliasiert). Im Gegensatz zu Ihrem eigenen MyProxySwap-Struct oben sind die Feldnamen und die Reihenfolge dieses Structs durch raydium-cp-swaps eigenes IDL festgelegt und müssen genau übereinstimmen:
cpi::swap_base_input wird aus dem IDL generiert; seine Argumentliste spiegelt die Argumentliste der Anchor-Anweisung wider. Jedes bestätigte Anchor-basierte Raydium-Programm (CPMM, CLMM, LaunchLab) generiert seine cpi::<ix>()-Helper auf die gleiche Weise, wobei der Funktionsname dem Anweisungsnamen in Snake-Case entspricht. Ob dies auf Farm v6 zutrifft, ist unbestätigt; siehe dessen Abschnitt.

Signer-Seeds (PDA-signierter CPI)

Wenn Ihr Programm den CPI im Namen einer PDA signiert (häufig bei Vaults, Escrows usw.), verwenden Sie CpiContext::new_with_signer:
Die Signer-Seeds müssen mit der Ableitung der PDA übereinstimmen. 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-Anweisungen nehmen verbleibende Konten an, eine Liste variabler Länge, die nach den festen Konten angehängt wird. Anchors CPI-Helper 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 die verbleibenden Konten in der Reihenfolge durchläuft, in der Sie sie übergeben. Zwei bestätigte Ordnungen:
  • CLMM SwapV2: Tick-Arrays, in Richtungsreihenfolge.
  • Farm v6: (reward_vault, user_reward_ata)-Paare, aber nur ab dem zweiten Reward-Stream an; siehe Farm v6 für das, was die Dekodierung 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 Modul #[program] der Crate heißt raydium_clmm, was auch sein Rust-use-Pfad ist.
Der CPI-Accounts-Struct heißt SwapSingleV2, nicht SwapV2. SwapV2 ist der On-Chain-Anweisungsname.
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-Walks: erstes Array in Swap-Richtung zuerst.

Das Muster anwenden: LaunchLab

LaunchLab basiert auf Anchor und veröffentlicht ein IDL: raydium_launchpad/raydium_launchpad.json im öffentlichen Repository raydium-idl. Der interne Metadaten-Identifikator dieses IDL ist raydium_launchpad, ein technischer Name für das zugrunde liegende Programm, nicht ein alternativer Name für das Produkt. Anders als bei CPMM und CLMM ist jedoch der Quellcode des Programms selbst nicht öffentlich verfügbar (siehe reference/program-addresses). Es gibt keine git = "..." Abhängigkeit für Cargo und keinen Quellcode, um zu bestätigen, welcher Rust use-Pfad einer echten Crate entsprechen würde. Generieren Sie Bindings aus dem veröffentlichten IDL mit Anchors declare_program! Makro. Speichern Sie die IDL-JSON als idls/raydium_launchpad.json in Ihrer Crate (Cargo sucht nach einem idls/ Verzeichnis relativ zu CARGO_MANIFEST_DIR), dann generiert declare_program!(raydium_launchpad); die Structs raydium_launchpad::cpi::accounts::<Ix> und Funktionen cpi::<ix>() direkt aus dem IDL, ohne Programmquellcode erforderlich. Der generierte Name der Accounts-Struktur ist immer der Instruktionsname in PascalCase (buy_exact_in → BuyExactIn), und die Feldnamen entsprechen exakt den Kontonamen des IDL, derselben 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-Instruktion buy_exact_in, nicht aus products/launchlab/instructions.mdx:
Nach der Graduierung ist das Zielprogramm CPMM oder AMM v4, abhängig von pool_state.migrate_type, das laut products/launchlab/accounts.mdx zur Zeit von Initialize gesetzt wird. Ihre CPI-Kontoliste muss für beide vorbereitet sein, oder Sie müssen migrate_type zuerst aus PoolState auslesen und verzweigen.

Fehlerbehandlung

Jedes Anchor-basierte Raydium-Programm gibt seine eigene Error-Enum zurück; Anchor umhüllt sie, sodass Ihr aufruferendes Programm sie als Err(ProgramError::Custom(code)) sieht. Um spezifische Fehler zu behandeln:
Ersetzen Sie den relevanten Error-Typ für das Programm, das Sie aufrufen (raydium_clmm::error::ErrorCode für CLMM usw.). Fehlercodes sind stabil gemäß der IDL-Richtlinie (sdk-api/anchor-idl), sodass Sie gegen spezifische Codes testen können, indem Sie gegen den numerischen Wert vergleichen. Vollständige Fehlertabellen: CPMM, CLMM, AMM v4, Farm v6 und LaunchLab.

Compute-Budget in zusammengesetzten CPIs

Jeder CPI-Frame hat Overhead, und der eigene CU-Verbrauch des aufgerufenen Programms addiert sich zu Ihrem, daher benötigt eine Transaktion, die von innerhalb Ihres Programms in Raydium aufruft, ein explizites Compute-Budget, anstatt sich auf das Standard-Limit von 200k CU zu verlassen.
Gemessen, nicht geschätzt. Ein CPMM swap_base_input im Mainnet verbraucht ~23.000 CU im CPMM-Programm selbst — gemessen am 2026-09-09 über acht Live-Swaps in einem hochvolumigen Pool (22.721–23.052), gelesen aus der Log-Zeile Program CPMMoo8… consumed N of M compute units. 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 Version dieser Seite meldete ~47.700 CU für einen Proxy-Swap CPI. Diese Zahl war die ganze Transaktion (computeUnitsConsumed), die das eigene Programm des Aufrufers, den CPI-Frame und jedes ATA-Setup umfasst — nicht die Kosten des aufgerufenen Programms. Beide sind nützlich, aber es sind nicht dieselben Zahlen, daher vergleichen Sie Gleiches mit Gleichem. Messen Sie Ihre eigene Transaktion, anstatt nach einer Zahl aus der Dokumentation zu budgetieren, da das Standard-Limit von 200k CU stillschweigend erschöpft wird und die Pro-Instruktions-Kosten sich verschieben, wenn Programme aktualisiert werden.
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 obige CPMM-Zahl ist ein gemessener Wert. Setzen Sie immer ein explizites ComputeBudgetProgram::set_compute_unit_limit(...) Instruktion, die auf Ihrer eigenen Messung basiert, nicht auf einer Zahl, die aus der Dokumentation kopiert wurde, da das Standard-Limit von 200k CU stillschweigend erschöpft wird und sich die Pro-Instruktions-Kosten verschieben, wenn Programme aktualisiert werden.

AMM v4: manuelle Instruction-Konstruktion

AMM v4 stammt aus der Zeit vor Anchor und hat keine CPI-Crate, was es zum einzigen Programm in dieser Dokumentation macht, das nicht dem allgemeinen Muster oben folgt. Bauen Sie die Instruction von Hand:
Siehe products/amm-v4/code-demos für die vollständige Kontoliste.

Farm v6

Verwenden Sie das TS SDK, wenn das für Ihre Integration eine Option ist. raydium.farm.deposit(...) (siehe products/farm-staking/code-demos) wird durch echte Demos ausgeübt und hängt nicht davon ab, ob eine Rust Anchor-Crate für dieses Programm existiert.
Farm v6 bietet keinen Anchor CPI-Pfad. Es gibt keine raydium_farm_v6 Crate auf crates.io, kein öffentliches Quellcode-Repository und kein 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 Instruktionen von Hand, wie unten.
Wenn Sie trotzdem Rust CPI benötigen, zum Beispiel um von einem anderen On-Chain-Programm zu komponieren, bauen Sie die Instruction von Hand, auf die gleiche Weise wie AMM v4: leiten Sie die echte Kontoliste und Instruktions-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 Instruktionsform ohne Argumente, die mit einem Harvest- oder Claim-Aufruf konsistent ist, ist die echte Kontenreihenfolge ein festes Präfix (token_program, das State-Konto der Farm, 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: die Vault und ATA des ersten Streams sind feste Konten, nicht nebeneinander, und nicht Teil von remaining_accounts überhaupt.

Testen eines CPI-Flows

Für die lokale Entwicklung müssen die Raydium-Programme in Ihrem Test-Validator verfügbar sein. Es gibt drei Optionen:
  1. anchor test mit Program Clone. Zieht den bereitgestellten 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 bei Pool-Erstellungstests zu Problemen führen.
  2. Devnet. Raydium stellt die meisten Programme auf Devnet bereit, aber unter unterschiedlichen Program IDs als auf Mainnet für jedes Programm (CPMM, CLMM, AMM v4, Stable AMM und LaunchLab haben jeweils eine eigene 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) zeigt das aktuelle Bild. Wenn Sie die gebündelten DEVNET_PROGRAM_ID-Konstanten von raydium_clmm 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 testen, sobald Sie die richtigen Adressen haben.
  3. Lokale Bereitstellung. Klonen Sie die Raydium-Repositories (CPMM, CLMM; LaunchLabs Quellcode ist für diese Option nicht verfügbar) und führen Sie anchor deploy auf einem lokalen Validator aus. Dies erhöht den Test-Zyklus-Overhead, ermöglicht es Ihnen aber, den aufgerufenen Code zum Debuggen zu ändern.
Führen Sie anchor test aus, oder führen Sie zuerst anchor build und dann anchor test --skip-build aus, wenn Sie die Test-Datei iterieren, ohne das Programm zu ändern.

Programme in einen lokalen Validator klonen

Dies funktioniert unabhängig von der Program ID, unabhängig davon, ob der Quellcode des Programms öffentlich ist oder nicht. LaunchLab wird daher auf die gleiche Weise geklont wie CPMM und CLMM, obwohl sein Quellcode nicht verfügbar ist. reference/program-addresses ist die maßgebliche Quelle für jede Adresse hier.
Das Klonen des Programms reicht nicht aus, wenn Ihr Test auch einen Pool erstellt (anstatt gegen einen bereits existierenden zu tauschen). CPMMs initialize-Anweisung validiert seine amm_config- und create_pool_fee-Konten gegen echte On-Chain-Daten, daher müssen Sie diese auch klonen, sonst schlägt initialize direkt fehl. Speziell für CPMM: Klonen Sie die Gebühren-Tier-AmmConfig, die Sie möchten (rufen Sie ihre Adresse von GET https://api-v3.raydium.io/main/cpmm-config ab, Index 0 ist die 0,25%-Tier) und das Gebühren-Empfänger-Token-Konto, das nach exakter Adresse validiert wird, nicht spontan 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 hinterlässt selbst startTime: 0 („sofort öffnen”, gemäß SDK) eine echte Lücke von ≥1 Sekunde, bevor der Pool Swaps akzeptiert. Ein Test, der einen Pool erstellt und sofort dagegen tauscht, trifft auf NotApproved. 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 dies normalerweise nicht bemerken, da Tippen und Prozessstart bereits mehr als eine Sekunde verbrauchen.

Hinweise

Quellen: