Skip to main content
Cette page est traduite automatiquement par IA. La version anglaise fait foi.Voir la version anglaise →
Cette page décrit la structure et le rôle de chaque compte. Les seeds sont canoniques et listés dans reference/program-addresses. Un pool CLMM est plus lourd en comptes qu’un pool CPMM car la liquidité est stockée de manière clairsemée sur la plage de ticks ; comprendre cette clairsemé est l’essentiel de cette page.

Inventaire des comptes

Un pool CLMM actif est décrit par les familles de comptes suivantes. Tous sont possédés par le programme CLMM sauf les deux mints et leurs vaults.

PoolState

L’état actif du pool, lu à chaque swap et à chaque changement de position.
Champs que vous allez réellement utiliser :
  • sqrt_price_x64 et tick_current sont l’état des prix du pool. Ils sont mis à jour ensemble à chaque swap. tick_current est le plancher de log_{1.0001}(price).
  • liquidity est la liquidité active — la somme des valeurs L pour toutes les positions dont la plage contient tick_current. Elle change chaque fois qu’un swap traverse un tick et chaque fois qu’une position est ouverte/fermée/redimensionnée.
  • fee_growth_global_{0,1}_x64 sont les frais cumulatifs gagnés par unité de liquidité sur tout l’historique du pool. Les positions lisent ceci pour calculer ce qui leur est dû.
  • tick_spacing est verrouillé sur AmmConfig à l’initialisation et ne change jamais. Il détermine quels indices de tick sont autorisés à être des points d’extrémité de position.
  • tick_array_bitmap est un bitmap inline couvrant la plage de ticks couramment utilisée autour du prix spot. Pour les pools dont les positions s’étendent loin, le suivi du débordement vit dans le TickArrayBitmapExtension séparé.
  • fee_on est fixé à la création du pool. 0 (FromInput) reproduit le comportement classique d’Uniswap-V3. 1 et 2 acheminent les frais de swap vers un seul côté du carnet — voir products/clmm/fees pour les compromis.
  • seed_index est [0, 0] pour chaque pool créé via CreatePool / CreateCustomizablePool (un pool canonique par paire). Une valeur non-zéro signifie que le pool a été créé via CreateCustomizablePoolV2 (nommé CreatePermissionedPool avant 2026-10-22) et l’index fait partie des seeds PDA du pool, permettant à plusieurs pools de coexister pour le même (config, mint0, mint1). Pour re-dériver l’adresse d’un tel pool, vous devez connaître son seed_index.
  • dynamic_fee_info porte l’état de volatilité pour la surcharge de frais dynamiques. Quand activé, chaque swap recalcule un dynamic_fee_component en plus de AmmConfig.trade_fee_rate. La structure est documentée sous DynamicFeeInfo ci-dessous ; les pools sans frais dynamiques laissent la structure entière à zéro.

AmmConfig

Depuis la mise à jour 2026-09, CreateAmmConfig écrit le protocol_fee_owner::ID codé en dur du programme dans owner et le fund_fee_owner::ID dans fund_owner. Avant cela, il copiait la clé du signataire admin dans les deux. Les configs existantes conservent ce qu’elles ont été créées ou rotées, donc lisez les deux champs du compte. Les paramètres UpdateAmmConfig 3 / 4 les font toujours tourner. Les adresses sont dans reference/program-addresses. Un ensemble typique de paliers de frais CLMM publiés (confirmez par rapport à GET https://api-v3.raydium.io/main/clmm-config) : protocol_fee_rate et fund_fee_rate sont des fractions des frais commerciaux ; même convention que CPMM. Voir products/clmm/fees.

TickArrayState

CLMM ne stocke pas un enregistrement unique par tick. Cela représenterait des milliards de comptes. À la place, il regroupe TICK_ARRAY_SIZE ticks adjacents initialisés ou non (généralement 60 ou 88 selon la version du programme) dans un TickArrayState créé de manière paresseuse à la première utilisation.
Les quatre champs de limite d’ordre sont zéro sur tout tick qui n’a jamais été utilisé pour un ordre limite. Quand des ordres sont ouverts sur un tick, le programme les suit comme une séquence de cohortes :
  • order_phase est l’identifiant de la cohorte. Il s’incrémente chaque fois qu’une cohorte passe de « complètement non remplie » à « partiellement remplie ».
  • orders_amount est le total du jeton d’entrée de la cohorte actuelle (la plus récente).
  • part_filled_orders_remaining suit la cohorte précédente qui est actuellement remplie par les swaps en cours.
  • unfilled_ratio_x64 est un multiplicateur Q64.64 porté sur la cohorte : quand un swap remplit X% de la cohorte, le ratio est multiplié par (1 − X). Chaque ordre ouvert stocke son propre snapshot (order_phase, unfilled_ratio_x64) au moment de l’ouverture, donc les mathématiques de règlement se réduisent à comparer les snapshots.
Règles :
  • Un tick d’extrémité de position t doit satisfaire t % tick_spacing == 0. Le programme rejette les positions mal espacées.
  • Le tableau du tick est situé à floor(t / (TICK_ARRAY_SIZE * tick_spacing)) * (TICK_ARRAY_SIZE * tick_spacing).
  • Un tableau de ticks est initialisé de manière paresseuse : la première position ou le premier swap qui touche un tableau non initialisé le crée, en payant le loyer.
  • Un tableau de ticks n’est jamais fermé par le programme. Une fois alloué, il persiste pour la durée de vie du pool, même après que chaque tick à l’intérieur revienne à liquidity_gross == 0. Les positions et swaps ultérieurs réutilisent le compte existant sans loyer supplémentaire. Il n’existe pas de chemin de nettoyage piloté par ClosePosition pour les tableaux de ticks.

TickArrayBitmapExtension

PoolState.tick_array_bitmap (en ligne) couvre la plage « proche du spot » — ±512 tableaux de ticks (TICK_ARRAY_BITMAP_SIZE = 512 ; le champ [u64; 16] est 1 024 bits divisés équitablement entre les indices de départ négatifs et positifs, donc les indices de tableau −512 … +511). En dehors de cette plage (pour les valeurs de tick extrêmes), le programme maintient un compte d’extension :
Si la plage de votre position est « normale », vous ne pensez jamais au compte d’extension. Les positions de plage complète (par exemple, (MIN_TICK, MAX_TICK)) le nécessitent ; le SDK le résout pour vous.

Positions

Une position CLMM est un ensemble de trois comptes plus un mint :

Position NFT mint

Un mint SPL Token ou Token-2022 avec une offre de 1. Le NFT de position dans le portefeuille du propriétaire est un ATA contenant ce jeton unique. Le programme lie l’autorisation au détenteur actuel du solde ATA du NFT, et non à une Pubkey stockée dans l’état. Les nouveaux mints NFT de position définissent pool_state comme leur autorité de gel avant de frapper le jeton unique et de supprimer l’autorité de mint. Définir une autorité de gel ne gèle pas en soi le compte NFT. Le compte reste dégelé et transférable sauf si les deux conditions sont remplies : l’appelant utilise OpenPositionV2 ou OpenPositionWithToken22Nft, et au moins l’autorité de gel d’un mint de coffre-fort sous-jacent apparaît sur la liste des émetteurs restreints de CLMM. Ce n’est que dans ce cas que CLMM gèle le compte NFT après la frappe. Cela ne change aucun octet de PersonalPositionState ou PoolState.

PersonalPositionState

Un par position ouverte. Clé basée sur le mint NFT.

ProtocolPositionState (obsolète)

Les versions plus anciennes de CLMM stockaient la comptabilité agrégée par (pool, tick_lower, tick_upper) dans un PDA ProtocolPositionState. Les versions plus récentes ne créent ni ne lisent plus ce compte. L’emplacement apparaît toujours sur les listes de comptes OpenPosition / IncreaseLiquidity / DecreaseLiquidity comme un UncheckedAccount pour la compatibilité ABI, mais le programme n’y écrit pas. Les comptes existants en chaîne sont vestigiaux ; l’administrateur peut appeler CloseProtocolPosition pour récupérer le loyer pour eux.La comptabilité de plage agrégée est maintenant dérivée directement des deux ticks d’extrémité (liquidity_gross, liquidity_net, et les fee_growth_outside_* / reward_growths_outside_x64 par tick) dans TickArrayState. La formule de croissance des frais fee_growth_inside = global − outside_lower − outside_upper continue de fonctionner sans un compte de position agrégée.

Observation

Le tampon d’observation de CLMM stocke un tick cumulatif, pas un prix cumulatif. Les consommateurs externes calculent le prix de la moyenne géométrique sur un intervalle à partir de (tick_cumulative[t1] − tick_cumulative[t0]) / (t1 − t0) puis price = 1.0001 ** tick. Voir algorithms/clmm-math.

DynamicFeeConfig et DynamicFeeInfo

Les paramètres de frais dynamiques vivent à deux endroits. Le modèle réutilisable — DynamicFeeConfig — est géré par l’administrateur et partagé entre les pools qui l’acceptent. L’état d’exécution par pool — DynamicFeeInfo — est intégré dans PoolState et mis à jour par chaque swap.

DynamicFeeConfig

Graine PDA : ["dynamic_fee_config", index.to_be_bytes()]. Créé via create_dynamic_fee_config (protégé par l’administrateur) et modifié via update_dynamic_fee_config. Un pool créé avec enable_dynamic_fee = true capture les cinq paramètres d’étalonnage de la configuration (filter_period, decay_period, reduction_factor, dynamic_fee_control, max_volatility_accumulator) dans son propre DynamicFeeInfo au moment de la création ; les modifications ultérieures à DynamicFeeConfig n’affectent pas rétroactivement les pools existants.

DynamicFeeInfo (intégré dans PoolState)

Les quatre champs du bas sont l’état ; les cinq du haut sont l’étalonnage copié de DynamicFeeConfig. Les mathématiques des frais et les règles de décroissance sont documentées sous products/clmm/math et products/clmm/fees. Constantes utilisées par la formule :

LimitOrderState

Un compte par ordre limite ouvert.
Cycle de vie :
  1. Ouverture — l’utilisateur appelle open_limit_order, dépose total_amount du jeton d’entrée, l’ordre est lié à une cohorte TickState.
  2. (optionnel) Augmentation / Diminution — increase_limit_order ajoute à total_amount ; decrease_limit_order retourne les jetons non remplis (et tout résultat réglé jusqu’à ce point).
  3. Règlement — quand la cohorte est complètement ou partiellement remplie, le propriétaire ou le gardien opérationnel appelle settle_limit_order pour pousser les jetons de sortie vers l’ATA du propriétaire.
  4. Fermeture — une fois que unfilled_amount == 0, le compte est fermable. Le loyer retourne toujours à owner.
Graine PDA : [owner.as_ref(), limit_order_nonce.key().as_ref(), limit_order_nonce.order_nonce.to_be_bytes().as_ref()]. Le PDA de l’ordre est donc unique par (owner, nonce_index, order_nonce).

LimitOrderNonce

Compteur par (wallet, nonce_index) qui permet à un utilisateur unique d’exécuter plusieurs pipelines parallèles d’ordres limités sans collision sur les PDAs.
Seed PDA : [user_wallet.as_ref(), &[nonce_index]]. La plupart des clients utilisent nonce_index = 0 et laissent order_nonce porter la cardinalité.

Permission (retiré)

Le compte Permission a été supprimé lors de la mise à jour du 2026-10-22. Il servait autrefois à contrôler CreatePermissionedPool, qui est maintenant le CreateCustomizablePoolV2 sans permission. Le programme ne lit ni ne ferme plus ces comptes, et les instructions CreatePermissionPda / ClosePermissionPda ont disparu. Les PDAs créés avant la mise à jour (["permission", authority], 280 octets) restent sur la chaîne en tant que données inactives ; ignorez-les lors du balayage des comptes appartenant à CLMM.

Dérivation des comptes clés

Les chaînes de seed exactes doivent toujours être vérifiées par rapport à l’IDL on-chain et à reference/program-addresses.

Référence rapide du cycle de vie

Les comptes TickArrayState ne sont jamais fermés par le programme — ils persistent pendant toute la durée de vie du pool. Une fois qu’un tableau de tick a été initialisé, il reste sur la chaîne même si chaque tick à l’intérieur revient à liquidity_gross == 0. La réutilisation d’un tableau de tick existant est gratuite ; seule la première position qui touche un tableau jamais initialisé paie son loyer.

Où lire quoi

Sources :