Skip to main content
Cette page est traduite automatiquement par IA. La version anglaise fait foi.Voir la version anglaise →

Configuration

Chaque exemple de cette page reprend un fichier du dépôt raydium-sdk-V2-demo/src/clmm ; le lien GitHub figure à côté de chaque section. L’initialisation suit le fichier config.ts.template du dépôt de démonstration (source). Pour toute intégration non triviale, nous recommandons de définir disableFeatureCheck: true :

Créer un pool CLMM

Source : src/clmm/createPool.ts
Le SDK :
  • Trie mint1 et mint2 selon l’ordre des octets avant la dérivation.
  • Calcule sqrt_price_x64 = floor(sqrt(initialPrice × 10^(dB−dA)) × 2^64).
  • Crée les comptes observation et tick_array_bitmap_extension.
  • Acquitte les frais de création de pool définis par ammConfig.

Ouvrir une position dans une plage de prix choisie

Source : src/clmm/createPosition.ts
Le SDK calcule les tick arrays couverts par la plage et les transmet comme comptes. Il n’a pas besoin d’inclure d’instruction d’initialisation : il n’existe pas d’instruction d’initialisation de tick array. OpenPosition* alloue lui-même un tick array manquant, aux frais du payeur.

Augmenter la liquidité d’une position existante

Source : src/clmm/increaseLiquidity.ts

Réduire la liquidité (et collecter les frais en même temps)

Source : src/clmm/decreaseLiquidity.ts et src/clmm/closePosition.ts
Pour collecter uniquement les frais et les récompenses, appelez decreaseLiquidity avec liquidity = new BN(0). Cette instruction règle les montants token_fees_owed_{0,1} et reward_amount_owed, puis les transfère : c’est le seul moyen de collecter l’un ou l’autre. Pour fermer entièrement la position après avoir ramené la liquidité et les frais à zéro, passez ownerInfo: { closePosition: true } lors du dernier appel à decreaseLiquidity. Le SDK ajoute l’instruction ClosePosition et brûle le NFT.
Les positions à émetteur restreint nécessitent un constructeur de fermeture compatible. Ces positions disposent d’un compte de jetons NFT gelé. ClosePosition doit ajouter l’identifiant du pool de la position comme premier compte restant, afin que CLMM puisse dégeler le compte avant de le brûler. La branche du code source du programme ne contient aucune modification du SDK. Vérifiez que votre version du SDK prend explicitement en charge le chemin de fermeture pour les comptes gelés avant d’activer la création de positions à émetteur restreint.
Pour un client Anchor direct, conservez les comptes déclarés tels quels et ajoutez le pool :
Vous pouvez transmettre poolId à chaque fermeture. CLMM ne le lit que lorsque positionNftAccount est gelé, ce qui permet à un même chemin client de fonctionner avec les anciennes comme avec les nouvelles positions.

Collecter la ou les récompenses

Source : src/clmm/harvestAllRewards.ts
harvestAllRewards parcourt chaque position de chaque pool transmis, regroupe les appels DecreaseLiquidity à liquidité nulle qui règlent les frais et les récompenses (ainsi que les éventuels UpdateRewardInfos), puis les répartit si nécessaire entre plusieurs transactions.

Swap

Source : src/clmm/swap.ts Ce code reprend src/clmm/swap.ts, qui effectue la simulation avec swapInternal plutôt qu’avec PoolUtils.computeAmountOutFormat.
La simulation parcourt la tick map hors chaîne avec la même logique que le programme on-chain, et renvoie le montant de sortie (amountCalculated) ainsi que la liste exacte des comptes que le swap va utiliser (accounts). Transmettez toujours les remainingAccounts renvoyés par la simulation : s’il en manque, le swap échoue en cours de parcours avec NotEnoughTickArrayAccount ; s’il y en a de périmés, vous ne faites que consommer du compute inutilement.
PoolUtils.computeAmountOutFormat existe toujours, mais il requiert un ComputeClmmPoolInfo (le computePoolInfo retourné par getPoolInfoFromRpc, et non un objet pool issu de l’API), ainsi que deux arguments obligatoires supplémentaires : tickarrayBitmapExtension et blockTimestamp. Il n’existe pas non plus de méthode raydium.clmm.fetchTickArrays (fetchTickArrays est une fonction libre ; les helpers au niveau du module sont PoolUtils.fetchMultiplePoolTickArrays et les tickData / tickArrays retournés par getPoolInfoFromRpc).

Créer un pool CLMM personnalisable

createCustomizablePool est le point d’entrée qui expose les options de frais dynamiques et de frais à un seul côté au moment de la création du pool. Il reprend la signature de createPool avec deux paramètres supplémentaires :
Il n’existe ni paramètre enableDynamicFee, ni paramètre dynamicFeeConfigId, ni paramètre startTime. Fournir dynamicFeeConfig est ce qui active les frais dynamiques : si vous l’omettez, vous obtenez un pool à frais statiques, sans aucune erreur. Notez également que les membres de l’énumération du SDK s’appellent TokenOnlyA / TokenOnlyB, alors que l’énumération Rust on-chain les nomme Token0Only / Token1Only. Les valeurs numériques correspondent (FromInput = 0).
createPool continue de fonctionner pour le chemin à frais par défaut, sans frais dynamiques. Utilisez createCustomizablePool dès que vous avez besoin de l’une de ces options. Consultez products/clmm/instructions pour la liste des comptes on-chain.

Ordres limites

Un ordre limite immobilise les fonds de l’utilisateur sur un tick unique, puis est exécuté selon la règle FIFO lorsqu’un swap franchit ce tick. Les montants obtenus sont envoyés vers l’ATA du propriétaire au moment du règlement ; le propriétaire n’a pas besoin d’être en ligne pour que l’ordre soit exécuté.

Ouvrir un ordre limite

Il n’existe ni configuration d’ordre limite par pool, ni helper getClmmLimitOrderConfigs() : les ordres sont identifiés par tick.
Le SDK dérive le PDA LimitOrderState à partir de (owner, nonce PDA, order nonce), incrémente le LimitOrderNonce propre au portefeuille, et insère l’ordre dans la cohorte FIFO correspondant à ce tick.

Augmenter / réduire un ordre ouvert

decreaseLimitOrder ne peut retirer que la partie non exécutée de l’ordre ; la partie exécutée reste bloquée jusqu’au règlement. Les deux instructions échouent avec InvalidOrderPhase si l’ordre a déjà été entièrement exécuté.

Régler un ordre exécuté

settleLimitOrder lit unfilled_ratio_x64 de l’ordre par rapport au suivi de la cohorte, calcule le montant exécuté et le transfère vers l’ATA du propriétaire. Le propriétaire peut appeler cette instruction lui-même ; limit_order_admin (un keeper opérationnel hors chaîne) peut aussi l’appeler pour le compte du propriétaire, le montant restant dans tous les cas destiné au propriétaire. Pour fermer les ordres entièrement réglés et récupérer le loyer, utilisez closeLimitOrder (unitaire) ou closeAllLimitOrder (par lot). Pour régler plusieurs ordres à la fois, settleAllLimitOrder regroupe autant d’appels SettleLimitOrder que possible dans une transaction v0.

Lister les ordres en attente d’un portefeuille (hors chaîne)

L’endpoint des ordres actifs renvoie dans une même réponse les ordres non exécutés et partiellement exécutés (totalAmount / filledAmount / pendingSettle permettent de distinguer les phases). Pour l’historique des ordres clôturés, utilisez /limit-order/history/order/list-by-user?wallet=… (par portefeuille, paginé par nextPageId) ; pour le journal complet des événements d’un ordre donné, utilisez /limit-order/history/event/list-by-pda?pda=….

Squelette de CPI en Rust

Ordre des comptes restants pour SwapV2 :
Si le swap n’a jamais besoin de l’extension, omettez-la ; sinon, elle occupe la première position parmi les comptes restants.

Pièges courants

  • Bornes de tick mal alignées → TickAndSpacingNotMatch. Alignez toujours les valeurs avec TickUtil.getPriceAndTick (au singulier, TickUtil).
  • Nombre insuffisant de tick arrays fournis dans SwapV2 → NotEnoughTickArrayAccount. Récupérez la liste depuis swapInternal(...).accounts.
  • Position pleine largeur sans l’extension de bitmap → le PDA de l’extension doit être accessible en écriture. Le SDK s’en charge automatiquement.
  • Confondre sqrt_price_x64 avec price → une erreur de facteur 2 est ici particulièrement pénible. En cas de doute, laissez le SDK calculer la valeur à partir d’un prix lisible.
  • Réclamer les récompenses trop souvent → chaque collecte est un DecreaseLiquidity à liquidité nulle et coûte une transaction. Regroupez les opérations avec harvestAllRewards sur plusieurs positions, et n’oubliez pas que son execute nécessite { sequentially: true }.
  • Fermer soi-même les comptes NFT → ClosePosition brûle le NFT et ferme son ATA. Il ferme aussi un mint NFT Token-2022 ; un mint SPL Token classique reste en circulation à zéro, car ce programme ne peut pas fermer les mints. Ne fermez pas séparément les comptes pris en charge, sinon l’instruction échouera.
  • Ouvrir un ordre limite sur un tick non aligné → TickAndSpacingNotMatch. Quantifiez toujours la valeur avec le helper exporté getOrderTick.
  • Appeler decreaseLimitOrder sur un ordre entièrement exécuté → InvalidOrderPhase. Utilisez plutôt settleLimitOrder, puis closeLimitOrder.
  • Chercher un indicateur enableDynamicFee → il n’existe pas. Omettre dynamicFeeConfig crée simplement un pool à frais statiques, sans aucune erreur ni avertissement. Si vous souhaitez des frais dynamiques, passez le PublicKey du compte de configuration, récupéré depuis /main/clmm-dynamic-config.

Où aller ensuite

Sources :