Skip to main content
Diese Seite wurde mit KI automatisch übersetzt. Maßgeblich ist stets die englische Version.Englische Version ansehen →
PDAs (Program-Derived Addresses) und CPIs (Cross-Program Invocation) sind die zwei Primitiven, die Raydium möglich machen. PDAs ermöglichen es einem Programm, deterministische Adressen zu „besitzen”, ohne private Schlüssel — so funktionieren Pool-Autoritäten und Vaults. CPIs ermöglichen es einem Programm, ein anderes aufzurufen — so tauscht Raydium Token über das SPL Token-Programm aus und wie Integratoren Raydium in ihre eigenen Flows komponieren. Beide sind es wert, verstanden zu werden, bevor Sie Raydiums Quellcode lesen.

PDAs: Adressen ohne Schlüssel

Eine Program-Derived Address ist ein öffentlicher Schlüssel, der:
  • Nicht auf der ed25519-Kurve liegt (es existiert kein privater Schlüssel dafür).
  • Deterministisch aus einer Programm-ID und einer Reihe von Seeds abgeleitet wird.
  • Nur vom Ableitungsprogramm signiert werden kann, über invoke_signed.
Jede Raydium-Pool-Autorität, jedes Pool-State-Konto, jeder Vault, jeder Farm-State — sie sind alle PDAs.

Ableitung

Eine PDA wird berechnet, indem die Programm-ID mit den Seeds gehasht wird, dann wird ein „Bump”-Byte gefunden, das das Ergebnis von der Kurve weg zwingt. Der erste Bump (typischerweise beginnend bei 255 und abnehmend), der eine Off-Curve-Adresse erzeugt, gewinnt; dies ist der kanonische Bump.
Die Seeds können alles sein — Strings, andere Pubkeys, u64-Werte als Little-Endian-Bytes. Raydiums Konvention ist ein menschenlesbares Präfix gefolgt von eindeutigen Identifikatoren.

Raydium PDA-Muster

Häufige PDAs in Raydiums Programmen: Benutzer und Integratoren können diese berechnen, ohne etwas zu fetchen — gegeben die öffentlichen Eingaben (Pool-ID, Farm-ID, Benutzerschlüssel), ist die PDA deterministisch.

Kanonischer Bump

Obwohl es prinzipiell mehrere Bumps geben kann, die Off-Curve-Adressen erzeugen, verwenden Raydiums Programme immer den kanonischen Bump (gefunden durch Abnehmung von 255). Dieser wird in den Kontodaten der PDA gespeichert, damit nachfolgende Transaktionen ihn übergeben können und die (teure) Ableitungsschleife überspringen:
(CLMMs PoolState speichert stattdessen bump: [u8; 1], also überprüfen Sie die Struktur des spezifischen Programms, anstatt eine Form anzunehmen.) Bei nachfolgenden Transaktionen wird der Bump aus dem Pool-State gelesen, anstatt neu berechnet zu werden.

CPIs: andere Programme aufrufen

Cross-Program Invocation ermöglicht es einem Programm, die Anweisungen eines anderen Programms inline innerhalb einer einzelnen Transaktion aufzurufen. Raydium nutzt CPIs umfangreich:
  • Swap-Anweisungen rufen das SPL Token-Programm auf, um Token zu verschieben.
  • CLMM ruft Metaplex auf, um die Position-NFT zu prägen.
  • Pool-Erstellung ruft das System-Programm auf, um Konten zuzuweisen.
  • Farm v6 ruft SPL Token auf, um Belohnungen zu übertragen.
Integratoren nutzen auch CPIs, um in Raydium aufzurufen — so funktionieren Vault-Strategien, Leveraged-LP-Protokolle und Auto-Compounder. Siehe integration-guides/cpi-integration.

invoke vs invoke_signed

Die Solana-Runtime bietet zwei CPI-Primitive:
  • invoke: ruft ein anderes Programm auf; das aufgerufene Programm erbt die Unterzeichner der äußeren Transaktion.
  • invoke_signed: ruft ein anderes Programm im Namen einer PDA auf; die Runtime verifiziert die Seeds der PDA und autorisiert die Signatur.
invoke_signed ist die Magie, die es Programmen ermöglicht, Autorität über Konten zu halten, ohne private Schlüssel zu verwalten.

Beispiel: Raydium überträgt aus einem Pool-Vault

Ein Pool-Vault ist ein Token-Konto, dessen Autorität eine PDA des Pool-Programms ist. Um Token während eines Swaps zu übertragen, muss das Pool-Programm als diese PDA signieren:
Die Runtime sieht, dass invoke_signed vom CPMM-Programm aufgerufen wird, verifiziert, dass vault_and_lp_mint_auth_seed + bump zu der Adresse von pool_authority abgeleitet wird, wenn es mit der CPMM-Programm-ID gehasht wird, und erlaubt die Autoritätssignatur auf der Token-Übertragung. Kein privater Schlüssel beteiligt.

Beispiel: Integrator ruft Raydium CPMM auf

Ein Integrator-Programm (z. B. ein Escrow) kann Raydiums swap_base_input über CPI aufrufen:
Dies ist das kanonische Integrationsmuster — siehe integration-guides/cpi-integration für das vollständige Escrow-Beispiel.

CPI-Tiefenlimit

Solana begrenzt die CPI-Tiefe auf 4 Ebenen. Die Top-Level-Anweisung einer Transaktion zählt als Tiefe 0; jeder CPI-Aufruf erhöht die Tiefe. Praktische Auswirkung: Raydiums eigener Swap nutzt bereits 1–2 Ebenen von CPI (Raydium → SPL Token). Ein Integrator, der Raydium aufruft, nutzt 2. Wenn dieser Integrator von einem anderen Integrator aufgerufen wird, sind es 3. Die 4. Ebene ist das Limit. Die meisten Kompositionen bleiben leicht darunter, aber tiefe Verschachtelung (Aggregator → Router → Raydium → Hook) kann es treffen. Entwerfen Sie flach statt tief.

Verbleibende Konten

Wenn eine Raydium-Anweisung eine variable Anzahl von Konten benötigt (z. B. CLMM-Swap, der eine unbekannte Anzahl von Tick-Arrays kreuzt), werden die zusätzlichen Konten als verbleibende Konten übergeben — an die Liste der festen Konten angehängt, interpretiert nach Position. CPMMs SwapV2 nutzt verbleibende Konten für zusätzlich erforderliche Konten von Transfer-Hook-Programmen. Clients fetchen die benötigten Konten und hängen sie an:
Auf der CPI-Ebene müssen Integratoren verbleibende Konten durch ihre eigene Anweisung weiterleiten:

PDA-Fallstricke

Falsche Seeds → falsche Adresse

Ein Bug, bei dem Seeds in der falschen Reihenfolge, falscher Kodierung oder mit/ohne ein zusätzliches Byte sind, erzeugt stillschweigend eine andere PDA. Die Transaktion schlägt mehrdeutig fehl (das Programm versucht, ein Konto zu lesen, das nicht existiert). Testen Sie die Seed-Ableitung immer gegen bekannte Golden Values.

Bump nicht speichern

Wenn Sie den Bump bei jeder Transaktion neu ableiten, zahlen Sie Compute für die Ableitungsschleife. Speichern Sie den kanonischen Bump in den Daten der PDA und lesen Sie ihn von dort.

Verwechslung von kanonischem und nicht-kanonischem Bump

Nicht-kanonische Bumps (falls jemand einen findet, der Off-Curve ergibt) sind von invoke_signed erlaubt, aber von Raydiums Programmen über assert_eq!(bump, canonical_bump) abgelehnt. Wenn jemand versucht, eine PDA mit einem nicht-kanonischen Bump zu beanspruchen, schlägt die Tx fehl.

Übergabe einer PDA als Unterzeichner, wenn Sie nicht das besitzende Programm sind

Nur das Programm, dessen ID in der PDA-Ableitung ist, kann invoke_signed mit seinen Seeds aufrufen. Wenn Sie es versuchen, lehnt die Runtime ab.

CPI-Fallstricke

Vergessen, remaining_accounts weiterzuleiten

Wenn Ihre äußere Anweisung Transfer-Hook-Konten in remaining_accounts übergibt, aber der CPI in Raydium sie nicht weiterleitet, schlägt Raydium fehl, weil es die Hook-Konten nicht finden kann. Fügen Sie immer with_remaining_accounts in CPIs ein, die sie benötigen.

Schreibbare Flags stimmen nicht überein

Ein Konto, das die äußere Anweisung als schreibbar markiert, muss auch im CPI-Aufruf schreibbar sein, wenn das aufgerufene Programm beabsichtigt, es zu schreiben. Nichtübereinstimmung → Runtime-Ablehnung.

Miete nicht berücksichtigen

CPI zu einem Programm, das ein Konto erstellt (z. B. ATA-Erstellung), erfordert, dass der Zahler genug SOL für Miete hat. Fehlgeschlagene Mietprüfungen erscheinen als obskure Fehler.

Durchgearbeitetes Beispiel: Berechnung von Raydium CPMM PDAs

Dies ist genau das, was Raydium SDK unter der Haube tut, wenn Sie getPoolInfoFromRpc({ poolId }) aufrufen — es leitet die zugehörigen PDAs ohne Round-Trip ab.

Verweise

Quellen: