Skip to main content
Diese Seite wurde mit KI automatisch übersetzt. Maßgeblich ist stets die englische Version.Englische Version ansehen →

Einrichtung

Jede Demo auf dieser Seite spiegelt eine Datei in raydium-sdk-V2-demo/src/clmm; der GitHub-Link steht neben jedem Abschnitt. Die Initialisierung folgt der Vorlage config.ts.template des Demo-Repositorys (Quelle). disableFeatureCheck: true wird für jede nicht triviale Integration empfohlen:

Einen CLMM-Pool erstellen

Quelle: src/clmm/createPool.ts
Das SDK:
  • Sortiert mint1/mint2 vor der Ableitung nach Byte-Reihenfolge.
  • Berechnet sqrt_price_x64 = floor(sqrt(initialPrice × 10^(dB−dA)) × 2^64).
  • Legt die Konten observation und tick_array_bitmap_extension an.
  • Bezahlt die Gebühr für die Poolerstellung, die durch ammConfig festgelegt ist.

Eine Position in einer gewählten Preisspanne eröffnen

Quelle: src/clmm/createPosition.ts
Das SDK berechnet, welche Tick-Arrays die Spanne berührt, und übergibt sie als Konten. Eine Init-Instruktion muss es nicht bündeln: Es gibt keine init-tick-array-Instruktion. OpenPosition* legt ein fehlendes Tick-Array selbst an, auf Kosten des Zahlers.

Liquidität auf einer bestehenden Position erhöhen

Quelle: src/clmm/increaseLiquidity.ts

Liquidität verringern (und gleichzeitig Gebühren einsammeln)

Quelle: src/clmm/decreaseLiquidity.ts und src/clmm/closePosition.ts
Um nur Gebühren und Belohnungen einzusammeln, rufen Sie decreaseLiquidity mit liquidity = new BN(0) auf. Die Nebenwirkung der Instruktion besteht darin, token_fees_owed_{0,1} und reward_amount_owed abzurechnen und auszuzahlen. Das ist der einzige Weg, beides einzusammeln. Um die Position vollständig zu schließen, nachdem Liquidität und Gebühren auf null gesetzt wurden, übergeben Sie ownerInfo: { closePosition: true } beim letzten decreaseLiquidity-Aufruf. Das SDK hängt ClosePosition an und verbrennt den NFT.
Positionen mit eingeschränktem Emittenten benötigen einen kompatiblen Schließ-Builder. Diese Positionen haben ein eingefrorenes NFT-Token-Konto. ClosePosition muss die Pool-ID der Position als erstes verbleibendes Konto anhängen, damit CLMM das Konto vor dem Verbrennen auftauen kann. Der Programmquellcode-Zweig enthält keine SDK-Änderung. Prüfen Sie, ob Ihre SDK-Version den Schließpfad für eingefrorene Konten ausdrücklich unterstützt, bevor Sie die Erstellung von Positionen mit eingeschränktem Emittenten aktivieren.
Für einen direkten Anchor-Client lassen Sie die deklarierten Konten unverändert und hängen den Pool an:
Sie können poolId bei jedem Schließen übergeben. CLMM liest sie nur, wenn positionNftAccount eingefroren ist. So bleibt ein Client-Pfad mit alten und neuen Positionen kompatibel.

Belohnung(en) einsammeln

Quelle: src/clmm/harvestAllRewards.ts
harvestAllRewards durchläuft jede Position in jedem übergebenen Pool. Dabei bündelt es die DecreaseLiquidity-Aufrufe mit null Liquidität, die Gebühren und Belohnungen abrechnen (zusammen mit etwaigen UpdateRewardInfos), und verteilt sie bei Bedarf auf mehrere Transaktionen.

Swap

Quelle: src/clmm/swap.ts Dieses Beispiel entspricht src/clmm/swap.ts. Dort wird die Simulation mit swapInternal durchgeführt und nicht mit PoolUtils.computeAmountOutFormat.
Die Simulation durchläuft die Tick-Map außerhalb der Chain mit derselben Logik wie das On-Chain-Programm. Sie liefert den Ausgabebetrag (amountCalculated) sowie die genaue Kontoliste, die der Swap berühren wird (accounts). Übergeben Sie immer die remainingAccounts, die die Simulation zurückgibt. Sind es zu wenige, bricht der Swap mitten in der Durchquerung mit NotEnoughTickArrayAccount ab. Veraltete Konten verbrauchen lediglich unnötiges Compute-Budget.
PoolUtils.computeAmountOutFormat gibt es weiterhin. Es benötigt jedoch eine ComputeClmmPoolInfo (das computePoolInfo aus getPoolInfoFromRpc, kein API-Pool-Objekt) sowie zwei weitere Pflichtargumente, tickarrayBitmapExtension und blockTimestamp. Außerdem existiert keine Methode raydium.clmm.fetchTickArrays. fetchTickArrays ist eine freie Funktion. Die modulweiten Hilfsfunktionen sind PoolUtils.fetchMultiplePoolTickArrays sowie die tickData und tickArrays, die getPoolInfoFromRpc zurückgibt.

Einen anpassbaren CLMM-Pool erstellen

createCustomizablePool ist der Einstiegspunkt, der beim Erstellen des Pools die Schalter für dynamische Gebühren und einseitige Gebühren bereitstellt. Er übernimmt die Struktur von createPool und ergänzt zwei Parameter:
Es gibt weder einen Parameter enableDynamicFee noch dynamicFeeConfigId oder startTime. Die Angabe von dynamicFeeConfig aktiviert dynamische Gebühren. Lassen Sie den Parameter weg, erhalten Sie einen Pool mit statischen Gebühren, und zwar ohne Fehlermeldung. Beachten Sie außerdem, dass die Enum-Member im SDK TokenOnlyA / TokenOnlyB heißen, während das Rust-Enum on-chain Token0Only / Token1Only benennt. Die numerischen Werte stimmen überein (FromInput = 0).
createPool funktioniert weiterhin für den Pfad mit Standardgebühren ohne dynamische Gebühren. Verwenden Sie createCustomizablePool, sobald Sie eine der beiden Optionen benötigen. Die On-Chain-Kontoliste finden Sie unter products/clmm/instructions.

Limit-Orders

Eine Limit-Order hinterlegt die Eingabe des Nutzers bei genau einem Tick. Sie wird im FIFO-Verfahren ausgeführt, sobald ein Swap diesen Tick durchquert. Die Ausgaben werden beim Settlement an die ATA des Inhabers gesendet. Der Inhaber muss zum Zeitpunkt der Ausführung nicht online sein.

Limit-Order eröffnen

Es gibt weder ein Konfigurationskonto pro Pool für Limit-Orders noch einen Helfer getClmmLimitOrderConfigs(). Orders werden über ihren Tick identifiziert.
Der SDK leitet die PDA von LimitOrderState aus (owner, nonce PDA, order nonce) ab, erhöht die LimitOrderNonce pro Wallet und fügt die Order am jeweiligen Tick in die FIFO-Kohorte ein.

Offene Order erhöhen oder verringern

decreaseLimitOrder kann nur aus dem nicht ausgeführten Teil der Order entnehmen. Der ausgeführte Teil bleibt bis zum Settlement gesperrt. Beide Instruktionen brechen mit InvalidOrderPhase ab, wenn die Order bereits vollständig ausgeführt wurde.

Ausgeführte Order abrechnen

settleLimitOrder liest das unfilled_ratio_x64 der Order gegen den Kohorten-Tracker aus, berechnet den ausgeführten Ertrag und überweist ihn an die ATA des Inhabers. Der Inhaber kann dies selbst aufrufen. Auch limit_order_admin (ein Off-Chain-Operations-Keeper) kann es im Namen des Inhabers tun. Die Ausgabe geht dabei trotzdem an den Inhaber. Um vollständig abgerechnete Orders zu schließen und die Rent zurückzuholen, verwenden Sie closeLimitOrder (einzeln) oder closeAllLimitOrder (im Stapel). Um viele Orders auf einmal abzurechnen, packt settleAllLimitOrder so viele SettleLimitOrder-Aufrufe in eine v0-Transaktion, wie hineinpassen.

Offene Orders einer Wallet abrufen (Off-Chain)

Der Endpunkt für aktive Orders liefert nicht ausgeführte und teilweise ausgeführte Orders in einer einzigen Antwort. totalAmount, filledAmount und pendingSettle unterscheiden die Phasen. Für die Historie geschlossener Orders verwenden Sie /limit-order/history/order/list-by-user?wallet=… (pro Wallet, paginiert über nextPageId). Für das vollständige Ereignisprotokoll einer bestimmten Order verwenden Sie /limit-order/history/event/list-by-pda?pda=….

Rust-CPI-Grundgerüst

Reihenfolge der verbleibenden Konten für SwapV2:
Wenn der Swap die Erweiterung nie benötigt, lassen Sie sie weg. Andernfalls ist sie das erste verbleibende Konto.

Häufige Fallstricke

  • Ungenaue Tick-Endpunkte → TickAndSpacingNotMatch. Rasten Sie Ticks immer über TickUtil.getPriceAndTick ein (Singular TickUtil).
  • Zu wenige Tick-Arrays in SwapV2 übergeben → NotEnoughTickArrayAccount. Übernehmen Sie die Liste aus swapInternal(...).accounts.
  • Full-Range-Position ohne Bitmap-Erweiterung → Die PDA der Erweiterung muss beschreibbar sein. Das SDK übernimmt dies automatisch.
  • Verwechslung von sqrt_price_x64 mit price → Ein Faktor-2-Fehler ist hier besonders unangenehm. Im Zweifel lassen Sie das SDK den Wert aus einem lesbaren Preis berechnen.
  • Rewards zu früh einsammeln → Jedes Einsammeln ist ein DecreaseLiquidity ohne Liquidität und kostet eine Transaktion. Bündeln Sie Einsammlungen über harvestAllRewards für mehrere Positionen. Denken Sie dabei daran, dass dessen execute { sequentially: true } benötigt.
  • NFT-Konten selbst schließen → ClosePosition verbrennt den NFT und schließt dessen ATA. Bei einem Token-2022-NFT-Mint wird auch dieser geschlossen. Ein klassischer SPL-Token-Mint bleibt dagegen mit Supply null bestehen, da dieses Programm Mints nicht schließen kann. Schließen Sie unterstützte Konten nicht separat, sonst bricht die Instruktion mit einem Revert ab.
  • Limit-Order auf einem nicht abgestimmten Tick eröffnen → TickAndSpacingNotMatch. Quantisieren Sie Ticks immer über den exportierten Helfer getOrderTick.
  • decreaseLimitOrder bei einer vollständig gefüllten Order aufrufen → InvalidOrderPhase. Verwenden Sie stattdessen settleLimitOrder und anschließend closeLimitOrder.
  • Ein Flag enableDynamicFee erwarten → Es gibt kein solches Flag. Wenn Sie dynamicFeeConfig weglassen, entsteht einfach ein Pool mit statischer Gebühr, und zwar ohne Fehlermeldung. Wenn Sie dynamische Gebühren möchten, übergeben Sie den PublicKey des Konfigurationskontos, den Sie unter /main/clmm-dynamic-config auswählen.

Wie es weitergeht

Quellen: