Cette page est traduite automatiquement par IA. La version anglaise fait foi.Voir la version anglaise →
Pourquoi les ticks existent
La liquidité de CLMM est concentrée dans des plages de prix. Pour rendre les plages tractables on-chain, les prix sont quantifiés en ticks entiers, où chaque tick est un multiple constant du précédent : Un tick correspond à un mouvement de prix de 0,01 %, soit environ 1 point de base. Le mappage est :MIN_TICK et MAX_TICK sont choisis de sorte que sqrt_price_x64 tienne dans un u128 aux deux extrémités. Chaque pool impose que tick_lower >= MIN_TICK et tick_upper <= MAX_TICK. En pratique, l’interface web restreint la plage à quelque chose de beaucoup plus étroit pour éviter que les utilisateurs ne verrouillent la liquidité dans des ticks inaccessibles.
Espacement des ticks
L’AmmConfig d’un pool fixe un espacement des ticks — les seuls ticks qu’une position est autorisée à utiliser comme points d’extrémité. Si tick_spacing = 60, seuls les ticks …, −120, −60, 0, 60, 120, … sont valides. Une tentative d’ouverture d’une position avec le point d’extrémité 31 revient avec InvalidTickIndex.
Espacements publiés courants :
Plus l’espacement est grossier, moins il y a de tick arrays à initialiser, moins cher il est d’ouvrir une position large, et plus floue est la limite de prix. Les paires volatiles vivent généralement dans les niveaux d’espacement 120 ; les stables vivent dans les niveaux d’espacement 1.
Tick arrays
Le pool ne stocke pas l’état par tick dans des comptes séparés. Au lieu de cela,TICK_ARRAY_SIZE ticks adjacents (60 dans le CLMM Raydium actuel) sont compressés dans un seul TickArrayState. Le premier tick du tableau est son start_tick_index, et il couvre exactement TICK_ARRAY_SIZE * tick_spacing unités de tick entier.
Pour tick_spacing = 60 et TICK_ARRAY_SIZE = 60 :
- Chaque tick array s’étend sur
60 × 60 = 3600ticks entiers. start_tick_indexest un multiple de 3600 :…, -7200, -3600, 0, 3600, 7200, ….
t = 2040 à tick_spacing = 60 réside dans le tick array avec start_tick_index = 0. Un point d’extrémité de position t = 4200 réside dans le tableau avec start_tick_index = 3600.
Quand un tableau est créé
Un tick array est lazy : la première position qui référence un tick à l’intérieur initialise le tableau, en payant le loyer. Les swaps n’initialisent pas les tick arrays — ils les contournent en utilisant le bitmap. Le flux open-position du SDK inspecte la plage choisie, calcule la liste des tick arrays qu’il touche, et ajoute les instructionsinit_tick_array dans la même transaction que OpenPosition si l’une d’elles manque.
Les tick arrays ne sont pas fermés
Une fois qu’un tick array a été initialisé, il persiste pour la durée de vie du pool. Le programme n’expose pas de chemin pour fermer un tick array, même après queinitialized_tick_count revienne à zéro. Il n’y a pas de récupération de loyer pour les tick arrays ; le loyer payé par la première position qui touche un tableau est verrouillé dans ce compte de manière permanente. C’est un compromis délibéré : réutiliser un tick array existant est gratuit pour chaque position ultérieure, donc un pool fortement échangé ne paie le coût du loyer qu’une seule fois par slot (pool, start_tick_index) indépendamment du renouvellement.
Le bitmap
Trouver « le prochain tick initialisé à gauche/droite du tick actuel » doit être rapide — un swap peut traverser de nombreux ticks. Le pool stocke un bitmap 1-bit-par-tick-array en ligne dansPoolState pour la plage ±1 024 tableaux autour du tick 0. En dehors de cette plage (positions full-range, configurations exotiques), TickArrayBitmapExtension fournit le débordement.
Un swap parcourt le bitmap : lowest_set_bit_above(tick_current_array_index) donne le prochain tableau avec un tick initialisé du côté vers lequel le swap se dirige. Dans ce tableau, un balayage de bit similaire localise le prochain tick initialisé.
liquidity_gross et liquidity_net
Chaque tick initialisé stocke deux valeurs de liquidité :
liquidity_gross— la somme deLsur toutes les positions qui référencent ce tick comme point d’extrémité. Quandliquidity_grossatteint zéro, le tick devient non initialisé et peut être supprimé du bitmap.liquidity_net— le changement signé à la liquidité au niveau du pool quand le prix traverse ce tick en se déplaçant vers le haut (de gauche à droite dans l’espace des ticks). Si ce tick est la limite inférieure d’une position de tailleL, il contribue+L; s’il est la limite supérieure de cette position, il contribue−L.
- Position A :
tick_lower = -120,tick_upper = 0, liquiditéL_A = 100. - Position B :
tick_lower = -60,tick_upper = 60, liquiditéL_B = 50.
Liquidité au niveau du pool pour différentes valeurs de
tick_current :
tick_current = -180:liquidity = 0(avant toute position)tick_current = -90:liquidity = 100(à l’intérieur de A uniquement)tick_current = -30:liquidity = 150(à l’intérieur de A et B)tick_current = 30:liquidity = 50(à l’intérieur de B uniquement)tick_current = 90:liquidity = 0(après les deux)
liquidity_net (possiblement négatif) à PoolState.liquidity. C’est le mécanisme exact d’Uniswap-v3.
Positions en tant que NFT
Une position CLMM Raydium est un NFT. L’ouverture d’une position crée un nouveau mint avec un approvisionnement de 1 dans le portefeuille de l’appelant, et l’autorité du mint est le programme CLMM. Le programme lie la propriété de la position à celui qui détient un solde dans un ATA de ce mint au moment du CPI. Conséquences :- Les positions sont normalement transférables. Un portefeuille peut vendre ou airdrop une position en transférant le NFT. Le nouveau détenteur peut alors appeler
CollectRewards,IncreaseLiquidity, etc. L’exception est une position gelée selon le chemin de l’émetteur restreint ci-dessous. - Les positions sont adressables en dehors de CLMM. Les places de marché et les portefeuilles affichent les positions comme d’autres NFT. Le SDK définit un
name/symbolraisonnable sur les métadonnées du mint. - Le PDA d’une position est dérivé du mint NFT. Vous pouvez trouver le
PersonalPositionStatesans savoir qui le détient actuellement.
Positions d’émetteur restreint
Chaque mint NFT de position créé après la mise à niveau 2026-08 enregistre sonpool_state CLMM comme autorité de gel. Cela ne signifie pas que chaque nouvelle position est gelée. Pour les pools ordinaires et chaque position non correspondante, le compte de token NFT reste dégelé et transférable. Le PDA du pool ne peut pas signer en dehors du programme CLMM, et CLMM n’expose aucune instruction de gel à usage général.
Le gel nécessite ces deux conditions :
- La position est ouverte via
OpenPositionV2ouOpenPositionWithToken22Nft. - Au moins un mint de coffre du pool porte une autorité de gel de la liste d’émetteurs restreints codée en dur du programme.
OpenPosition V1 n’applique pas ce filtre. Voir reference/program-addresses pour la liste actuelle.
Une position gelée :
- Ne peut pas transférer son NFT à un autre compte de token.
- Ne peut pas changer le propriétaire du compte de token NFT.
- Peut toujours augmenter ou diminuer la liquidité et collecter les frais ou récompenses quand le propriétaire enregistré signe.
- Peut toujours se fermer.
ClosePositionutilise le PDA du pool pour dégeler le compte NFT, puis brûle le NFT et ferme les comptes de position dans la même instruction.
Positions Token-2022
CLMM peut créer un NFT de position sous le Token SPL classique viaOpenPositionV2, ou sous Token-2022 via OpenPositionWithToken22Nft. Les deux chemins V2 inspectent les mints de coffre du pool et appliquent la même règle de gel d’émetteur restreint. OpenPosition V1 est le chemin classique-token hérité et ne peut pas servir un pool avec des mints de coffre Token-2022. La compatibilité des portefeuilles et des places de marché diffère ; l’interface utilisateur de Raydium suit les deux programmes NFT.
Règles de plage autorisée
Au moment deOpenPosition, le programme impose :
tick_lower < tick_upper.tick_lower % tick_spacing == 0ettick_upper % tick_spacing == 0.MIN_TICK <= tick_lowerettick_upper <= MAX_TICK.- L’appelant a fourni les tick arrays contenant
tick_lowerettick_upper— soit déjà initialisés, soit via uninit_tick_arraydans la même transaction. - Le compte d’extension bitmap, si cette position s’étend dans la plage d’extension.
InvalidTickIndex, NotApproved, ou InsufficientLiquidity selon la contrainte. Voir reference/error-codes.
« In-range » vs « out-of-range »
Une position est in-range quandtick_lower <= tick_current < tick_upper. Seules les positions in-range contribuent à PoolState.liquidity et donc seules elles gagnent des frais de swap.
Une position out-of-range :
- Détient 100 % d’un token (celui dont sa plage a dépassé). Spécifiquement, si
tick_current < tick_lower, la position ne détient que le token1 (elle a déjà été « vendue » par le prix s’éloignant) ; sitick_current >= tick_upper, elle ne détient que le token0. - Ne gagne pas les frais de swap.
- Continue à accumuler les récompenses si les flux de récompenses du pool émettent vers la liquidité out-of-range — mais le comportement par défaut de Raydium est « émettre uniquement vers in-range », correspondant à la convention Uniswap v3. Voir
products/clmm/fees.
Pièges d’intégration courants
- Points d’extrémité hors espacement. Le code qui calcule un tick à partir d’un prix cible doit s’aligner sur un multiple de
tick_spacingavant de le passer àOpenPosition. Les assistants du SDK (TickUtils.getTickWithPriceAndTickspacing) le font ; les mathématiques maison souvent ne le font pas. - Tick arrays manquants. L’ouverture d’une position large peut nécessiter l’initialisation de plusieurs tick arrays ; oublier de les passer en tant que comptes inscriptibles revient. Le
openPositionFromBasedu SDK vous retourne la liste. - Tick obsolète après un swap.
tick_currentpeut traverser de nombreux ticks en un seul swap. Si votre UX affiche un « tick actuel » d’un appel RPC et ouvre ensuite une position dans un appel ultérieur, la position relative par rapport au prix en direct peut être décalée de dizaines de ticks. Récupérez à nouveau juste avant de signer. - NFT de position avec métadonnées supplémentaires. Si vous construisez un portefeuille qui reconnaît les positions Raydium, utilisez le PDA de position / données du programme et non un champ de métadonnées codé en dur. Les nouveaux mints de position utilisent le PDA du pool comme autorité de mint et de gel à la création ; l’autorité de mint est supprimée après le minage du seul NFT.
- Supposer que chaque position est transférable. Lisez l’état
isFrozendu compte de token NFT avant d’afficher les actions de transfert, place de marché, séquestre, ou Burn & Earn.
Où aller ensuite
- Math — le passage du swap et la dérivation de la croissance des frais auxquels les limites des ticks participent.
- Comptes — les dispositions
TickArrayStateetPositionState. - Frais et récompenses — comment l’in-range-ness contrôle l’accumulation des frais.
algorithms/clmm-math— la dérivation partagée des formules de liquidité concentrée.
raydium-io/raydium-clmm— modulestick_array,tick,position- Livre blanc « Uniswap v3 Core », §6 (ticks), §7 (fee growth)

