Esta página foi traduzida automaticamente por IA. A versão em inglês é a fonte oficial.Ver versão em inglês →
Por que ticks existem
A liquidez do CLMM é concentrada em faixas de preço. Para tornar as faixas viáveis on-chain, os preços são quantizados em ticks inteiros, onde cada tick é um múltiplo constante do anterior: Um tick corresponde a um movimento de preço de 0,01%, ou ~1 basis point. O mapeamento é:MIN_TICK e MAX_TICK são escolhidos para que sqrt_price_x64 caiba em um u128 em ambas as extremidades. Cada pool garante que tick_lower >= MIN_TICK e tick_upper <= MAX_TICK. Na prática, a interface web limita o intervalo a algo muito mais estreito para evitar que os usuários travem liquidez em ticks inacessíveis.
Espaçamento de ticks
OAmmConfig de um pool define um espaçamento de ticks — os únicos ticks que uma posição pode usar como endpoints. Se tick_spacing = 60, apenas ticks …, −120, −60, 0, 60, 120, … são válidos. Uma tentativa de abrir uma posição com endpoint 31 reverte com TickAndSpacingNotMatch.
Espaçamentos publicados comuns:
Quanto mais grosseiro o espaçamento, menos tick arrays para inicializar, mais barato abrir uma posição ampla, e mais borrada a fronteira de preço. Pares voláteis normalmente vivem em camadas de espaçamento 120; stablecoins vivem em camadas de espaçamento 1.
Tick arrays
O pool não armazena estado por-tick em contas separadas. Em vez disso,TICK_ARRAY_SIZE ticks adjacentes (60 no CLMM atual do Raydium) são empacotados em um único TickArrayState. O primeiro tick do array é seu start_tick_index, e ele cobre exatamente TICK_ARRAY_SIZE * tick_spacing unidades de tick inteiro.
Para tick_spacing = 60 e TICK_ARRAY_SIZE = 60:
- Cada tick array abrange
60 × 60 = 3600ticks inteiros. start_tick_indexé um múltiplo de 3600:…, -7200, -3600, 0, 3600, 7200, ….
t = 2040 em tick_spacing = 60 vive no tick array com start_tick_index = 0. Um endpoint de posição t = 4200 vive no array com start_tick_index = 3600.
Quando um array é criado
Um tick array é lazy: a primeira posição que referencia qualquer tick dentro dele inicializa o array, pagando o aluguel. Swaps não inicializam tick arrays — eles pulam sobre arrays não inicializados usando o bitmap. Não existe uma instrução separada de init-tick-array:OpenPosition* e IncreaseLiquidity* chamam TickArrayState::get_or_create_tick_array internamente e alocam um array faltante às custas do payer. Você simplesmente passa o PDA do tick-array — mesmo quando ele ainda não está inicializado e é de propriedade do sistema.
Tick arrays não são fechados
Uma vez que um tick array foi inicializado, ele persiste pela vida do pool. O programa não expõe um caminho para fechar um tick array, mesmo depois queinitialized_tick_count retorna a zero. Não há recuperação de aluguel para tick arrays; o aluguel pago pela primeira posição que toca um array é travado naquela conta permanentemente. Esta é uma troca deliberada: reutilizar um tick array existente é gratuito para cada posição subsequente, então um pool muito negociado paga o custo de aluguel apenas uma vez por slot (pool, start_tick_index) independentemente da rotatividade.
O bitmap
Encontrar “o próximo tick inicializado à esquerda/direita do tick atual” tem que ser rápido — um swap pode cruzar muitos ticks. O pool armazena um bitmap de 1-bit-por-tick-array inline emPoolState para o intervalo de ±512 arrays ao redor do tick 0 (TICK_ARRAY_BITMAP_SIZE = 512; o campo é [u64; 16] = 1.024 bits, dividido em 512 negativos / 512 positivos, isto é, índices de array −512 … +511). Fora desse intervalo (posições de intervalo completo, configurações exóticas), TickArrayBitmapExtension fornece o overflow.
Um swap caminha pelo bitmap: lowest_set_bit_above(tick_current_array_index) fornece o próximo array com um tick inicializado no lado para o qual o swap está se movendo. Dentro desse array, um bit-scan similar localiza o próximo tick inicializado.
liquidity_gross e liquidity_net
Todo tick inicializado armazena dois valores de liquidez:
liquidity_gross— a soma deLsobre todas as posições que referenciam este tick como endpoint. Quandoliquidity_grossatinge zero, o tick se torna não inicializado e pode ser removido do bitmap.liquidity_net— a mudança assinada para aliquidityde nível de pool quando o preço cruza este tick se movendo para cima (esquerda-para-direita no espaço de ticks). Se este tick é o limite inferior de uma posição com tamanhoL, ele contribui+L; se é o limite superior dessa posição, ele contribui−L.
- Posição A:
tick_lower = -120,tick_upper = 0, liquidezL_A = 100. - Posição B:
tick_lower = -60,tick_upper = 60, liquidezL_B = 50.
liquidity de nível de pool para diferentes valores de tick_current:
tick_current = -180:liquidity = 0(antes de qualquer posição)tick_current = -90:liquidity = 100(dentro de A apenas)tick_current = -30:liquidity = 150(dentro de A e B)tick_current = 30:liquidity = 50(dentro de B apenas)tick_current = 90:liquidity = 0(após ambas)
liquidity_net (possivelmente negativo) a PoolState.liquidity. Este é o mecanismo exato do Uniswap-v3.
Posições como NFTs
Uma posição CLMM do Raydium é um NFT. Abrir uma posição cria um novo mint com suprimento 1 na carteira do chamador, e a autoridade do mint é o programa CLMM. O programa vincula a propriedade da posição a quem quer que tenha um saldo em um ATA daquele mint no momento do CPI. Consequências:- Posições são normalmente transferíveis. Uma carteira pode vender ou fazer airdrop de uma posição transferindo o NFT. O novo detentor pode então chamar
CollectRewards,IncreaseLiquidity, etc. A exceção é uma posição congelada sob o caminho de emissor restrito abaixo. - Posições são endereçáveis fora do CLMM. Marketplaces e carteiras exibem posições como outros NFTs. O SDK define um
name/symbolrazoável nos metadados do mint. - O PDA de uma posição é derivado do mint do NFT. Você pode encontrar o
PersonalPositionStatesem saber quem o detém atualmente.
Posições de emissor restrito
Todo mint de NFT de posição criado após a atualização de 2026-08 registra seupool_state do CLMM como autoridade de congelamento. Isto não significa que toda nova posição está congelada. Para pools ordinários e toda posição não correspondente, a conta de token do NFT permanece descongelada e transferível. O PDA do pool não pode assinar fora do programa CLMM, e o CLMM não expõe nenhuma instrução de congelamento de propósito geral.
O congelamento requer ambas estas condições:
- A posição é aberta através de
OpenPositionV2ouOpenPositionWithToken22Nft. - Pelo menos um mint de vault do pool carrega uma autoridade de congelamento da lista de emissor restrito codificada do programa.
OpenPosition V1 não aplica este filtro. Veja reference/program-addresses para a lista atual.
Uma posição congelada:
- Não pode transferir seu NFT para outra conta de token.
- Não pode mudar o proprietário da conta de token do NFT.
- Ainda pode aumentar ou diminuir liquidez e coletar taxas ou recompensas quando o proprietário registrado assina.
- Ainda pode fechar.
ClosePositionusa o PDA do pool para descongelar a conta do NFT, depois queima o NFT e fecha as contas de posição na mesma instrução.
Posições Token-2022
O CLMM pode cunhar um NFT de posição sob Token SPL clássico através deOpenPositionV2, ou sob Token-2022 através de OpenPositionWithToken22Nft. Ambos os caminhos V2 inspecionam os mints de vault do pool e aplicam a mesma regra de congelamento de emissor restrito. OpenPosition V1 é o caminho clássico de token legado e não pode servir um pool com mints de vault Token-2022. A compatibilidade de carteira e marketplace difere; a interface do Raydium rastreia ambos os programas de NFT.
Regras de intervalo permitido
No momento deOpenPosition o programa garante:
tick_lower < tick_upper.tick_lower % tick_spacing == 0etick_upper % tick_spacing == 0.MIN_TICK <= tick_loweretick_upper <= MAX_TICK.- O chamador forneceu os PDAs de tick-array contendo
tick_loweretick_upper. Eles não precisam estar inicializados — o programa cria por conta própria um que esteja faltando. - A conta de extensão de bitmap, se esta posição se estende para o intervalo de extensão.
TickInvalidOrder (regra 1), TickAndSpacingNotMatch (regra 2), InvalidTickIndex (regra 3), ou MissingTickArrayBitmapExtensionAccount (regra 5); NotApproved cobre o caso separado em que pool_state.status tem o bit de abrir-posição definido. Veja reference/error-codes.
”In-range” vs “out-of-range”
Uma posição está in-range quandotick_lower <= tick_current < tick_upper. Apenas posições in-range contribuem para PoolState.liquidity e portanto apenas elas ganham taxas de swap.
Uma posição out-of-range:
- Detém 100% de um token. Se
tick_current < tick_lower— preço abaixo do intervalo — a posição é inteiramente token0; setick_current >= tick_upper— preço acima do intervalo — ela é inteiramente token1. O preço é cotado comotoken1/token0, portanto uma posição atravessada por um preço em alta acaba detendo o ativo de cotação. - Não ganha taxas de swap.
- Continua a acumular recompensas se os fluxos de recompensa do pool emitem para liquidez out-of-range — mas o comportamento padrão do Raydium é “emitir apenas para in-range”, correspondendo à convenção do Uniswap v3. Veja
products/clmm/fees.
Armadilhas comuns de integração
- Endpoints fora do espaçamento. Código que calcula um tick a partir de um preço alvo deve se ajustar a um múltiplo de
tick_spacingantes de passá-lo paraOpenPosition, ou a instrução reverte comTickAndSpacingNotMatch. O auxiliar do SDK éTickUtil.getPriceAndTick({ price, mintADecimals, mintBDecimals, zeroForOne, tickSpacing })(note:TickUtil, no singular); matemática caseira frequentemente pula o ajuste. - Tick arrays faltando. Abrir uma posição ampla toca dois tick arrays; esquecer de passá-los como contas graváveis reverte. Eles não precisam existir previamente — o programa cria um que esteja faltando — mas a conta deve estar na lista.
- Tick obsoleto após um swap.
tick_currentpode cruzar muitos ticks em um swap. Se sua UX mostra um “tick atual” de uma chamada RPC e depois abre uma posição em uma posterior, a posição relativa vs o preço ao vivo pode estar desviada por dezenas de ticks. Re-busque logo antes de assinar. - NFTs de posição com metadados extras. Se você construir uma carteira que reconheça posições do Raydium, use o PDA de posição / dados do programa e não um campo de metadados codificado. Novos mints de posição usam o PDA do pool como autoridade de mint e congelamento na criação; a autoridade de mint é removida após o único NFT ser cunhado.
- Assumindo que toda posição é transferível. Leia o estado
isFrozenda conta de token do NFT antes de mostrar transferência, marketplace, escrow, ou ações de Burn & Earn.
Próximos passos
- Math — o passo de swap e derivação de crescimento de taxa que limites de ticks participam.
- Accounts — os layouts
TickArrayStateePositionState. - Fees and rewards — como in-range-ness controla acúmulo de taxa.
algorithms/clmm-math— a derivação compartilhada das fórmulas de liquidez concentrada.
raydium-io/raydium-clmm— módulostick_array,tick,position- “Uniswap v3 Core” whitepaper, §6 (ticks), §7 (fee growth)

