Skip to main content
Diese Seite wurde mit KI automatisch übersetzt. Maßgeblich ist stets die englische Version.Englische Version ansehen →
Program ID und PDA-Seeds für CPMM sind kanonisch in reference/program-addresses aufgelistet. Diese Seite konzentriert sich auf wofür jedes Konto ist und welche Invarianten es aufrechterhält, nicht auf die hardcodierten Adressen.

Die sechs Konten eines CPMM-Pools

Jeder CPMM-Pool wird vollständig durch sechs programmabgeleitete Adressen (PDAs) unter dem CPMM-Programm beschrieben, plus ein gemeinsames AmmConfig-Konto, auf das er verweist. Sobald Sie die beiden Mints haben, können Sie alles deterministisch ableiten, ohne das Netzwerk zu berühren. Und die gemeinsame Konfiguration: Und ein optionales Pro-Creator-Konto:

Ableitung eines Pools aus nichts als zwei Mints

Sortieren Sie Mints immer vor der Ableitung der Pool-PDA. Der Seed hasht die beiden Mints in Byte-Reihenfolge, nicht in Benutzerreihenfolge. Zwei Pools mit (A, B) und (B, A) würden sich in der Kette kollidieren — Sortieren ist, wie das Programm die Zuordnung kanonisch macht.
Pool-ID ist nicht immer die kanonische PDA. Initialize akzeptiert einen beliebigen Unterzeichner-Keypair als pool_state zusätzlich zur obigen PDA. Wenn das übergebene Konto nicht der kanonischen PDA entspricht, erfordert das Programm, dass es ein Unterzeichner ist — d. h., der Ersteller übergibt einen neuen Keypair, den er signiert. Dies ist die Front-Run-Verteidigung: Jeder Dritte, der versucht, die kanonische PDA zu schnappen, kann vom legitimen Ersteller umgangen werden, indem stattdessen ein zufälliger Keypair verwendet wird. Die nachgelagerten PDAs (lpMint, vault0, vault1, observation) werden immer noch von poolState.key() abgeleitet, daher bleiben sie eindeutig für die verwendete Adresse. Wenn Sie Pools indizieren, entdecken Sie die Pool-ID immer aus dem On-Chain-State (z. B. PoolState-Konten unter dem CPMM-Programm), nicht durch Ableitung der kanonischen PDA — letztere werden Zufalls-Keypair-Pools übersehen.

Kontenlayouts

Die vollständigen Rust-Definitionen befinden sich in der raydium-cp-swap-Quelle. Die folgenden Felder sind diejenigen, die Sie aus einer Integration lesen werden.

PoolState

Was Sie tatsächlich lesen sollten:
  • lp_supply — das interne LP-Gesamtvolumen des Pools. Es ist nicht gleich dem Angebot des LP-Mints: es ist genau 100 Basiseinheiten höher, da die 100 gesperrten Einheiten hier gezählt werden, aber nie geprägt werden. Die gesamte LP-Share-Mathematik (Einzahlung, Auszahlung) dividiert durch lp_supply, daher verwenden Sie dieses Feld und ersetzen Sie nicht das On-Chain-Angebot des Mints.
  • protocol_fees_token{0,1}, fund_fees_token{0,1} — akkumulierte Gebühren, die noch nicht eingezogen wurden. Diese beeinflussen nicht die Swap-Preisgestaltung; sie sitzen in den Vaults, bis CollectProtocolFee / CollectFundFee aufgerufen wird. protocol_fees_token{0,1} erhält auch den Protokoll-Anteil der Creator-Gebühr, wenn eine Creator-Gebühr eingezogen wird, daher wächst sie außerhalb von Swaps — siehe products/cpmm/fees.
  • status — eine Bitmaske, die steuert, ob Swap, Deposit, Withdraw zulässig sind. Wird vom Admin über UpdatePoolStatus aktualisiert. Das SDK prüft dies vor dem Erstellen einer Transaktion; wenn Sie direkt CPI verwenden, prüfen Sie es selbst.
  • token0_program / token1_program — das Token-Programm, in das für jeden Vault CPI durchgeführt werden soll. Eines kann klassisches SPL Token und das andere Token-2022 sein; sie sind unabhängig.
  • open_time — ein Unix-Zeitstempel. Swaps vor dieser Zeit schlagen fehl. Einzahlungen sind vor open_time zulässig, damit der Pool gesät werden kann.
  • creator_fee_on / enable_creator_fee — zusammen steuern, ob die optionale Creator-Gebühr für diesen Pool aktiv ist und von welcher Seite des Swaps sie eingezogen wird. enable_creator_fee == false setzt den Creator-Fee-Pfad vollständig auf Null. Wenn aktiviert, wählt creator_fee_on: 0 = Gebühr von welchem Token auch immer der Swap-Input ist (BothToken); 1 = Gebühr nur von token_0 (überspringen bei token_1 → token_0 Swaps); 2 = Gebühr nur von token_1. Wird bei der Pool-Erstellung über InitializeWithPermission gesetzt; kann sich später nicht ändern.
  • creator_fees_token_{0,1} — akkumulierte Creator-Gebühren, eingezogen durch CollectCreatorFee oder CollectCreatorFeePermissionless. Beide Pfade setzen die vollständigen Zähler auf Null, aber seit dem Upgrade vom 2026-09-19 verlässt nur ein Teil des Saldos den Pool: Der Protokoll-Anteil wird zu protocol_fees_token_{0,1} hinzugefügt und der Rest wird an den Creator übertragen. Der erlaubnislose Pfad behebt die Empfänger auf die kanonischen ATAs von pool_creator. PoolState selbst hat sich nicht geändert — es gibt keinen separaten Zähler für den gemeinsamen Betrag.

AmmConfig

Drei Dinge, auf die Sie achten sollten:
  1. trade_fee_rate und creator_fee_rate sind Bruchteile des Volumens, beide in Einheiten von 1/1_000_000 bezeichnet. 2500 bedeutet 0,25% des Handelsvolumens. protocol_fee_rate und fund_fee_rate sind Bruchteile der Handelsgebühr (nicht des Volumens), mit demselben 1/1_000_000-Nenner. Die Creator-Gebühr ist nicht ein Bruchteil der Handelsgebühr — sie ist ihre eigene unabhängige Rate. Die vollständige Arithmetik ist in products/cpmm/fees.
  2. index ist ein u16, daher verwendet der Seed-Hash 2 Bytes Big-Endian. Ein Off-by-One bei der Byte-Reihenfolge ist ein häufiger Integrationsfehler.
  3. AmmConfig ist auf Pool-Ebene unveränderlich. Ein Pool verweist bei der Erstellung auf eine AmmConfig und wechselt nie. Gebührenänderungen werden verbreitet, da der Pool die Konfiguration bei jedem Swap liest — aber der Pool kann nicht zwischen Gebühren-Tiers verschoben werden.
Eine Anmerkung zu Creator-Gebühren: Die Rate selbst (creator_fee_rate) lebt auf AmmConfig und wird über das Gebühren-Tier geteilt. Ob ein bestimmter Pool sie tatsächlich berechnet (enable_creator_fee) und von welcher Seite des Swaps sie landet (creator_fee_on) lebt auf PoolState. Die Creator-Gebühr ist unabhängig von der Handelsgebühr — sie ist ihre eigene Rate, akkumuliert zu ihren eigenen Zählern (creator_fees_token_{0,1}), und reduziert niemals die LP-/Protokoll-/Fonds-Anteile der Handelsgebühr. Das Eintreiben erfolgt über CollectCreatorFee oder den zielgebundenen CollectCreatorFeePermissionless, und beide Pfade übergeben einen Anteil des akkumulierten Saldos an das Protokoll auf dem Weg hinaus — bei creator_fee_share_rate, oder bei der Rate auf einer CreatorFeeShare-PDA, wenn eine für das (creator, amm_config)-Paar existiert. Siehe products/cpmm/fees für die vollständige Mechanik.

Permission

Ein kleines Zugriffskontroll-Konto, das von InitializeWithPermission verwendet wird. Das CPMM-Programm unterstützt einen genehmigten Pool-Erstellungspfad, damit andere Programme (z. B. LaunchLab beim Upgrade eines Tokens zu CPMM) nachweisen können, dass sie berechtigt sind, einen Pool gegen eine bestimmte AmmConfig zu erstellen.
Die Permission-PDA wird über CreatePermissionPda von entweder dem CPMM-Admin oder einer dedizierten Permission-PDA-Creator-Autorität erstellt. Seit dem Upgrade vom 2026-09 akzeptiert ClosePermissionPda die gleichen zwei Unterzeichner; davor war es nur Admin. Endbenutzer interagieren nicht direkt mit diesem Konto — es ist Rohrleitungen für Cross-Program-Flows. Siehe security/admin-and-multisig für die Rollengrenzen und reference/program-addresses für kanonische Adressen.

CreatorFeeShare

Ein optionales Konto, das den Protokoll-Anteil der Creator-Gebühr für ein (Pool-Creator, AmmConfig)-Paar überschreibt. Hinzugefügt durch das Upgrade vom 2026-09-19 für Creator-Fee-Share.
Wie es sich verhält:
  • Es ist optional, aber das Konto ist niemals optional in der Anweisung. CollectCreatorFee und CollectCreatorFeePermissionless deklarieren beide creator_fee_share mit der obigen Seed-Einschränkung und nehmen es bei jedem Aufruf. Das Programm prüft dann, ob das Konto leer oder fremd ist; wenn ja, fällt es auf AmmConfig.creator_fee_share_rate zurück. Ein Client muss also immer die Adresse ableiten und übergeben, unabhängig davon, ob das Konto existiert oder nicht.
  • share_rate ist auf FEE_RATE_DENOMINATOR_VALUE (1_000_000) bei der Erstellung begrenzt, und erneut, wenn die Aufteilung läuft. 1_000_000 leitet die gesamte Creator-Gebühr an das Protokoll; 0 leitet keine davon.
  • Erstellt und geschlossen vom Admin oder einer dedizierten Autorität durch CreateCreatorFeeShare / CloseCreatorFeeShare. Das Schließen gibt die Miete an den Unterzeichner zurück und fällt das Paar auf den Config-Standard zurück; der Pool-Creator ist kein Unterzeichner auf beiden Pfaden.
  • Es wird auf dem Creator, nicht dem Pool, verschlüsselt. Ein Konto regelt jeden Pool, den dieser Creator auf dieser AmmConfig hat. Ein Creator mit Pools auf zwei Gebühren-Tiers benötigt zwei Konten, um auf beiden abgedeckt zu sein.
Die Aufteilungsarithmetik, die es antreibt, ist in products/cpmm/fees.

Vaults und Token-2022

vault0 und vault1 werden von der CPMM-Authority-PDA besessen, und ihr Token-Programm-Besitzer (token_program) ist entweder SPL Token oder Token-2022, bestimmt bei der Pool-Erstellung durch das Mint-Programm. Der Pool behandelt die beiden Fälle transparent — Sie übergeben die richtige Token-Programm-ID für jede Seite in den Swap / Deposit / Withdraw-Anweisungskonten. CPMM erzwingt eine strikte Erweiterungs-Zulassungsliste bei der Pool-Erstellung (is_supported_mint in utils/token.rs). Ein Token-2022-Mint kann in einem CPMM-Pool verwendet werden, nur wenn jede Erweiterung, die er trägt, auf dieser Liste ist:
  • TransferFeeConfig. Angewendet vom Mint bei jedem Transfer. Der Pool ist auf der Empfängerseite für SwapBaseInput-Einzahlungen und auf der Senderseite für Auszahlungen. Das Programm berechnet den Netto-Betrag, der im Vault landet, und setzt die Kurve entsprechend. Siehe algorithms/token-2022-transfer-fees.
  • MetadataPointer und TokenMetadata. Standard-On-Mint-Metadaten. Keine Auswirkung auf die Swap-Mathematik.
  • InterestBearingConfig. Der UI-Betrag des Mints sammelt Zinsen. Der Vault speichert Rohbeträge; die Kurve arbeitet nur mit Rohbeträgen. UIs, die APR anzeigen, sollten die Token-2022-Helfer aufrufen, um den UI-Betrag zu rendern.
  • ScaledUiAmount. UI-Display-Skalierungserweiterung. Gleiche Behandlung wie InterestBearingConfig — die Kurve verwendet Rohbeträge.
Jede andere Erweiterung — PermanentDelegate, TransferHook, DefaultAccountState, NonTransferable, ConfidentialTransfer, Group/GroupMember, MintCloseAuthority, usw. — führt dazu, dass Initialize mit NotSupportMint ablehnt. Die eine Ausnahme ist eine Pro-Mint-Registrierung: Wenn eine SupportMintAssociated-PDA bei Seed [b"support_mint", mint] existiert, wird der Mint unabhängig von seinem Erweiterungssatz zugelassen. Diese PDA wird vom Admin (oder einer dedizierten Support-Mint-Autorität) über CreateSupportMintAssociated / CloseSupportMintAssociated erstellt und entfernt, daher benötigt das Onboarding eines bestimmten Mints kein Programm-Upgrade mehr.
Geändert in 2026-09. CPMM trug zuvor auch eine hardcodierte vier-Adressen-MINT_WHITELIST, die die Erweiterungsprüfung kurzschloss. Dieses Array wurde entfernt; die Registrierungs-PDA ist jetzt der einzige Bypass. Jeder Mint, der sich auf die hardcodierte Liste verließ, benötigt eine SupportMintAssociated-PDA, bevor ein neuer Pool dafür erstellt werden kann — bestehende Pools sind nicht betroffen, da die Prüfung nur bei der Pool-Erstellung läuft.
Die geprüfte Erweiterungsliste lebt in der CP-Swap-Quelle unter programs/cp-swap/src/utils/token.rs und kann sich mit zukünftigen Programm-Upgrades ändern. Siehe reference/token-2022-support für die Cross-Program-Matrix.

Observation

Das Observation-Konto ist ein Ringpuffer von ObservationState-Einträgen, die jeweils einen block_timestamp und einen kumulativen Preis speichern. Bei jedem Swap hängt das Programm eine neue Observation an, wenn genug Zeit seit der letzten vergangen ist. TWAPs werden berechnet, indem zwei Observations gelesen und Δcumulative / Δtime dividiert werden.
Der Ringpuffer ist für 100 Observations dimensioniert. Jede Observation ist 40 Bytes (8 + 16 + 16), daher ist das Array allein 4.000 Bytes; ObservationState::LEN ist genau 4.075 Bytes (8 + 1 + 2 + 32 + 4.000 + 8 × 4). Zwei Verbraucherregeln:
  • Verwenden Sie nicht eine einzelne Observation als Preis. Es ist ein kumulativ, kein Spot-Preis. Verwenden Sie zwei davon, um einen TWAP zu berechnen.
  • Wählen Sie Observations mindestens einen Block auseinander. Swaps innerhalb desselben Blocks können keine neue Observation erzeugen; das Zurücklesen kann denselben Datensatz zurückgeben.
Mehr Mathematik in products/clmm/accounts.

Kontenlebenszyklus

CPMM-Pools und ihre PDAs werden nie geschlossen. Permission, SupportMintAssociated und CreatorFeeShare sind die Ausnahmen — sie sind eigenständige Admin-verwaltete Datensätze, keine Pool-State, und jeder hat eine explizite Close-Anweisung. Selbst bei Null-Liquidität bleibt poolState bestehen. Dies ist beabsichtigt: Das erneute Seeding desselben Pools später bewahrt seinen historischen Observation-Puffer und seine PDA-Ableitung bleibt stabil.

Was wo zu lesen ist

Quellen: