Skip to main content
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 →

El invariante

CPMM mantiene el invariante clásico de producto constante en sus dos bóvedas: x⋅y=kx \cdot y = k donde x es el saldo de vault0 después de cualquier comisión de transferencia de Token-2022 en la recepción, e igualmente para y. Cada swap debe dejar k' ≥ k después de contabilizar las comisiones comerciales acreditadas a los LP (los buckets de protocolo, fondo y creador no se cuentan hacia k — se encuentran en la bóveda pero se excluyen de la vista de la curva, ver Comisiones en la curva abajo). k por lo tanto crece monótonamente con el tiempo a medida que los LP acumulan comisiones. Las acciones de LP se cotizan por las reservas del pool, no por k: Precio de LP en token0=xlpSupply,Precio de LP en token1=ylpSupply\text{Precio de LP en token0} = \frac{x}{\text{lpSupply}}, \qquad \text{Precio de LP en token1} = \frac{y}{\text{lpSupply}} Quemar ΔLP tokens de LP devuelve exactamente ΔLP × x / lpSupply de token0 y ΔLP × y / lpSupply de token1. Ni la curva ni k se mueven en depósitos o retiros — solo los swaps cambian el precio.

Modelo de comisiones en la ruta de swap

CPMM aplica dos comisiones con tasas independientes en cada swap:
  • La comisión comercial se toma en el lado de entrada, cobrada a AmmConfig.trade_fee_rate. Luego se divide en acciones de LP, protocolo y fondo (la parte de LP permanece en la bóveda y crece k; las partes de protocolo y fondo se extraen de la contabilidad de la bóveda).
  • La comisión del creador (activa solo cuando enable_creator_fee == true) se cobra a AmmConfig.creator_fee_rate. Se toma en el lado de entrada o de salida dependiendo de PoolState.creator_fee_on y la dirección del swap (ver products/cpmm/fees). Es su propio bucket — nunca una porción de la comisión comercial.
La parte del protocolo de la comisión del creador no aparece en ningún lugar de esta página, y eso es deliberado. Se aplica cuando CollectCreatorFee mueve comisiones acumuladas entre dos contadores que la curva ya excluye — no durante un swap. Las matemáticas de swap, cotizaciones y k son idénticas con y sin ella. Ver products/cpmm/fees.
Sea:
  • FEE_RATE_DENOMINATOR = 1_000_000
  • trade_fee_rate — de AmmConfig, p. ej., 2500 = 0.25% del lado de volumen relevante
  • creator_fee_rate — de AmmConfig, p. ej., 1000 = 0.10% del lado de volumen relevante
  • protocol_fee_rate, fund_fee_rate — denominados en unidades de 1/FEE_RATE_DENOMINATOR de la comisión comercial, no del volumen
Cuando la comisión del creador está en el lado de entrada:
Cuando la comisión del creador está en el lado de salida:
En ambos casos la comisión comercial se divide de la misma manera:
La cantidad protocol_fee + fund_fee + creator_fee se mantiene en las bóvedas pero se rastrea por separado en el estado del pool (protocol_fees_token*, fund_fees_token*, creator_fees_token*). Cuando la verificación del invariante de producto constante comprueba k' ≥ k, utiliza saldos de bóveda menos las tres comisiones acumuladas pero no barridas — por lo que los LP capturan solo lp_fee. Ver products/cpmm/fees para las instrucciones de recopilación y los ejemplos numéricos trabajados.

SwapBaseInput (entrada exacta)

“El usuario nos da exactamente amount_in del mint de entrada y recibe al menos minimum_amount_out del mint de salida.” Ignorando Token-2022 por un momento:
Por álgebra: amount_out=y⋅Δxnetx+Δxnet\text{amount\_out} = \frac{y \cdot \Delta x_{\text{net}}}{x + \Delta x_{\text{net}}} donde Δx_net = amount_in_after_trade_fee. El programa luego actualiza la contabilidad de la bóveda de modo que la porción de trade_fee adeudada a protocolo/fondo/creador se encuentre en buckets “acumulados” (no incluidos en el siguiente x de la curva), mientras que la parte de LP se une a x para el siguiente swap.

Token-2022 en el lado de entrada

Si el mint de entrada tiene una extensión de comisión de transferencia, el mint deduce su comisión en la transferencia de usuario → bóveda. Entonces la bóveda realmente recibe amount_in − transfer_fee_in(amount_in). El programa CPMM por lo tanto calcula:
y ejecuta la curva contra amount_in_after_trade_fee. Esto importa porque el precio de la curva se calcula a partir de la cantidad neta que llegó a la bóveda, no a partir de la cantidad titular del usuario.

Token-2022 en el lado de salida

Si el mint de salida tiene una comisión de transferencia, el pool envía amount_out desde su bóveda al usuario. El mint entonces deducirá su comisión en el camino, por lo que el usuario recibe amount_out − transfer_fee_out(amount_out). El programa calcula amount_out de la curva como de costumbre, pero es responsabilidad del integrador convertir el número de “envío de bóveda” del pool en un número de “recepción del usuario” al mostrar cotizaciones.

Verificación de deslizamiento

Después de calcular amount_out:
Si el mint de salida cobra una comisión de transferencia, el SDK aplica la comisión de transferencia antes de establecer minimum_amount_out para que la constante de deslizamiento se denomine en lo que el usuario realmente recibirá, no en lo que la bóveda envía.

SwapBaseOutput (salida exacta)

“El usuario recibirá exactamente amount_out del mint de salida y está dispuesto a pagar hasta maximum_amount_in del mint de entrada.” Invirtiendo la 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 El techo es importante — garantiza k' ≥ k después del truncamiento de enteros. Luego:
En entrada de Token-2022, envuelve con:
para que el usuario pague lo suficiente para que después de la deducción de comisión de transferencia del mint, el pool aún reciba gross_needed.

Verificación de deslizamiento

Ejemplo trabajado

Estado del pool, ignorando Token-2022:
  • x = 1_000_000_000_000 (1,000,000.000000 de token0, 6 decimales)
  • y = 2_000_000_000_000 (2,000,000.000000 de token1, 6 decimales)
  • AmmConfig: trade_fee_rate = 2500, protocol_fee_rate = 120_000, fund_fee_rate = 40_000, creator_fee_rate = 0
Usuario: SwapBaseInput con amount_in = 1_000_000_000 (1,000.000000 de token0). La comisión del creador está deshabilitada (enable_creator_fee = false).
Si el mismo pool tuviera enable_creator_fee = true con creator_fee_rate = 1000 (0.10%) en el lado de entrada, el programa cobraría total_input_fee = ceil(1_000_000_000 * 3500 / 1_000_000) = 3_500_000, luego lo dividiría como creator_fee = 1_000_000 y trade_fee = 2_500_000. La aritmética de protocolo/fondo/LP en trade_fee es idéntica al ejemplo anterior — la comisión del creador es su propio bucket, acumulada a creator_fees_token0 y excluida de curve_x junto con los buckets de protocolo y fondo. Si el mint de entrada tiene una comisión de transferencia de Token-2022 del 1%, la bóveda recibe 990_000_000 tokens en lugar de 1_000_000_000, y cada cálculo posterior utiliza esa cantidad neta.

Regla de actualización de observación

En cada swap, el programa evalúa si debe insertar una nueva observación en el búfer circular:
Dos propiedades:
  • Precio acumulativo, no precio spot. Una sola observación no es un precio. Para obtener un TWAP desde el tiempo t0 a t1, lee las observaciones más cercanas a cada extremo y calcula (cumulative(t1) − cumulative(t0)) / (t1 − t0).
  • Las muestras tienen límite de velocidad. Los swaps consecutivos en el mismo slot pueden compartir una observación. Leer una observación inmediatamente después de un swap puede parecer obsoleta por un slot — esto es normal.
Más en products/clmm/accounts.

Comisiones en la curva

Esta es la parte sutil y vale la pena destacarla. La aritmética de la curva funciona contra los saldos de bóveda netos — es decir, saldo SPL bruto menos comisiones acumuladas de protocolo, fondo y creador (los tres son buckets independientes — ver products/cpmm/fees). Una imagen concreta:
Consecuencias para integradores:
  • No cites desde saldos brutos. Resta los campos de comisión acumulada primero, o llama a SwapBaseInput como una simulación y toma su retorno.
  • CollectProtocolFee mueve tokens fuera de la bóveda. Después de la recopilación, raw_vault_balance cae pero curve_balance no cambia; el precio del pool no se mueve. Esto es deliberado.

Precisión y desbordamiento

  • Toda la aritmética de la curva utiliza intermedios u128 para prevenir desbordamiento en x * y.
  • La división redondea hacia cero excepto para Δx_net de SwapBaseOutput, que redondea hacia arriba, y el cálculo de comisiones, que redondea hacia arriba en trade_fee y hacia abajo en las subdivisiones. Estas direcciones de redondeo se eligen para que el invariante nunca disminuya debido al truncamiento de enteros.
  • Los pools con proporciones de bóveda extremas (miles de millones : 1) pueden alcanzar pisos de precisión en operaciones pequeñas; el programa devuelve ZeroTradingTokens en ese caso. Ver reference/error-codes.

Dónde ir a continuación

Fuentes: