Skip to main content
Esta página foi traduzida automaticamente por IA. A versão em inglês é a fonte oficial.Ver versão em inglês →

O invariante

O CPMM mantém o invariante clássico de produto constante em seus dois vaults: x⋅y=kx \cdot y = k onde x é o saldo do vault0 após qualquer taxa de transferência Token-2022 no recebimento, e similarmente para y. Cada swap deve deixar k' ≥ k após contabilizar as taxas de negociação creditadas ao LP (os buckets de protocolo, fundo e criador não são contados em k — ficam no vault mas são excluídos da visualização da curva, veja Taxas na curva abaixo). k portanto cresce monotonicamente ao longo do tempo conforme os LPs acumulam taxas. As cotas de LP são precificadas pelas reservas do pool, não por k: Prec¸o de LP em token0=xlpSupply,Prec¸o de LP em token1=ylpSupply\text{Preço de LP em token0} = \frac{x}{\text{lpSupply}}, \qquad \text{Preço de LP em token1} = \frac{y}{\text{lpSupply}} Queimar ΔLP tokens de LP retorna exatamente ΔLP × x / lpSupply de token0 e ΔLP × y / lpSupply de token1. Nem a curva nem k se movem em depósito ou saque — apenas swaps alteram o preço.

Modelo de taxa no caminho de swap

O CPMM aplica duas taxas independentemente classificadas em cada swap:
  • A taxa de negociação é cobrada no lado de entrada, com taxa de AmmConfig.trade_fee_rate. Ela é então dividida em cotas de LP, protocolo e fundo (a cota de LP permanece no vault e cresce k; as cotas de protocolo e fundo são extraídas da contabilidade do vault).
  • A taxa de criador (ativa apenas quando enable_creator_fee == true) é cobrada em AmmConfig.creator_fee_rate. É cobrada no lado de entrada ou no lado de saída dependendo de PoolState.creator_fee_on e da direção do swap (veja products/cpmm/fees). É seu próprio bucket — nunca uma fatia da taxa de negociação.
A cota do protocolo da taxa de criador não aparece em nenhum lugar nesta página, e isso é deliberado. É aplicada quando CollectCreatorFee move taxas acumuladas entre dois contadores que a curva já exclui — não durante um swap. A matemática de swap, cotações e k são idênticas com e sem ela. Veja products/cpmm/fees.
Seja:
  • FEE_RATE_DENOMINATOR = 1_000_000
  • trade_fee_rate — de AmmConfig, ex., 2500 = 0,25% do lado de volume relevante
  • creator_fee_rate — de AmmConfig, ex., 1000 = 0,10% do lado de volume relevante
  • protocol_fee_rate, fund_fee_rate — denominados em unidades de 1/FEE_RATE_DENOMINATOR da taxa de negociação, não do volume
Quando a taxa de criador está no lado de entrada:
Quando a taxa de criador está no lado de saída:
Em ambos os casos a taxa de negociação é dividida da mesma forma:
O montante protocol_fee + fund_fee + creator_fee é mantido nos vaults mas rastreado separadamente no estado do pool (protocol_fees_token*, fund_fees_token*, creator_fees_token*). Quando a verificação do invariante de produto constante verifica k' ≥ k, ela usa saldos do vault menos todas as três taxas acumuladas mas não coletadas — então os LPs capturam apenas lp_fee. Veja products/cpmm/fees para as instruções de coleta e exemplos numéricos trabalhados.

SwapBaseInput (entrada exata)

“O usuário nos dá exatamente amount_in do mint de entrada e recebe pelo menos minimum_amount_out do mint de saída.” Ignorando Token-2022 por um momento:
Por álgebra: amount_out=y⋅Δxnetx+Δxnet\text{amount\_out} = \frac{y \cdot \Delta x_{\text{net}}}{x + \Delta x_{\text{net}}} onde Δx_net = amount_in_after_trade_fee. O programa então atualiza a contabilidade do vault de forma que a porção de trade_fee devida ao protocolo/fundo/criador fica em buckets “acumulados” (não incluídos no próximo x da curva), enquanto a cota de LP se junta a x para o próximo swap.

Token-2022 no lado de entrada

Se o mint de entrada tem uma extensão de taxa de transferência, o mint deduz sua taxa na transferência de usuário → vault. Então o vault realmente recebe amount_in − transfer_fee_in(amount_in). O programa CPMM portanto computa:
e executa a curva contra amount_in_after_trade_fee. Isso importa porque o preço da curva é computado do montante líquido que chegou ao vault, não do montante de manchete do usuário.

Token-2022 no lado de saída

Se o mint de saída tem uma taxa de transferência, o pool envia amount_out de seu vault para o usuário. O mint então vai descontar sua taxa no caminho, então o usuário recebe amount_out − transfer_fee_out(amount_out). O programa computa amount_out da curva como usual, mas é responsabilidade do integrador converter o número de “envio do vault” do pool em um número de “recebimento do usuário” ao mostrar cotações.

Verificação de slippage

Após computar amount_out:
Se o mint de saída cobra uma taxa de transferência, o SDK aplica a taxa de transferência antes de definir minimum_amount_out para que a constante de slippage seja denominada no que o usuário realmente receberá, não no que o vault envia.

SwapBaseOutput (saída exata)

“O usuário receberá exatamente amount_out do mint de saída e está disposto a pagar até maximum_amount_in do mint de entrada.” Invertendo a curva para Δx_net: Δxnet=⌈x⋅amount_outy−amount_out⌉\Delta x_{\text{net}} = \left\lceil \frac{x \cdot \text{amount\_out}}{y - \text{amount\_out}} \right\rceil O teto é importante — garante k' ≥ k após truncamento inteiro. Então:
Em Token-2022 de entrada, envolva com:
para que o usuário pague o suficiente para que após a dedução de taxa de transferência do mint o pool ainda receba gross_needed.

Verificação de slippage

Exemplo trabalhado

Estado do pool, ignorando Token-2022:
  • x = 1_000_000_000_000 (1.000.000,000000 de token0, 6 decimais)
  • y = 2_000_000_000_000 (2.000.000,000000 de token1, 6 decimais)
  • AmmConfig: trade_fee_rate = 2500, protocol_fee_rate = 120_000, fund_fee_rate = 40_000, creator_fee_rate = 0
Usuário: SwapBaseInput com amount_in = 1_000_000_000 (1.000,000000 de token0). Taxa de criador desabilitada (enable_creator_fee = false).
Se o mesmo pool tivesse enable_creator_fee = true com creator_fee_rate = 1000 (0,10%) no lado de entrada, o programa cobraria total_input_fee = ceil(1_000_000_000 * 3500 / 1_000_000) = 3_500_000, então dividiria como creator_fee = 1_000_000 e trade_fee = 2_500_000. A aritmética de protocolo/fundo/LP em trade_fee é inalterada do exemplo acima — a taxa de criador é seu próprio bucket, acumulada em creator_fees_token0 e excluída de curve_x junto com os buckets de protocolo e fundo. Se o mint de entrada tem uma taxa de transferência Token-2022 de 1%, o vault recebe 990_000_000 tokens em vez de 1_000_000_000, e cada cálculo subsequente usa esse montante líquido.

Regra de atualização de observação

Em cada swap, o programa avalia se deve enviar uma nova observação para o buffer de anel:
Duas propriedades:
  • Preço cumulativo, não preço spot. Uma única observação não é um preço. Para obter um TWAP do tempo t0 para t1, leia as observações mais próximas de cada extremidade e compute (cumulative(t1) − cumulative(t0)) / (t1 − t0).
  • Amostras são limitadas por taxa. Swaps consecutivos no mesmo slot podem compartilhar uma observação. Ler uma observação imediatamente após um swap pode portanto parecer obsoleta por um slot — isso é normal.
Mais em products/clmm/accounts.

Taxas na curva

Esta é a parte sutil e vale a pena chamar atenção. A aritmética da curva funciona contra os saldos líquidos do vault — ou seja, saldo SPL bruto menos taxas acumuladas de protocolo, fundo e criador (todos os três são buckets independentes — veja products/cpmm/fees). Uma imagem concreta:
Consequências para integradores:
  • Não cite de saldos brutos. Subtraia os campos de taxa acumulada primeiro, ou chame SwapBaseInput como uma simulação e pegue seu retorno.
  • CollectProtocolFee move tokens para fora do vault. Após coleta, raw_vault_balance cai mas curve_balance permanece inalterado; o preço do pool não se move. Isso é deliberado.

Precisão e overflow

  • Toda aritmética de curva usa intermediários u128 para prevenir overflow em x * y.
  • Divisão arredonda para zero exceto para Δx_net de SwapBaseOutput, que arredonda para cima, e computação de taxa, que arredonda para cima em trade_fee e para baixo nas sub-divisões. Essas direções de arredondamento são escolhidas para que o invariante nunca diminua devido a truncamento inteiro.
  • Pools com proporções de vault extremas (bilhões : 1) podem atingir pisos de precisão em pequenos trades; o programa retorna ZeroTradingTokens nesse caso. Veja reference/error-codes.

Próximos passos

Fontes: