Skip to main content
Diese Seite wurde mit KI automatisch übersetzt. Maßgeblich ist stets die englische Version.Englische Version ansehen →
Diese Seite beschreibt das Layout und die Rolle jedes Kontos. Seeds sind kanonisch und in reference/program-addresses aufgelistet. Ein CLMM-Pool ist kontointensiver als ein CPMM-Pool, da Liquidität spärlich über den Tick-Bereich verteilt ist; das Verständnis dieser Spärlichkeit ist der Kern dieser Seite.

Kontobestand

Ein aktiver CLMM-Pool wird durch die folgenden Kontofamilien beschrieben. Alle werden vom CLMM-Programm verwaltet, außer den beiden Mints und ihren Vaults.

PoolState

Der Live-Status des Pools, gelesen bei jedem Swap und jeder Positionsänderung.
Felder, die Sie tatsächlich verwenden werden:
  • sqrt_price_x64 und tick_current sind der Preisstatus des Pools. Sie werden bei jedem Swap zusammen aktualisiert. tick_current ist die Untergrenze von log_{1.0001}(price).
  • liquidity ist die aktive Liquidität — die Summe der L-Werte für alle Positionen, deren Bereich tick_current enthält. Sie ändert sich jedes Mal, wenn ein Swap einen Tick kreuzt, und jedes Mal, wenn eine Position geöffnet/geschlossen/angepasst wird.
  • fee_growth_global_{0,1}_x64 sind die kumulativen Gebühren pro Liquiditätseinheit über die gesamte Pool-Historie. Positionen lesen dies, um zu berechnen, was ihnen geschuldet wird.
  • tick_spacing ist bei der Initialisierung an die AmmConfig gebunden und ändert sich nie. Es bestimmt, welche Tick-Indizes als Positionsendpunkte zulässig sind.
  • tick_array_bitmap ist eine Inline-Bitmap, die den häufig verwendeten Tick-Bereich um den Spotpreis abdeckt. Für Pools, deren Positionen weit reichen, lebt die Overflow-Verfolgung in der separaten TickArrayBitmapExtension.
  • fee_on ist bei der Pool-Erstellung festgelegt. 0 (FromInput) reproduziert das klassische Uniswap-V3-Verhalten. 1 und 2 leiten die Swap-Gebühr auf eine einzelne Seite des Buches — siehe products/clmm/fees für Abwägungen.
  • seed_index ist [0, 0] für jeden Pool, der über CreatePool / CreateCustomizablePool erstellt wird (ein kanonischer Pool pro Paar). Ein nicht-null Wert bedeutet, dass der Pool über CreateCustomizablePoolV2 (vor 2026-10-22 CreatePermissionedPool genannt) erstellt wurde und der Index Teil der Pool-PDA-Seeds ist, was mehrere Pools für dasselbe (config, mint0, mint1) ermöglicht. Um die Adresse eines solchen Pools erneut abzuleiten, müssen Sie seinen seed_index kennen.
  • dynamic_fee_info trägt Volatilitätsstatus für den dynamischen Gebührenzuschlag. Wenn aktiviert, berechnet jeder Swap eine dynamic_fee_component zusätzlich zu AmmConfig.trade_fee_rate neu. Das Layout ist unter DynamicFeeInfo unten dokumentiert; Pools ohne dynamische Gebühr lassen die gesamte Struktur null.

AmmConfig

Seit dem Upgrade von 2026-09 schreibt CreateAmmConfig die hardcodierte protocol_fee_owner::ID des Programms in owner und fund_fee_owner::ID in fund_owner. Davor kopierte es den Schlüssel des Admin-Signers in beide. Bestehende Konfigurationen behalten, was sie erstellt oder rotiert wurden, also lesen Sie beide Felder vom Konto. UpdateAmmConfig-Parameter 3 / 4 rotieren sie immer noch. Adressen sind in reference/program-addresses aufgelistet. Ein typischer veröffentlichter Satz von CLMM-Gebührentiers (bestätigen Sie gegen GET https://api-v3.raydium.io/main/clmm-config): protocol_fee_rate und fund_fee_rate sind Anteile der Handelsgebühr; gleiche Konvention wie CPMM. Siehe products/clmm/fees.

TickArrayState

CLMM speichert nicht einen einzelnen Datensatz pro Tick. Das würde Milliarden von Konten bedeuten. Stattdessen gruppiert es TICK_ARRAY_SIZE benachbarte initialisierte oder nicht initialisierte Ticks (typischerweise 60 oder 88, je nach Programmversion) in einen TickArrayState, der bei der ersten Verwendung lazy erstellt wird.
Die vier Limit-Order-Felder sind null auf jedem Tick, der noch nie für eine Limit-Order verwendet wurde. Wenn Orders auf einem Tick eröffnet werden, verfolgt das Programm sie als eine Sequenz von Kohorten:
  • order_phase ist die Kohorten-ID. Sie erhöht sich jedes Mal, wenn eine Kohorte von „vollständig ungefüllt” zu „teilweise gefüllt” übergeht.
  • orders_amount ist die Input-Token-Summe der aktuellen (neuesten) Kohorte.
  • part_filled_orders_remaining verfolgt die vorherige Kohorte, die derzeit durch laufende Swaps gefüllt wird.
  • unfilled_ratio_x64 ist ein Q64.64-Multiplikator, der auf der Kohorte gespeichert wird: Wenn ein Swap X% der Kohorte füllt, wird das Verhältnis mit (1 − X) multipliziert. Jede offene Order speichert ihren eigenen (order_phase, unfilled_ratio_x64)-Snapshot zum Zeitpunkt der Eröffnung, sodass die Settle-Mathematik auf den Vergleich von Snapshots reduziert wird.
Regeln:
  • Ein Positions-Endpunkt-Tick t muss t % tick_spacing == 0 erfüllen. Das Programm lehnt Positionen mit falscher Abstände ab.
  • Das Array des Ticks befindet sich unter floor(t / (TICK_ARRAY_SIZE * tick_spacing)) * (TICK_ARRAY_SIZE * tick_spacing).
  • Ein Tick-Array wird lazy initialisiert: Die erste Position oder der erste Swap, der ein nicht initialisiertes Array berührt, erstellt es und zahlt die Miete.
  • Ein Tick-Array wird vom Programm nie geschlossen. Nach der Zuweisung bleibt es für die Lebensdauer des Pools bestehen, auch nachdem jeder Tick darin zu liquidity_gross == 0 zurückgekehrt ist. Nachfolgende Positionen und Swaps verwenden das vorhandene Konto ohne zusätzliche Miete wieder. Es gibt keinen ClosePosition-gesteuerten Bereinigungspfad für Tick-Arrays.

TickArrayBitmapExtension

PoolState.tick_array_bitmap (inline) deckt den „nahe am Spot”-Bereich ab — ±512 Tick-Arrays (TICK_ARRAY_BITMAP_SIZE = 512; das [u64; 16]-Feld ist 1.024 Bits, gleichmäßig zwischen negativen und positiven Start-Indizes aufgeteilt, also Array-Indizes −512 … +511). Außerhalb dieses Bereichs (für extreme Tick-Werte) verwaltet das Programm ein Erweiterungskonto:
Wenn der Bereich Ihrer Position „normal” ist, denken Sie nie über das Erweiterungskonto nach. Full-Range-Positionen (z. B. (MIN_TICK, MAX_TICK)) erfordern es; das SDK löst es für Sie auf.

Positionen

Eine CLMM-Position ist ein Bündel aus drei Konten plus einem Mint:

Position-NFT-Mint

Ein SPL-Token oder Token-2022-Mint mit Supply 1. Das Position-NFT in der Wallet des Besitzers ist ein ATA, das diesen einzelnen Token hält. Das Programm bindet die Autorisierung an den aktuellen Inhaber des NFT-ATA-Guthabens, nicht an einen in der State gespeicherten Pubkey. Neue Position-NFT-Mints setzen pool_state als ihre Freeze-Authority, bevor sie den einzelnen Token prägen und die Mint-Authority entfernen. Das Setzen einer Freeze-Authority friert das NFT-Konto nicht selbst ein. Das Konto bleibt ungefroren und übertragbar, es sei denn, beide Bedingungen sind erfüllt: Der Aufrufer verwendet OpenPositionV2 oder OpenPositionWithToken22Nft, und mindestens eine zugrunde liegende Vault-Mint-Freeze-Authority erscheint auf CLMMs Restricted-Issuer-Liste. Nur dann friert CLMM das NFT-Konto nach dem Prägen ein. Dies ändert keine PersonalPositionState- oder PoolState-Bytes.

PersonalPositionState

Eines pro offene Position. Basierend auf dem NFT-Mint.

ProtocolPositionState (veraltet)

Ältere CLMM-Versionen speicherten aggregierte Pro-(pool, tick_lower, tick_upper)-Buchführung in einem ProtocolPositionState-PDA. Neuere Versionen erstellen oder lesen dieses Konto nicht mehr. Der Slot erscheint immer noch in den OpenPosition- / IncreaseLiquidity- / DecreaseLiquidity-Kontolisten als UncheckedAccount für ABI-Kompatibilität, aber das Programm schreibt nicht darauf. Vorhandene Konten in der Chain sind vestigial; der Admin kann CloseProtocolPosition aufrufen, um die Miete dafür zurückzufordern.Die aggregierte Bereichsbuchführung wird jetzt direkt aus den zwei Endpunkt-Ticks (liquidity_gross, liquidity_net und den Pro-Tick-fee_growth_outside_* / reward_growths_outside_x64) in TickArrayState abgeleitet. Die Fee-Growth-Inside-Formel fee_growth_inside = global − outside_lower − outside_upper funktioniert weiterhin ohne ein aggregiertes Positions-Konto.

Observation

CLMMs Observation-Buffer speichert einen kumulativen Tick, keinen kumulativen Preis. Externe Consumer berechnen den geometrischen Mittelpreis über ein Intervall aus (tick_cumulative[t1] − tick_cumulative[t0]) / (t1 − t0) und dann price = 1.0001 ** tick. Siehe algorithms/clmm-math.

DynamicFeeConfig und DynamicFeeInfo

Parameter für dynamische Gebühren befinden sich an zwei Stellen. Die wiederverwendbare Vorlage — DynamicFeeConfig — wird vom Admin verwaltet und von Pools gemeinsam genutzt, die sich dafür entscheiden. Der Pro-Pool-Laufzeitzustand — DynamicFeeInfo — ist in PoolState eingebettet und wird bei jedem Swap aktualisiert.

DynamicFeeConfig

PDA-Seed: ["dynamic_fee_config", index.to_be_bytes()]. Erstellt über create_dynamic_fee_config (Admin-gated) und modifiziert über update_dynamic_fee_config. Ein Pool, der mit enable_dynamic_fee = true erstellt wird, speichert die fünf Kalibrierungsparameter der Config (filter_period, decay_period, reduction_factor, dynamic_fee_control, max_volatility_accumulator) zum Erstellungszeitpunkt in seinen eigenen DynamicFeeInfo; spätere Änderungen an DynamicFeeConfig beeinflussen bestehende Pools nicht rückwirkend.

DynamicFeeInfo (eingebettet in PoolState)

Die unteren vier Felder sind State; die oberen fünf sind Kalibrierung, die aus DynamicFeeConfig kopiert wurde. Die Gebühren-Mathematik und die Decay-Regeln sind unter products/clmm/math und products/clmm/fees dokumentiert. Von der Formel verwendete Konstanten:

LimitOrderState

Ein Konto pro offene Limit-Order.
Lebenszyklus:
  1. Open — Der Benutzer ruft open_limit_order auf, hinterlegt total_amount des Input-Tokens, die Order wird an eine TickState-Kohorte gebunden.
  2. (optional) Increase / Decrease — increase_limit_order addiert zu total_amount; decrease_limit_order gibt ungefüllte Tokens zurück (und jede bis dahin abgerechnete Ausgabe).
  3. Settle — Wenn die Kohorte vollständig oder teilweise gefüllt ist, ruft der Besitzer oder der operationale Keeper settle_limit_order auf, um Output-Tokens an das ATA des Besitzers zu übertragen.
  4. Close — Sobald unfilled_amount == 0, ist das Konto schließbar. Die Miete wird immer an owner zurückgegeben.
PDA-Seed: [owner.as_ref(), limit_order_nonce.key().as_ref(), limit_order_nonce.order_nonce.to_be_bytes().as_ref()]. Das Order-PDA ist daher eindeutig pro (owner, nonce_index, order_nonce).

LimitOrderNonce

Ein Pro-(wallet, nonce_index)-Zähler, der es einem einzelnen Benutzer ermöglicht, mehrere parallele Pipelines von Limit-Orders auszuführen, ohne auf PDAs zu kollidieren.
PDA-Seed: [user_wallet.as_ref(), &[nonce_index]]. Die meisten Clients verwenden nonce_index = 0 und lassen order_nonce die Kardinalität tragen.

Permission (veraltet)

Das Permission-Konto wurde im Upgrade vom 2026-10-22 entfernt. Es sperrte früher CreatePermissionedPool, das jetzt die erlaubnisfreie CreateCustomizablePoolV2 ist. Das Programm liest oder schließt diese Konten nicht mehr, und die Anweisungen CreatePermissionPda / ClosePermissionPda sind weg. PDAs, die vor dem Upgrade erstellt wurden (["permission", authority], 280 Bytes), bleiben als inerte Daten in der Chain; ignorieren Sie sie beim Scannen von CLMM-eigenen Konten.

Ableitung der Schlüsselkonten

Die genauen Seed-Strings sollten immer gegen die On-Chain-IDL und reference/program-addresses überprüft werden.

Lebenszyklus-Kurzreferenz

TickArrayState-Konten werden vom Programm niemals geschlossen — sie bleiben für die Lebensdauer des Pools bestehen. Sobald ein Tick-Array initialisiert wurde, bleibt es in der Chain, auch wenn jeder Tick darin zu liquidity_gross == 0 zurückkehrt. Die Wiederverwendung eines bestehenden Tick-Arrays ist kostenlos; nur die erste Position, die ein noch nie initialisiertes Array berührt, zahlt dessen Miete.

Was wo zu lesen ist

Quellen: