Esta página foi traduzida automaticamente por IA. A versão em inglês é a fonte oficial.Ver versão em inglês →
Esta página é operacional: fornece as fórmulas, convenções de ponto fixo e procedimentos passo a passo usados pelo programa CLMM. Para o raciocínio por trás da própria curva de liquidez concentrada — por que
L = sqrt(x · y) importa — veja algorithms/clmm-math. Esta página assume que você já leu aquela.Representação de sqrt-price
O CLMM armazena o preço comosqrt_price_x64 — a raiz quadrada do preço token1-por-token0, como um número de ponto fixo Q64.64:
onde p = token1_amount / token0_amount. Trabalhar em sqrt em vez de p lineariza a matemática do swap (os deltas de quantidade de token se tornam lineares em Δsqrt_price), e o x64 de ponto fixo mantém a precisão através de swaps multi-tick.
A conversão tick ↔ sqrt-price é pré-computada via uma aproximação logarítmica bit-por-bit:
implementada como uma exponenciação baseada em lookup em tick_math::get_sqrt_price_at_tick.
Liquidity como unidade canônica
Dentro de um intervalo[sqrt_a, sqrt_b] (com sqrt_a < sqrt_b) uma posição de liquidity L mapeia para quantidades de tokens da seguinte forma. Seja sqrt_c = sqrt_price_x64 o preço atual do pool.
Todas as três identidades vêm do invariante
x = L / sqrt_p, y = L · sqrt_p que a liquidez concentrada satisfaz dentro de um intervalo.
Integradores normalmente querem o inverso: dada uma deposição de amount0 / amount1, calcular o máximo L que cabe no intervalo. O método LiquidityMath.getLiquidityFromTokenAmounts do SDK faz isso. A fórmula para o caso dentro do intervalo:
Qual lado se vincula determina a razão realmente consumida; o outro lado pode ter sobra.
Passo de swap de um único tick
Um swap procede em passos. Cada passo ou (a) consome toda a entrada disponível dentro do intervalo de tick atual sem cruzar um tick, ou (b) move o preço exatamente para o próximo tick inicializado. Dado o estado atual(sqrt_c, L) e um swap para baixo (token0 entra, token1 sai, sqrt_price diminui — o preço é cotado como token1/token0, então adicionar token0 o reduz), o próximo tick inicializado abaixo fica em sqrt_t < sqrt_c. Dentro deste micro-intervalo a relação entre entrada e preço é:
e
Um swap com token1 como entrada é a imagem espelhada: sqrt_price sobe em direção ao próximo tick acima, e as duas fórmulas trocam qual endpoint é subtraído. O programa codifica a direção como zero_for_one (true quando o mint de entrada é token_mint_0), e um swap zero_for_one se limita a MIN_SQRT_PRICE_X64.
O programa faz uma de duas coisas:
-
A entrada inteira cabe? Se a entrada restante (após taxa) for menor que
Δamount0para alcançarsqrt_t, resolva para o novosqrt_c'exatamente: (para um swap exato-entradatoken0 → token1). O swap se completa neste passo sem cruzar um tick. -
A entrada excede
Δamount0? Definasqrt_c' = sqrt_t, cruze o tick (apliqueliquidity_net), decremente a entrada restante porΔamount0, incremente a saída porΔamount1, e repita.
token1 → token0, preço descendo), as fórmulas têm sqrt_c e sqrt_t trocados e a inversão no outro slot.
A implementação completa em Rust fica em raydium-clmm/programs/amm/src/libraries/swap_math.rs. A lógica lá corresponde exatamente ao SwapMath.computeSwapStep do Uniswap v3.
Taxas em cada passo
As taxas de negociação são retiradas da quantidade de entrada em cada passo, mesma convenção do CPMM:L_i que permaneceu dentro do intervalo durante este swap posteriormente lerá L_i · Δfee_growth_global / 2^{64} tokens devidos.
As porções de protocolo e fundo acumulam em PoolState.protocol_fees_token_{0,1} e PoolState.fund_fees_token_{0,1} respectivamente, idêntico ao CPMM. Elas são coletadas por CollectProtocolFee / CollectFundFee.
Crescimento de taxa fora e dentro
A parte complicada da contabilidade de taxa do CLMM: uma posição ganha taxas apenas enquanto o preço do pool está dentro de seu intervalo. O pool rastreia taxas cumulativas globalmente; a posição precisa saber as taxas cumulativas enquanto dentro de seu intervalo específico. A solução é um acumulador baseado em tick. Cada tick armazena:- Se o preço do pool está acima deste tick (
tick_current >= this_tick),fee_growth_outside = fee_growth_global. (Tudo ganho até agora é “fora” — ou seja, abaixo — deste tick, relativo ao preço atual.) - Caso contrário
fee_growth_outside = 0.
fee_growth_outside daquele tick:
O invariante que isso preserva: para qualquer tick t, fee_growth_outside(t) é igual às taxas que acumularam enquanto tick_current estava no lado oposto de t.
Crescimento de taxa dentro de um intervalo [tick_lower, tick_upper] é então derivado:
O que uma posição armazena e o que lê
UmPersonalPositionState armazena fee_growth_inside_0_last_x64 e fee_growth_inside_1_last_x64: os valores de fee_growth_inside na última vez que a posição foi tocada.
Em qualquer toque subsequente (aumentar, diminuir, coletar), o programa:
- Calcula o
fee_growth_inside_{0,1}_x64atual usando a fórmula acima. - Calcula
Δ = fee_growth_inside_now − fee_growth_inside_last(subtração modular em u128). - Adiciona
Δ × position.liquidity / 2^{64}atokens_fees_owed_{0,1}. - Atualiza
fee_growth_inside_lastpara o novo valor.
CollectFees / DecreaseLiquidity, contra tokens_fees_owed.
Recompensas
Cada um dos até 3 fluxos de recompensa do pool usa a mesma maquinaria de crescimento-dentro, em seu próprio acumuladorreward_growth_global_x64. No momento da emissão:
— as emissões escalam inversamente com a liquidez ativa, então um pool mais denso paga a cada posição proporcionalmente menos por segundo, mas sobre mais posições no total. A recompensa por posição devida é
e é paga por DecreaseLiquidity / DecreaseLiquidityV2 — não há instrução de coleta de recompensa autônoma. Veja products/clmm/fees.
Exemplo trabalhado: swap exato-entrada
Suponha:tick_spacing = 60sqrt_price_x64 = 1 × 2^{64}— preço = 1.0, entãotick_current = 0.- Liquidez ativa
L = 1_000_000 × 2^{64}. - Próximo tick inicializado abaixo:
t = −60(sqrt_price_b ≈0.997005 × 2^{64}). Um swap com token0 como entrada se move para baixo, então o tick acima é irrelevante aqui. - Taxa de taxa de negociação: 500 (0.05%).
SwapBaseInput exato-entrada 1.000 token0.
Passo 1 — taxas:
999 < 3004.4, então a entrada inteira cabe sem cruzar o tick.
Passo 3 — novo preço:
sqrt_c' fica ligeiramente abaixo de sqrt_c, que é a direção correta: um swap token0 → token1 adiciona token0 ao pool e assim reduz o preço token1/token0.
Passo 4 — quantidade de saída:
trade_fee_rate × protocol_fee_rate / 1e6 (e similar para fundo); a porção LP flui para fee_growth_global_0_x64.
Correspondência de ordem limitada durante swap
Quando um passo de swap cruza um tick que contém ordens limitadas abertas, essas ordens consomem entrada de swap antes da curva LP, ao preço exato do tick. A correspondência é FIFO dentro do tick por cohortorder_phase.
Estado por-cohort em TickState
orders_amount e herdam o próximo order_phase; elas não podem preencher até que o cohort anterior seja totalmente consumido.
Passo de correspondência
Pseudo-código para a correspondência que acontece em cada cruzamento de tick durante um swap:SettleLimitOrder (ou DecreaseLimitOrder). O pool simplesmente rastreia quanto do cohort agora está preenchido via unfilled_ratio_x64. Cada LimitOrderState armazena seu próprio snapshot (order_phase, unfilled_ratio_x64) no tempo de abertura, então a liquidação se reduz a:
Interação com a curva LP
Em um passo de swap, a correspondência de ordem limitada acontece no tick (zeroΔsqrt_price); o consumo da curva LP acontece entre ticks. A ordem é portanto:
- Cruze o tick
t_cross(aplique a mudança LPliquidity_netprimeiro, já que é assim que o Uniswap-V3 faz). - Preencha quaisquer ordens limitadas sentadas em
t_cross. - Continue ao longo da curva LP para o próximo tick inicializado ou até a exaustão de
swap_input.
Derivação de taxa dinâmica
PoolState.dynamic_fee_info carrega o estado de volatilidade. Cada passo de swap calcula a taxa de taxa por-passo como:
onde:
- —
DYNAMIC_FEE_CONTROL_DENOMINATOR - —
VOLATILITY_ACCUMULATOR_SCALE vol_accé o acumulador por-swap após a regra de atualização abaixotick_spacingé dePoolState.tick_spacing
Atualização do acumulador
Duas regras são aplicadas a cada swap, em ordem: Decaimento. O piso de referência decai com base no tempo desde a última atualização: Acumular. O novo acumulador é a referência mais a distância de tick percorrida desde o índice de referência anterior:tick_spacing_index_reference () está em unidades de tick-spacing, não ticks brutos: .
Por que parabólico em distância de tick
Elevar ao quadrado o acumulador significa que a taxa sobe como o quadrado de quão longe o preço caminhou de seu ponto de referência. Empiricamente isso corresponde ao escalonamento de variância do preço sob pressão de passeio aleatório: uma excursão de tick 2× implica 4× a volatilidade implícita, então cobra 4× a sobretaxa. O parâmetrodynamic_fee_control calibra o nível absoluto.
A janela filter_period previne pequenas oscilações sub-segundo (por exemplo, bots MEV fazendo sandwich) de inflacionar o acumulador. A janela decay_period previne um único pico passado de cobrar taxas indefinidamente após o mercado ter se acalmado.
Robustez numérica
- Todos os produtos intermediários passam por aritmética em forma de
u128ouu256. O CLMM usa helpersU128Sqrte padrõesFullMath::mulDivdiretamente portados do Uniswap v3. - O arredondamento de divisão é escolhido por-passo para impor o invariante
k' ≥ klocalmente.SwapBaseInputarredonda a saída para baixo;SwapBaseOutputarredonda a entrada para cima. - Cruzamentos de tick que reduzem
PoolState.liquiditya zero são permitidos (o preço pode atravessar um “buraco de liquidez”) mas o swap simplesmente avança para o próximo tick inicializado sem consumir entrada, não cobrando taxa. - Guarda de overflow:
sqrt_price_x64é mantido no intervalo inclusivo[MIN_SQRT_PRICE_X64, MAX_SQRT_PRICE_X64]correspondendo a[MIN_TICK, MAX_TICK]. Um swap que empurraria além de qualquer limite reverte comSqrtPriceLimitOverflow.
Próximos passos
products/clmm/ticks-and-positionspara como o mapa de tick participa da caminhada.products/clmm/feespara o lado de taxa/recompensa da matemática em detalhe.algorithms/clmm-mathpara as derivações por trás deL = sqrt(x · y)e as fórmulas de intervalo-vs-liquidez.
raydium-io/raydium-clmm—libraries/swap_math.rs,libraries/tick_math.rs- Whitepaper “Uniswap v3 Core”, §6–7

