Saltar al contenido principal
Esta página fue traducida automáticamente por IA. La versión en inglés es la fuente autorizada.Ver versión en inglés →
Esta página describe el esquema y rol de cada cuenta. Las semillas canónicas están listadas en reference/program-addresses. Un pool CLMM utiliza más cuentas que un pool CPMM porque la liquidez se almacena de forma dispersa a lo largo del rango de ticks; comprender esa dispersión es el tema central de esta página.

Inventario de cuentas

Un pool CLMM activo se describe mediante las siguientes familias de cuentas. Todas pertenecen al programa CLMM, excepto los dos mints y sus vaults.

PoolState

El estado en vivo del pool, leído en cada swap y en cada cambio de posición.
Campos con los que interactuarás directamente:
  • sqrt_price_x64 y tick_current representan el estado de precio del pool. Se actualizan juntos en cada swap. tick_current es el entero inferior de log_{1.0001}(price).
  • liquidity es la liquidez activa: la suma de los valores L de todas las posiciones cuyo rango contiene a tick_current. Cambia cada vez que un swap cruza un tick y cada vez que se abre, cierra o redimensiona una posición.
  • fee_growth_global_{0,1}_x64 son las comisiones acumuladas por unidad de liquidez a lo largo de toda la historia del pool. Las posiciones los leen para calcular lo que se les debe.
  • tick_spacing queda fijado al AmmConfig durante la inicialización y nunca cambia. Determina qué índices de tick pueden ser puntos extremos de una posición.
  • tick_array_bitmap es un bitmap inline que cubre el rango de ticks más habitual alrededor del precio spot. Para pools con posiciones muy alejadas del centro, el seguimiento del desbordamiento vive en la cuenta separada TickArrayBitmapExtension.
  • fee_on se fija en el momento de la creación del pool. El valor 0 (FromInput) reproduce el comportamiento clásico de Uniswap V3. Los valores 1 y 2 dirigen la comisión de swap a un solo lado del libro — consulta products/clmm/fees para ver los compromisos de diseño.
  • dynamic_fee_info almacena el estado de volatilidad para el recargo de comisión dinámica. Cuando está habilitado, cada swap recalcula un dynamic_fee_component sobre AmmConfig.trade_fee_rate. El esquema se documenta en DynamicFeeInfo más abajo; los pools sin comisión dinámica dejan toda la estructura en cero.

AmmConfig

Conjunto típico de niveles de comisión CLMM publicados (verifica contra GET https://api-v3.raydium.io/main/clmm-config): protocol_fee_rate y fund_fee_rate son fracciones de la comisión de trading; misma convención que en CPMM. Consulta products/clmm/fees.

TickArrayState

El CLMM no almacena un registro por tick individual, ya que eso implicaría miles de millones de cuentas. En cambio, agrupa TICK_ARRAY_SIZE ticks adyacentes (inicializados o no, típicamente 60 u 88 según la versión del programa) en un TickArrayState que se crea de forma diferida en el primer uso.
Los cuatro campos de orden límite son cero en cualquier tick que nunca haya sido usado para una orden límite. Cuando se abren órdenes en un tick, el programa las gestiona como una secuencia de cohortes:
  • order_phase es el identificador de cohorte. Se incrementa cada vez que una cohorte pasa de «totalmente sin ejecutar» a «parcialmente ejecutada».
  • orders_amount es el total en tokens de entrada de la cohorte actual (la más reciente).
  • part_filled_orders_remaining lleva el seguimiento de la cohorte anterior que está siendo ejecutada en curso por los swaps activos.
  • unfilled_ratio_x64 es un multiplicador Q64.64 asociado a la cohorte: cuando un swap ejecuta el X% de la cohorte, el ratio se multiplica por (1 − X). Cada orden abierta almacena su propio snapshot de (order_phase, unfilled_ratio_x64) en el momento de apertura, por lo que la liquidación se reduce a comparar snapshots.
Reglas:
  • Un tick t que sea extremo de posición debe satisfacer t % tick_spacing == 0. El programa rechaza posiciones que no respeten el espaciado.
  • El array de un tick se ubica en floor(t / (TICK_ARRAY_SIZE * tick_spacing)) * (TICK_ARRAY_SIZE * tick_spacing).
  • Un tick array se inicializa de forma diferida: la primera posición o swap que toca un array no inicializado lo crea y paga el alquiler.
  • El programa nunca cierra un tick array. Una vez asignado, persiste durante toda la vida del pool, incluso después de que todos los ticks dentro de él vuelvan a liquidity_gross == 0. Las posiciones y swaps posteriores reutilizan la cuenta existente sin coste adicional de alquiler. No existe una ruta de limpieza de tick arrays derivada de ClosePosition.

TickArrayBitmapExtension

PoolState.tick_array_bitmap (inline) cubre el rango «cercano al spot» — ±1.024 tick arrays. Fuera de ese rango (para valores de tick extremos), el programa mantiene una cuenta de extensión:
Si el rango de tu posición es «normal», nunca tendrás que pensar en la cuenta de extensión. Las posiciones de rango completo (p. ej., (MIN_TICK, MAX_TICK)) sí la requieren; el SDK la resuelve por ti.

Posiciones

Una posición CLMM es un conjunto de tres cuentas más un mint:

NFT mint de posición

Un mint de token SPL con supply 1. La dirección del mint es un PDA determinista; el NFT de posición en la wallet del propietario es simplemente una ATA que contiene ese único token. Transferir el NFT es el mecanismo por el que cambia de manos una posición — el programa vincula la autorización al titular actual del saldo en la ATA del NFT, no a una Pubkey almacenada en el estado.

PersonalPositionState

Una por posición abierta. Su clave se deriva del mint del NFT.

ProtocolPositionState (obsoleto)

Las versiones anteriores del CLMM almacenaban la contabilidad agregada por (pool, tick_lower, tick_upper) en un PDA llamado ProtocolPositionState. Las versiones más recientes ya no crean ni leen esta cuenta. El slot sigue apareciendo en las listas de cuentas de OpenPosition / IncreaseLiquidity / DecreaseLiquidity como UncheckedAccount por compatibilidad con el ABI, pero el programa no escribe en él. Las cuentas existentes en la cadena son vestigiales; el admin puede llamar a CloseProtocolPosition para recuperar el alquiler.La contabilidad agregada de rango ahora se deriva directamente de los dos ticks extremos (liquidity_gross, liquidity_net y los campos fee_growth_outside_* / reward_growths_outside_x64 por tick) en TickArrayState. La fórmula de crecimiento de comisiones dentro del rango fee_growth_inside = global − outside_lower − outside_upper sigue funcionando sin necesidad de una cuenta de posición agregada.

Observation

El buffer de observaciones del CLMM almacena un tick acumulado, no un precio acumulado. Los consumidores externos calculan el precio de media geométrica sobre un intervalo a partir de (tick_cumulative[t1] − tick_cumulative[t0]) / (t1 − t0) y luego price = 1.0001 ** tick. Consulta algorithms/clmm-math.

DynamicFeeConfig y DynamicFeeInfo

Los parámetros de comisión dinámica viven en dos lugares. La plantilla reutilizable — DynamicFeeConfig — es administrada por el admin y compartida entre los pools que la activan. El estado de ejecución por pool — DynamicFeeInfo — está embebido en PoolState y se actualiza en cada swap.

DynamicFeeConfig

Semilla PDA: ["dynamic_fee_config", index.to_be_bytes()]. Se crea mediante create_dynamic_fee_config (solo admin) y se modifica con update_dynamic_fee_config. Un pool creado con enable_dynamic_fee = true copia los cinco parámetros de calibración de la config (filter_period, decay_period, reduction_factor, dynamic_fee_control, max_volatility_accumulator) en su propio DynamicFeeInfo en el momento de la creación; las ediciones posteriores al DynamicFeeConfig no afectan retroactivamente a los pools existentes.

DynamicFeeInfo (embebido en PoolState)

Los cuatro campos inferiores son estado; los cinco superiores son la calibración copiada de DynamicFeeConfig. La matemática de la comisión y las reglas de decaimiento están documentadas en products/clmm/math y products/clmm/fees. Constantes usadas por la fórmula:

LimitOrderState

Una cuenta por orden límite abierta.
Ciclo de vida:
  1. Apertura — el usuario llama a open_limit_order, deposita total_amount del token de entrada y la orden queda vinculada a una cohorte de TickState.
  2. (Opcional) Aumento / Reducciónincrease_limit_order añade al total_amount; decrease_limit_order devuelve los tokens sin ejecutar (y cualquier output liquidado hasta ese momento).
  3. Liquidación — cuando la cohorte está total o parcialmente ejecutada, el propietario o el keeper operacional llama a settle_limit_order para enviar los tokens de salida a la ATA del propietario.
  4. Cierre — una vez que unfilled_amount == 0, la cuenta puede cerrarse. El alquiler siempre retorna al owner.
Semilla PDA: [owner.as_ref(), limit_order_nonce.key().as_ref(), limit_order_nonce.order_nonce.to_be_bytes().as_ref()]. El PDA de la orden es por tanto único por (owner, nonce_index, order_nonce).

LimitOrderNonce

Contador por (wallet, nonce_index) que permite a un mismo usuario ejecutar múltiples pipelines paralelas de órdenes límite sin colisionar en los PDAs.
Semilla PDA: [user_wallet.as_ref(), &[nonce_index]]. La mayoría de los clientes usan nonce_index = 0 y dejan que order_nonce gestione la cardinalidad.

Derivar las cuentas clave

Las cadenas de semilla exactas siempre deben verificarse contra el IDL on-chain y reference/program-addresses.

Referencia rápida del ciclo de vida

Las cuentas TickArrayState nunca son cerradas por el programa — persisten durante toda la vida del pool. Una vez inicializado un tick array, permanece en la cadena aunque todos los ticks dentro de él vuelvan a liquidity_gross == 0. Reutilizar un tick array existente es gratuito; solo la primera posición que toca un array nunca inicializado paga su alquiler.

Dónde leer cada tema

Fuentes: