Skip to main content
Diese Seite wurde mit KI automatisch übersetzt. Maßgeblich ist stets die englische Version.Englische Version ansehen →
Diese Seite ergänzt products/clmm/accounts (was die Konten sind) und products/clmm/math (was die Mathematik ist). Sie ist maßgeblich für Argumente und Kontenreihenfolge; spezifische Byte-Layouts stammen aus dem IDL.Das Programm-Upgrade 2026-09 hat CLMM auf Anchor 1.0.2 / Solana 3.1.10 neu aufgebaut, die Admin-Anweisung CollectExcessLamports hinzugefügt und geändert, was CreateAmmConfig in owner / fund_owner schreibt. Keine benutzergerichtete Anweisung hat ihre Konten, Argumente oder Mathematik geändert. Siehe den Changelog-Eintrag vom 2026-09-30.Das Programm-Upgrade 2026-10-22 benennt CreatePermissionedPool in CreateCustomizablePoolV2 um, macht es für jeden aufrufbar und entfernt das Permission-Konto mit seinen zwei Admin-Anweisungen. Siehe den Changelog-Eintrag vom 2026-10-22.

Anweisungsübersicht

Es gibt keine Init-Tick-Array-Anweisung und keine ist erforderlich. Ein Tick-Array wird innerhalb OpenPosition* / IncreaseLiquidity* durch TickArrayState::get_or_create_tick_array erstellt, bezahlt durch payer. Übergeben Sie die (möglicherweise noch nicht initialisierte, System-eigene) Tick-Array-PDA als tick_array_lower / tick_array_upper und das Programm ordnet sie zu, wenn sie fehlt. OpenLimitOrder macht dasselbe für sein einzelnes tick_array.
Die meisten Admin-only-Anweisungen (CreateAmmConfig, UpdateAmmConfig, UpdatePoolStatus, CreateOperationAccount, UpdateOperationAccount, CloseProtocolPosition) werden durch den hardcodierten admin-Pubkey des Programms gated. CreateSupportMintAssociated / CloseSupportMintAssociated akzeptieren entweder den admin-Pubkey oder einen dedizierten Support-Mint-Owner-Schlüssel; CollectExcessLamports akzeptiert entweder den admin-Pubkey oder eine dedizierte Collect-Lamports-Wallet. Reward-Stream-Admin-Anweisungen (TransferRewardOwner, CollectRemainingRewards) werden durch den Reward-Funder gated, nicht durch den Programm-Admin. V2-Suffix bedeutet „unterstützt Token-2022 auf Vaults / NFT, erfordert Bitmap-Erweiterungs-Slot”. Das SDK wählt V2 standardmäßig für neue Pools.

CreatePool

Argumente
Konten (gekürzt)
Slots 10 und 11 sind pro-Mint, nicht „SPL Token dann Token-2022”. Jeder wird durch mint::token_program auf dem passenden Mint eingeschränkt, also für einen Pool, dessen token_mint_0 Token-2022 ist und token_mint_1 klassisches SPL ist, müssen Sie Token-2022 in Slot 10 und SPL Token in Slot 11 übergeben. CreateCustomizablePool und CreateCustomizablePoolV2 verwenden die gleichen zwei Slots.
Vorbedingungen
  • token_mint_0 < token_mint_1 nach Byte-Reihenfolge.
  • amm_config.disable_create_pool == false.
  • Mints werden nicht durch die Token-2022-Erweiterungs-Erlaubnisliste abgelehnt.
Nachbedingungen
  • pool_state.sqrt_price_x64 = sqrt_price_x64, tick_current = floor(log_{1.0001}(price)).
  • pool_state.liquidity = 0 (noch keine Positionen).
  • pool_state.fee_on = FromInput (Legacy-Standard).
  • pool_state.dynamic_fee_info ist auf Null gesetzt (dynamische Gebühr deaktiviert).

CreateCustomizablePool

Empfohlen für neue Pools. Gleiche Wirkung wie CreatePool plus Pool-spezifischer Gebührensammlungsmodus und optionales Dynamic-Fee-Opt-in. Argumente
Konten — genau die 13 deklarierten Konten von CreatePool. dynamic_fee_config ist kein deklariertes Konto.
Wenn enable_dynamic_fee = true, muss die zu erfassende DynamicFeeConfig als letztes remaining_account bereitgestellt werden — der Handler liest ctx.remaining_accounts.last(). Alle SupportMintAssociated-Bypass-PDAs müssen daher davor kommen, oder das Programm erfasst das falsche Konto und schlägt bei der Deserialisierung fehl. Das Weglassen bei gesetztem Flag schlägt mit AccountLack fehl.
Vorbedingungen — gleich wie CreatePool. Wenn enable_dynamic_fee = false, ist kein remaining_account erforderlich und alle übergebenen werden nur auf Support-Mint-Datensätze gescannt. Nachbedingungen
  • pool_state.fee_on auf die gewählte CollectFeeOn-Variante gesetzt.
  • Wenn dynamische Gebühr aktiviert wurde: pool_state.dynamic_fee_info wird aus der bereitgestellten DynamicFeeConfig initialisiert (fünf Kalibrierungsparameter kopiert; Zustandsfelder auf Null gesetzt).
  • Andernfalls: pool_state.dynamic_fee_info ist auf Null gesetzt (= dynamische Gebühr für immer inaktiv für diesen Pool).
fee_on und das Dynamic-Fee-Aktivierungsbit werden nur bei der Pool-Erstellung gesetzt. Es gibt kein In-Place-Upgrade — Pools, die über Legacy-CreatePool erstellt wurden, können nicht rückwirkend dynamische Gebühren oder einseitige Gebühren erhalten. Neue Bereitstellungen sollten standardmäßig diese Anweisung verwenden.

CreateCustomizablePoolV2

Sowohl CreatePool als auch CreateCustomizablePool leiten die Pool-PDA von ["pool", amm_config, token_mint_0, token_mint_1] ab, sodass es genau eine kanonische Pool-Adresse pro (config, mint0, mint1)-Tripel gibt — ein zweiter init mit denselben Seeds schlägt fehl. CreateCustomizablePoolV2 hebt diese Einschränkung auf, indem es einen vom Client bereitgestellten seed_index: u16 in die Pool-PDA-Seeds einbezieht und damit mehrere Pools für dasselbe Paar und dieselbe Gebührenebene ermöglicht — jeweils unter einer eigenen Adresse. Jeder kann diese Anweisung aufrufen. Alles andere am Pool ist identisch mit CreateCustomizablePool: Sie nimmt dieselben CreateCustomizableParams und unterstützt einseitige Gebühren sowie das Opt-in für dynamische Gebühren.
Bis zum Upgrade vom 2026-10-22 hieß diese Anweisung CreatePermissionedPool und erforderte, dass der Zahler eine vom Administrator ausgestellte Permission-PDA hielt. Das Upgrade benannte sie um, entfernte das permission-Konto und löschte die Berechtigungsmechanik. Der Diskriminator änderte sich mit dem Namen, daher müssen Clients, die gegen CreatePermissionedPool erstellt wurden, neu erstellt werden.
Argumente
Konten remaining_accounts: die Support-Mint-Registry-PDAs, wenn ein Token-2022-Mint diese benötigt, und die DynamicFeeConfig zuletzt, wenn enable_dynamic_fee = true — wie in CreateCustomizablePool. Vorbedingungen
  • seed_index != 0. Ein seed_index von 0 ist für Legacy-Pools reserviert und wird hier abgelehnt; die [0, 0]-Seed-Komponente ist das, was eine Legacy-Pool-Adresse zum klassischen Vier-Seed-Format zusammenfallen lässt.
  • Es existiert noch kein Pool unter der abgeleiteten Adresse.
  • Dieselben Mint- / Allowlist-Regeln wie CreatePool.
Nachbedingungen
  • Ein neuer pool_state existiert unter der seed_index-abgeleiteten Adresse, mit pool_state.seed_index = seed_index.
  • Alle anderen Nachzustände entsprechen CreateCustomizablePool (Gebührenmodell, optionale dynamische Gebühren).
Da pool_creator nicht überprüft wird, kann jeder Zahler jede Adresse in pool_state.owner schreiben. Diese Adresse kann InitializeReward auf dem Pool aufrufen, aber das ist kein Beweis dafür, wer den Pool erstellt hat. Integratoren sollten V2-Pools nicht nach ihrem owner kennzeichnen oder bewerten.

OpenPositionV2 / OpenPositionWithToken22Nft

Erstellen Sie eine neue Position in einem bestehenden Pool. Argumente
Konten — die beiden Varianten haben unterschiedliche Kontolisten. OpenPositionV2 deklariert 22; OpenPositionWithToken22Nft deklariert 20. OpenPositionV2, in Reihenfolge: OpenPositionWithToken22Nft ist dieselbe Liste mit metadata_account (5) und metadata_program (19) entfernt — es schreibt die Metadaten der Position stattdessen über die Token-2022-Metadaten-Erweiterung auf dem NFT-Mint — was 20 Konten ergibt. Sein position_nft_mint ist ein einfacher Signer und position_nft_account ein UncheckedAccount.
tick_array_bitmap_extension ist auf keiner der beiden Varianten ein deklariertes Konto. Wenn der Bereich der Position außerhalb der Inline-tick_array_bitmap des Pools (±512 Tick-Arrays) liegt, fügen Sie die TickArrayBitmapExtension-PDA mit Seeds ["pool_tick_array_bitmap_extension", pool_state] als remaining_accounts[0] an.
Mathematik — siehe products/clmm/math. Anhand von base_flag löst das Programm entweder liquidity oder (amount_0_max, amount_1_max) in das tatsächliche L und die tatsächlich verbrauchten Token-Beträge auf. Vorbedingungen
  • tick_lower < tick_upper, beide Vielfache von pool.tick_spacing, innerhalb von [MIN_TICK, MAX_TICK].
  • Die beiden Tick-Array-PDAs werden übergeben. Sie müssen nicht bereits existieren — get_or_create_tick_array weist eine fehlende auf Kosten des payer innerhalb dieser Anweisung zu. Es gibt keine separate Init-Tick-Array-Anweisung.
  • Der Benutzer hat mindestens amount_0_max und amount_1_max in den Quell-ATAs.
Nachbedingungen
  • personal_position existiert, liquidity gesetzt, fee_growth_inside_last erfasst.
  • Tick-Array-Einträge bei tick_lower und tick_upper aktualisiert (liquidity_gross += L, liquidity_net ± L, Gebührenwachstums-Snapshots gepflegt).
  • pool_state.liquidity += L, wenn die Position im Bereich liegt (tick_lower ≤ tick_current < tick_upper).
  • Der Position-NFT-Mint zeichnet pool_state als Freeze-Autorität auf. Die Mint-Autorität wird nach dem Prägen der einzelnen NFT entfernt. Das Aufzeichnen der Freeze-Autorität ändert den Zustand des NFT-Token-Kontos nicht.
  • Das NFT-Token-Konto bleibt entsperrt, es sei denn, die Anweisung ist OpenPositionV2 oder OpenPositionWithToken22Nft und die Freeze-Autorität eines der Vault-Mints entspricht der Restricted-Issuer-Liste von CLMM. Nur dieser übereinstimmende V2-Pfad sperrt das Konto. OpenPosition V1 sperrt nicht.
Häufige Fehler — TickInvalidOrder (tick_lower >= tick_upper), TickAndSpacingNotMatch (ein Endpunkt ist kein Vielfaches von tick_spacing), InvalidTickIndex (außerhalb von [MIN_TICK, MAX_TICK]), MissingTickArrayBitmapExtensionAccount (Bereich außerhalb der Inline-Bitmap und die Erweiterung wurde nicht angehängt), NotApproved (pool_state.status blockiert das Öffnen), ZeroAmountSpecified.
Das Sperren von Positionen fügt keine deklarierten Anweisungskonten oder Argumente hinzu. Clients können diese Positionen mit den bestehenden V2-Layouts öffnen. Das Verhalten wird On-Chain aus vault_0_mint und vault_1_mint ausgewählt.

IncreaseLiquidityV2

Fügen Sie Liquidität zu einer bereits offenen Position hinzu. Argumente
Konten — 15, und nicht von OpenPosition ableitbar: es gibt kein rent, kein system_program, kein associated_token_program und kein Metadaten-Konto. Stellen Sie die TickArrayBitmapExtension-PDA als remaining_accounts[0] voran, wenn der Bereich der Position außerhalb der Inline-Bitmap liegt. Effekt
  • Überträgt amount_0_actual / amount_1_actual von Benutzer → Vaults.
  • Erhöht personal_position.liquidity und pool_state.liquidity (wenn im Bereich) und entsprechend die Endpunkt-Tick-liquidity_gross / liquidity_net.
  • Erfasst Gebühren und Belohnungen, die seit der letzten Berührung fällig sind und schreibt sie token_fees_owed_{0,1} / reward_amount_owed gut. Diese werden nur bei DecreaseLiquidity / DecreaseLiquidityV2 ausgezahlt, nicht bei Erhöhung — es gibt keine eigenständige Collect-Anweisung.

DecreaseLiquidityV2

Entfernen Sie Liquidität aus einer Position. Argumente
Konten — 16, und nicht dieselbe Form oder Reihenfolge wie IncreaseLiquidityV2: personal_position und pool_state sind vertauscht, die Vaults kommen vor den Tick-Arrays, die Benutzerkonten heißen recipient_token_account_*, und es gibt ein zusätzliches memo_program. Verbleibende Konten — drei pro aktiver Belohnung, die erfasst wird, in der Reihenfolge reward_token_vault(W), recipient_token_account(W), reward_vault_mint. Stellen Sie die TickArrayBitmapExtension-PDA voran, wenn der Bereich der Position außerhalb der Inline-Bitmap liegt.
Dies ist auch die einzige Möglichkeit, Gebühren und Belohnungen zu erfassen. Um zu erfassen, ohne die Position zu ändern, rufen Sie sie mit liquidity = 0, amount_0_min = 0, amount_1_min = 0 auf.
Effekt
  • Berechnet (amount_0, amount_1) für das entfernte L anhand des aktuellen sqrt_price_x64.
  • Begleicht Gebühren/Belohnungen, die seit der letzten Berührung aufgelaufen sind, wie IncreaseLiquidity.
  • Überträgt amount_0 + fees_owed_0 und amount_1 + fees_owed_1 aus Vaults an den Benutzer.
  • Verringert Liquiditätszähler; wenn die neue personal_position.liquidity == 0, ist die Position berechtigt für ClosePosition.
Slippage — amount_0_min und amount_1_min sind die Mindestwerte, die der Benutzer netto der Token-2022-Transfergebühren auf der Ausgabeseite akzeptiert.

ClosePosition

Brennt die Position-NFT und schließt PersonalPositionState. Deklarierte Konten Verbleibende Konten
  • Nicht eingefrorene NFT: keine erforderlich; ein zusätzliches Pool-Konto ist harmlos, da der Handler es nicht liest.
  • Eingefrorene NFT: personal_position.pool_id als erstes verbleibendes Konto anhängen. Das Programm lädt es als PoolState und verwendet seine PDA-Seeds zum Signieren des Auftauens.
Vorbedingungen
  • personal_position.liquidity == 0.
  • tokens_fees_owed_{0,1} == 0.
  • Alle Reward-Zähler reward_amount_owed == 0.
(D. h., alles einsammeln und zuerst auf Null reduzieren.) Effekt
  • Wenn das NFT-Token-Konto eingefroren ist, wird überprüft, dass das erste verbleibende Konto personal_position.pool_id entspricht, dann wird es mit der Pool-PDA aufgetaut.
  • Brennt die NFT.
  • Schließt das NFT-Token-Konto und personal_position, wobei die Miete an nft_owner zurückerstattet wird. Wenn die Position-NFT Token-2022 verwendet, wird auch die NFT-Mint geschlossen; klassische SPL Token-Mints können nicht geschlossen werden und bleiben mit Angebot Null.
Das Auftauen, Brennen und Schließen sind atomar. Die NFT kann zwischen diesen Schritten nicht übertragbar werden. Bedingter Client-Break — das deklarierte IDL-Layout ist unverändert, daher setzen Legacy-Clients weiterhin bestehende und nicht eingefrorene Positionen. Ein Legacy-Builder, der das Pool-Remaining-Konto auslässt, schlägt mit AccountLack fehl, wenn eine eingefrorene Position geschlossen wird. Das Pool-Konto bei jedem Schließen zu übergeben ist die einfachste kompatible Strategie.

SwapV2

Durchläuft die Liquiditätskurve; exakte Eingabe oder exakte Ausgabe je nach is_base_input. Argumente
Konten (gekürzt) Aufrufer übergeben eine priorisierte Liste von Tick-Arrays, die den erwarteten Swap-Durchlauf abdecken; das Programm verwendet so viele wie nötig. Das SDK berechnet diese Liste über PoolUtils.computeAmountOutFormat oder den Quote-Endpunkt der API. Vorbedingungen
  • pool_state.status erlaubt Swap.
  • now >= open_time.
  • sqrt_price_limit_x64 liegt auf der korrekten Seite von sqrt_price_x64 für die Richtung.
Häufige Fehler — TooLittleOutputReceived (Slippage bei exakter Eingabe), TooMuchInputPaid (Slippage bei exakter Ausgabe), SqrtPriceLimitOverflow, NotEnoughTickArrayAccount, InvalidFirstTickArrayAccount, MissingTickArrayBitmapExtensionAccount, LiquidityInsufficient, NotApproved (Swap-Bit in pool_state.status gesetzt). CLMM hat keine ExceededSlippage-Variante — dieser Name gehört zu CPMM — und kein TickArrayNotFound. Was SwapV2 intern macht, das Aufrufer wissen sollten (nach Release 2025):
  1. Dynamische Gebührenaufschlag — wenn pool.dynamic_fee_info ungleich Null ist, aktualisiert das Programm den Volatilitätsakkumulator unter Verwendung der seit dem letzten Swap durchlaufenen Tick-Distanz (mit den Filter-/Decay-Regeln aus products/clmm/fees) und addiert eine dynamic_fee_component auf AmmConfig.trade_fee_rate. Die Gesamtgebühr ist auf 10% begrenzt (MAX_FEE_RATE_NUMERATOR / 1_000_000).
  2. Limit-Order-Matching — wenn der Preis-Durchlauf einen Tick kreuzt, der offene Limit-Orders hält, füllt das Programm zuerst verfügbare Limit-Order-Liquidität bei diesem Tick (FIFO nach order_phase), dann geht es entlang der LP-Liquiditätskurve weiter. Gefüllte Beträge aktualisieren tick.unfilled_ratio_x64 und tick.part_filled_orders_remaining für spätere Abwicklung; Orders selbst bleiben unausgegeben, bis ihr Besitzer SettleLimitOrder aufruft.
  3. Einseitige Gebührenleitung — wenn pool.fee_on = Token0Only oder Token1Only, berechnet der Swap-Schritt immer noch denselben Input-Output-Handel; die Gebühr wird dann auf die konfigurierte Seite geleitet. Für Richtungen, bei denen die konfigurierte Gebührenseite die Ausgabe ist, wird die Gebühr von der Swap-Ausgabe abgezogen (der Benutzer erhält out − fee); für Richtungen, bei denen sie die Eingabe ist, entspricht das Verhalten FromInput. Siehe is_fee_on_input(zero_for_one) und is_fee_on_token0(zero_for_one) auf PoolState.
Swap (V1) implementiert dieselbe dynamische Gebühr, einseitige Gebührenleitung und Limit-Order-Matching wie SwapV2; das einzige Feature, das es nicht hat, ist Token-2022-Unterstützung — beide Vaults müssen klassisches SPL Token sein. Pools mit einer beliebigen Token-2022-Mint müssen über SwapV2 getauscht werden. Der Aggregator und das SDK bevorzugen bereits V2 für jeden CLMM-Leg, daher müssen Aufrufer nicht nach Mint-Typ verzweigen.

OpenLimitOrder

Platziert eine Verkaufsorder bei einem bestimmten Tick. Die Order sitzt in einer Pro-Tick-FIFO-Kohorte und wird gefüllt, wenn der Preis vorbeigeht. Argumente
Konten (gekürzt) Verbleibende Konten — [0] tick_array_bitmap_extension, erforderlich nur beim Initialisieren eines Tick-Arrays, dessen Startindex außerhalb der Inline-Bitmap des Pools liegt. Andernfalls nichts übergeben.
Es gibt kein rent-Konto: die Struktur endet bei system_program, 13 deklarierte Konten. Ein verirrtes rent in Position 14 landet genau dort, wo die optionale Bitmap-Erweiterung gelesen wird, daher scheint die Order zu funktionieren, bis zum ersten Mal ein Tick-Array außerhalb der Inline-Bitmap erstellt werden muss — und schlägt dann fehl.
Konten-Listen-Änderung (2026-07 Release). OpenLimitOrder nimmt jetzt auch die Output-Seiten-Konten — output_token_account, output_vault und output_vault_mint — zusätzlich zur Input-Seite. Sie werden nur zur Validierung verwendet: das Programm lehnt die Order ab, wenn das Token-Konto des Besitzers auf der Input- oder Output-Seite eingefroren ist. Dies garantiert, dass eine Füllung tatsächlich auf die Output-ATA des Besitzers abgewickelt werden kann, was für Allow-List / Standard-eingefrorene Token-2022-Mints (z. B. berechtigte Token) wichtig ist, bei denen ein Konto möglicherweise noch nicht aufgetaut ist. Clients, die gegen die ältere einseitige Kontenliste erstellt wurden, müssen die drei Output-Konten hinzufügen.
Vorbedingungen
  • Weder input_token_account noch output_token_account ist eingefroren (sonst NotApproved).
  • pool_state.status erlaubt sowohl Swap (Bit 4) als auch Limit-Order (Bit 5) Operationen (sonst NotApproved).
  • tick_index % pool.tick_spacing == 0 und innerhalb von [MIN_TICK, MAX_TICK].
  • tick_index liegt auf der rechten Seite von pool.tick_current für die gewählte Richtung (Token0 verkaufen → Tick muss über aktuell sein, und umgekehrt). Der Verkauf bei einem bereits gekreuzten Tick würde sofort abgeglichen und wird abgelehnt.
Nachbedingungen
  • limit_order existiert, wobei tick.order_phase und tick.unfilled_ratio_x64 zum Öffnungszeitpunkt erfasst werden.
  • tick.orders_amount += amount (in der aktuellen Kohorte).
  • limit_order_nonce.order_nonce += 1.
  • OpenLimitOrderEvent emittiert.
Häufige Fehler — NotApproved (Input- oder Output-Token-Konto eingefroren, oder Pool hat Swap / Limit-Order deaktiviert), ZeroAmountSpecified (amount == 0 nach der Input-seitigen Transfergebühr), InvalidLimitOrderAmount (der Betrag würde eine Ausgabe unter 1 Basiseinheit bei diesem Tick erzeugen, oder u64 überlasten), InvalidTickIndex (außerhalb von [MIN_TICK, MAX_TICK], oder auf der falschen Seite von tick_current für die gewählte Richtung), TickAndSpacingNotMatch (tick_index % pool.tick_spacing != 0), OrderPhaseSaturated.

IncreaseLimitOrder

Addiert zu einer bestehenden offenen Order. Nur vom owner der Order aufrufbar. Argumente
Konten — 8, nur Input-Seite. Es lässt das Nonce-Konto, alle drei Output-Seiten-Konten und system_program weg. Vorbedingungen
  • limit_order.owner == signer.
  • Die Order ist immer noch in derselben Kohorte (tick.order_phase == limit_order.order_phase). Wenn die Kohorte bereits mit dem Füllen begonnen hat, ist die Order teilweise abgewickelt — der Aufrufer sollte zuerst DecreaseLimitOrder oder SettleLimitOrder aufrufen, um voranzukommen.
Effekt
  • Überträgt amount von Owner-ATA zu input_vault.
  • limit_order.total_amount += amount; tick.orders_amount += amount.

DecreaseLimitOrder

Reduziert oder bricht eine offene Order vollständig ab. Zahlt den ungefüllten Rest an den Besitzer zurück, plus jede Ausgabe, die bereits durch frühere Teilfüllungen abgewickelt wurde. Argumente
Konten — sowohl Input- als auch Output-Token-Seiten: Effekt
  • Berechnet den gefüllten Betrag der Order aus der unfilled_ratio_x64 der Kohorte seit dem Öffnen neu.
  • Sendet gefüllte Ausgabe an output_token_account.
  • Sendet amount der ungefüllten Eingabe zurück an input_token_account.
  • Aktualisiert limit_order entsprechend. Wenn der neue ungefüllte Rest Null ist, schließt das Programm das Konto und erstattet die Miete an owner.

SettleLimitOrder

Gefüllte Output-Token an den Eigentümer übertragen, ohne den ungefüllten Rest der Order zu ändern. Nützlich, wenn auto_withdraw-Keeper lange laufende Teilfüllungen schrittweise auszahlen möchten. Aufrufer — entweder der owner der Order oder der limit_order_admin des Programms (ein Off-Chain-Operationswallet, das eine automatisierte Keeper-Schleife ausführt). Der Keeper hat keine weitere Autorität — er kann Benutzermittel nicht außerhalb des Pushens gefüllter Output zum owner ATA der Order verschieben. Konten Effekt
  • Berechnet die kumulierte geschuldete Output mit (limit_order.unfilled_ratio_x64, tick.unfilled_ratio_x64).
  • Überweist die Differenz zu output_token_account.
  • Aktualisiert limit_order.settled_output.
  • Schließt die Order nicht; sie bleibt offen für verbleibende Input.

CloseLimitOrder

Schließt ein vollständig verbrauchtes Order-Konto. Die Miete wird immer an limit_order.owner zurückgegeben, unabhängig davon, wer signiert. Aufrufer — entweder owner oder limit_order_admin. Vorbedingungen
  • Die Order hat keinen ungefüllten Rest (entweder amount == total_amount wurde gefüllt und abgerechnet, oder der Eigentümer hat die Order zuvor auf Null reduziert und vergessen, sie zu schließen).
Effekt
  • Schließt limit_order; die Miete wird an limit_order.owner gesendet.

CreateDynamicFeeConfig (Admin)

Erstellt einen wiederverwendbaren Parametersatz unter einem u16-Index. Argumente
Konten Häufige Fehler — InvalidDynamicFeeConfigParams, wenn decay_period <= filter_period oder ein Feld mit Wert 0 außerhalb der Grenzen liegt.

UpdateDynamicFeeConfig (Admin)

Ändert eine vorhandene DynamicFeeConfig. Pools, die die Konfiguration bereits bei der Erstellung als Snapshot erstellt haben, werden nicht rückwirkend aktualisiert; nur neu erstellte Pools, die auf diese Konfiguration verweisen, übernehmen die neuen Werte. Argumente — dieselben fünf Kalibrierungsfelder wie CreateDynamicFeeConfig (filter_period, decay_period, reduction_factor, dynamic_fee_control, max_volatility_accumulator); index ist bei der Erstellung festgelegt und wird hier nicht erneut übergeben.

CollectProtocolFee / CollectFundFee

Sammelt aufgelaufene Protokoll-/Fondsgebühren aus den Pool-Vaults zu einem Empfänger und setzt die entsprechenden PoolState.protocol_fees_* / fund_fees_*-Felder auf Null. Dies ist nicht das CPMM-Layout — CLMM hat kein authority-Konto, und die Empfängerfelder heißen recipient_token_account_{0,1} statt recipient_token_{0,1}_account. Argumente — amount_0_requested: u64, amount_1_requested: u64.
Geändert in 2026-09: neue Konfigurationen beziehen ihre Gebühreninhaber nicht mehr vom Unterzeichner. create_amm_config schreibt jetzt die hardcodierte protocol_fee_owner::ID des Programms in owner und fund_fee_owner::ID in fund_owner. Zuvor wurde der Schlüssel des Admin-Unterzeichners in beide kopiert. Im Mainnet sind dies bereits die gleichen Schlüssel, die auf allen 21 vorhandenen Konfigurationen gespeichert sind. Adressen finden Sie in reference/program-addresses.Die akzeptierten Unterzeichner oben sind unverändert. Der Admin kann weiterhin von jeder Konfiguration sammeln, und vorhandene AmmConfig-Konten werden nicht umgeschrieben. Lesen Sie owner / fund_owner vom Konto statt einen Wert anzunehmen. UpdateAmmConfig-Parameter 3 und 4 rotieren sie weiterhin.

CollectExcessLamports

Admin-Sweep von Lamports über dem Rent-Exempt-Minimum auf Konten, die CLMM kontrolliert. Es wurde im 2026-09-Upgrade hinzugefügt, um die Überfinanzierung zurückzufordern, die die SIMD-0437-Mietreduktion auf Konten hinterlässt, die vor jedem Schritt erstellt wurden. Nur der Überschuss wird verschoben. Token-Guthaben, Kontodaten, Eigentümer, Pool-Status und die Preiskurve bleiben unverändert. Ein Konto, das bereits auf seinem Minimum ist, wird unverändert gelassen, sodass die Anweisung nach jedem Rollout-Schritt sicher erneut ausgeführt werden kann. Argumente: keine. Konten Umfang: ein Pool pro Aufruf. CLMM hat keine programmweite Vault-Autorität. Die Vaults jedes Pools gehören seinem eigenen PoolState. Jede Token-Programm-Quelle muss daher den pool_state in Slot 2 als ihre Autorität haben: token_vault_0, token_vault_1 oder einen der Reward-Vaults dieses Pools. Wenn Sie den Vault eines anderen Pools oder ein Benutzerkonto übergeben, schlägt die Eigentümerprüfung des Token-Programms fehl und die gesamte Anweisung wird rückgängig gemacht. Sie wird nicht übersprungen. Position-NFT-Mints können nicht gefegt werden, da ihre Mint-Autorität widerrufen wird, wenn die Position geöffnet wird. Wie jedes Quellkonto behandelt wird Das Programm macht zwei Durchläufe über remaining_accounts: zuerst alle Token-Programm-CPIs, dann die direkten Belastungen. Das Verschachteln der beiden bricht mit dem UnbalancedInstruction-Fehler der Runtime ab, daher ist die Reihenfolge im Programm festgelegt und Sie müssen die Liste nicht selbst sortieren.
Durchlauf 2 umfasst Konten, deren Miete ein Benutzer bezahlt hat. Ein PersonalPositionState oder LimitOrderState, das hier übergeben wird, gibt seinen Überschuss wie jedes andere CLMM-eigene Konto auf. Es bleibt Rent-Exempt und behält seine Daten. Wenn es später geschlossen wird, erhält der Eigentümer zurück, was das Konto zu diesem Zeitpunkt hält, was nach einem Sweep das aktuelle Rent-Minimum ist.
Die Transaktionsgröße ist die echte Grenze, wie viele Quellen in einen Aufruf passen. Es ist die gleiche Einschränkung wie der Wallet-seitige Sweep, der in solana-fundamentals/rent-and-reclaimable-rent beschrieben wird. Häufige Fehler:
  • NotApproved (6000): falscher Unterzeichner.
  • LamportsCalculateError (6052): die wSOL-Rundreise nettete nicht zu Null.
  • Ein Token-Programm-Eigentümer-Mismatch-Fehler: eine Token-Quelle gehört nicht zu pool_state.
  • InsufficientFunds: ein Programm-eigenes Konto hält weniger als sein eigenes Rent-Minimum.
Kein SDK-Builder. @raydium-io/raydium-sdk-v2 liefert keinen Builder für diesen Admin-Pfad. Kodieren Sie ihn von Hand aus der IDL.

InitializeReward

Fügt einen neuen Reward-Stream zu einem Pool hinzu. Bis zu 3 Streams können gleichzeitig aktiv sein. Argumente — eine einzelne Struktur, param: InitializeRewardParam:
Die Wire-Kodierung ist die drei Felder hintereinander, daher ist eine manuell erstellte Anweisung unbeeinträchtigt — aber ein IDL-gesteuerter Client muss ein param-Objekt statt drei positionaler Argumente übergeben. Konten Vorbedingungen
  • Weniger als 3 Streams sind derzeit auf dem Pool aktiv.
  • Der Funder zahlt total_emission = emissions_per_second × (end_time − open_time) Reward-Token als Teil dieser Anweisung in den Vault ein.
  • Whitelisted Reward-Mint pro operation_state.

SetRewardParams

Erweitert, erhöht oder ändert die Emissionsrate auf einem vorhandenen Reward-Stream. Wird normalerweise von einem Pool-Ersteller oder dem Raydium-Multisig aufgerufen. Einschränkungen sind On-Chain: Sie können normalerweise end_time erweitern oder Emissionen erhöhen, nicht rückwirkend reduzieren. Überprüfen Sie die Eigentümerliste von operation_state.

UpdateRewardInfos

Reine Buchhaltung — setzt reward_growth_global_x64 auf die aktuelle Zeit, indem emissions_per_second × Δt / liquidity multipliziert wird. Wird intern von jeder Liquiditäts-berührenden Anweisung aufgerufen. Wird als eigenständige Anweisung bereitgestellt, da externe Akteure (UIs, Cranks) sie manchmal auslösen möchten.

Rewards sammeln

Es gibt keine eigenständige Collect-Reward-Anweisung. Das Programm stellt keinen CollectReward-Einstiegspunkt bereit, und die veröffentlichte IDL auch nicht.
Rewards, die einer Position geschuldet werden, werden von DecreaseLiquidity / DecreaseLiquidityV2 ausgezahlt. Um zu sammeln, ohne die Position zu ändern, rufen Sie sie mit liquidity = 0, amount_0_min = 0, amount_1_min = 0 auf. Die Reward-Vaults und Empfängerkonten gehen in remaining_accounts in Gruppen von drei pro aktivem Reward in der Reihenfolge reward_token_vault(W), recipient_token_account(W), reward_vault_mint. CollectRemainingRewards ist etwas anderes: Es ermöglicht dem Reward-Funder, nach dem end_time eines Streams Token zu fegen, die nie einer Position zugeordnet wurden.

Zustandsänderungsmatrix

Nächste Schritte

Quellen: