> ## Documentation Index
> Fetch the complete documentation index at: https://docs.raydium.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Matemática de AMM v4

> Invariante de producto constante con la convención de comisiones de AMM v4, conversión de precios de reservas a libro de órdenes, construcción de la cuadrícula de órdenes objetivo, y el paso de liquidación de PnL.

<Info>
  **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 →](/products/amm-v4/math)
</Info>

## El invariante

El pool mantiene `coin_reserve × pc_reserve = k`, donde:

```
coin_reserve = coin_vault_balance
             + orders_posted_on_openbook.base
             + pending_coin_fill_not_yet_settled
pc_reserve   = pc_vault_balance
             + orders_posted_on_openbook.quote
             + pending_pc_fill_not_yet_settled
             - accrued_pnl_pc
```

Hay dos cosas importantes que notar:

1. Las reservas incluyen **cantidades comprometidas en OpenBook**. Las órdenes limitadas del AMM siguen siendo parte de su liquidez — no se "pierden" en el libro de órdenes, solo se custodian allí. Calcular `k` únicamente con los saldos de bóveda en cadena subestima las reservas.
2. El acúmulo de PnL (`need_take_pnl_*`) se resta para que la curva se conserve cuando el administrador retira las comisiones. El mismo principio que la exclusión de `protocol_fees_*` de CPMM.

Cada operación `Swap*` garantiza que `k' ≥ k` después de volver a añadir la cuota de comisión del proveedor de liquidez a las reservas.

## Convención de comisiones

AMM v4 utiliza **comisiones de razón** (pares numerador/denominador) en lugar de la convención `1/1_000_000` de CPMM / CLMM. La estructura `Fees` en cadena (ver [`Fees::initialize`](https://github.com/raydium-io/raydium-amm/blob/master/program/src/state.rs) en el código fuente del programa) tiene estos valores predeterminados:

```
Fees {
  min_separate_numerator:    5,
  min_separate_denominator:  10_000,   //  5/10_000 = 0.05%

  trade_fee_numerator:      25,
  trade_fee_denominator:    10_000,    // 25/10_000 = 0.25% — usado para precios de órdenes limitadas en OpenBook

  pnl_numerator:            12,
  pnl_denominator:          100,       // 12/100   = 12%   — cuota del protocolo DEL swap fee

  swap_fee_numerator:       25,
  swap_fee_denominator:     10_000,    // 25/10_000 = 0.25% — comisión bruta en swaps por ruta AMM
}
```

Interpretación (valores predeterminados publicados en mainnet):

* **Comisión total del swap:** `swap_fee = amount_in × 25 / 10_000 = 0.25%` de la entrada bruta.
* **Cuota del protocolo:** `pnl_numerator / pnl_denominator = 12 / 100 = 12%` **de la comisión de swap**, lo que resulta en `0.25% × 12% = 0.03%` del volumen. Esta cuota se acumula en los contadores de PnL y se retira mediante `WithdrawPnl`.
* **Cuota del LP:** el `88%` restante de la comisión de swap, lo que resulta en `0.25% × 88% = 0.22%` del volumen. Se queda en el pool e infla `k`.
* **Sin cuota de fondo.** AMM v4 no tiene la división de comisiones de fondo de CPMM/CLMM.

Nota que `pnl_numerator / pnl_denominator` es una fracción **de la comisión**, no del volumen de trading — una confusión común con estos nombres de campos.

`trade_fee_numerator / trade_fee_denominator` (también `25 / 10_000`) es un campo separado utilizado por la integración con OpenBook al calcular precios inclusive de comisiones para la cuadrícula de órdenes limitadas del AMM; es igual a `swap_fee` por defecto pero se lee desde una ruta de código diferente.

Las desviaciones de estos valores predeterminados son raras pero existen en algunos pools heredados; siempre lee las comisiones desde `AmmInfo.fees` antes de hacer una cotización.

## Matemática directa del swap (ruta AMM)

El caso más simple: el usuario realiza un swap contra las bóvedas del pool sin interactuar con OpenBook. Las reservas internas del pool (incluidas las asignaciones en el libro) son el denominador.

**SwapBaseIn (entrada exacta):**

```
amount_after_fee = amount_in − ceil(amount_in × swap_fee_numerator / swap_fee_denominator)
amount_out = amount_after_fee × out_reserve
           / (in_reserve + amount_after_fee)
require(amount_out >= minimum_amount_out)
```

Las reservas utilizadas aquí son las **reservas efectivas**. Históricamente esto era `coin_vault_balance + coin_posted_on_openbook + ...` (la bóveda del AMM más los tokens que tenía bloqueados en órdenes de OpenBook). **Desde la desactivación de OpenBook, el saldo en el libro es cero**, así que las reservas efectivas son iguales a los saldos brutos de la bóveda. La ruta `MonitorStep` / liquidación implícita que solía refrescar el lado de OpenBook ya no es necesaria en la práctica.

**SwapBaseOut (salida exacta):**

```
amount_in_after_fee = ceil(in_reserve × amount_out / (out_reserve − amount_out))
amount_in_gross     = ceil(amount_in_after_fee × swap_fee_denominator
                            / (swap_fee_denominator − swap_fee_numerator))
require(amount_in_gross <= maximum_amount_in)
```

## Interacción con el libro de órdenes (histórico)

<Note>
  **Ya no está activo.** La construcción de la cuadrícula descrita en esta sección refleja cómo AMM v4 *originalmente* reflejaba la curva en un mercado de OpenBook. La integración con OpenBook ha sido desactivada; los pools ya no publican ni mantienen órdenes en OpenBook. La matemática a continuación se preserva para contexto — explica para qué se dimensionaban las cuentas `target_orders` / `amm_open_orders` en cadena y por qué el programa aún valida los parámetros relacionados con `MonitorStep` aunque el keeper ya no los ejecute.
</Note>

Aparte de los swaps de usuarios, AMM v4 históricamente colocaba una **cuadrícula** de órdenes limitadas en el mercado OpenBook. La cuadrícula se calculaba a partir de los parámetros de `AmmInfo`:

* **`depth`** — número de niveles de precio por lado.
* **`amount_wave`** — unidad base de tamaño por nivel.
* **`min_size`**, **`coin_lot_size`**, **`pc_lot_size`** — restricciones del mercado OpenBook.
* **`state_data.swap_acc_coin_fee`**, **`swap_acc_pc_fee`** — contadores de comisiones acumuladas desde el último `TakePnl`.

El programa deriva los precios por nivel caminando desde el precio actual de la curva en pasos de razón constante:

```
price_level(k) = curve_price × (1.0001 ^ k)       # conceptualmente
size_level(k)  = amount_wave × f(depth, k)        # disminuido por depth
```

Los precios y tamaños exactos se determinan mediante `target_orders` calculado en `build_orders` y comparado con `amm_open_orders` en cada `MonitorStep`. Cualquier divergencia resulta en cancelaciones + nuevas publicaciones. Las órdenes recién completadas en OpenBook se liquidan en las bóvedas del pool en la siguiente operación que refresca el lado de OpenBook.

Los integradores raramente necesitan calcular la cuadrícula — el keeper de Raydium la mantiene — pero es útil saber que:

* Un pool con **liquidez significativa en el libro** tiene esa liquidez contribuyendo a `k`, no sentada sin hacer nada.
* Un mercado OpenBook obsoleto (cola de eventos llena, cranks bloqueados) impide actualizaciones de la cuadrícula; el AMM entonces puede cotizar precios que divergen del libro de órdenes visible hasta el siguiente crank.

## Paso de liquidación (PnL)

La cuota del protocolo del 0.03% se acumula en `state_data.need_take_pnl_coin` y `state_data.need_take_pnl_pc`. `TakePnl` mueve estos montos fuera de las bóvedas al destino especificado por el administrador, luego pone a cero los contadores.

Propiedad crucial: las reservas en el invariante siempre se calculan **menos** PnL acumulado, así que `TakePnl` no mueve la curva. Esto coincide con la convención de CPMM.

## Ejemplo trabajado

Estado del pool:

* `coin_reserve = 1_000_000_000_000` (1.000.000 lado coin; 6 decimales)
* `pc_reserve   = 2_000_000_000_000` (2.000.000 lado pc; 6 decimales)
* Comisiones: `swap = 25/10_000` predeterminado, `pnl = 3/10_000`.

Usuario: `SwapBaseIn` entrada exacta `1_000_000_000` coin (1.000 coin).

```
swap_fee        = ceil(1_000_000_000 * 25 / 10_000)    = 2_500_000
amount_after_fee =                                      997_500_000

amount_out = amount_after_fee * pc_reserve
           / (coin_reserve + amount_after_fee)
           = 997_500_000 * 2_000_000_000_000
           / (1_000_000_000_000 + 997_500_000)
           ≈ 1_995_015_009  (1.995,015 pc)

// De la comisión de swap de 2_500_000:
pnl_share = 2_500_000 * 3 / 25  = 300_000    (va al protocolo vía need_take_pnl_coin)
lp_share  = 2_500_000 * 22 / 25 = 2_200_000  (se queda en coin_reserve)

new coin_reserve = 1_000_000_000_000 + 1_000_000_000                 = 1_001_000_000_000
                   (de la cual 300_000 es PnL acumulado)
  curve coin_reserve = 1_001_000_000_000 − 300_000 = 1_000_999_700_000
new pc_reserve   = 2_000_000_000_000 − 1_995_015_009                 ≈ 1_998_004_984_991

k' = curve_coin_reserve * new_pc_reserve
   ≈ 2.000_002_701E24
k  = 1_000_000_000_000 * 2_000_000_000_000
   = 2.0E24
k' > k   ✓
```

La cuota del LP (`2_200_000`) no se desglosa en ningún lugar — es simplemente el residual que eleva `k'`.

## Reglas de precisión

* Las multiplicaciones de reservas utilizan `u128`; las divisiones finales redondean hacia cero.
* `swap_fee` redondea hacia arriba (así el pool no cobra menos).
* `amount_in` para `SwapBaseOut` redondea hacia arriba (así el usuario no paga menos).
* Los pools con ratios de reserva extremos pueden golpear `ZeroTradingTokens` en entradas muy pequeñas; la misma convención que CPMM.

## Limitaciones vs CPMM

* Las reservas de AMM v4 incluyen la porción en custodia de OpenBook, así que un integrador no puede cotizar correctamente desde solo `getTokenAccountBalance`. Siempre obtén el estado completo (bóvedas + `open_orders.free` + `open_orders.locked`), o utiliza el quote del SDK / API.
* AMM v4 no expone un TWAP estructurado en cadena. Los consumidores externos que quieran un precio respaldado por AMM v4 deben calcularlo por sí mismos a partir de logs de transacciones.
* Token-2022 no es soportado.

## A dónde ir ahora

* [`products/amm-v4/instructions`](/es/products/amm-v4/instructions) — donde se conectan `SwapBaseIn`, `Deposit`, etc.
* [`products/amm-v4/fees`](/es/products/amm-v4/fees) — mecánica completa de comisiones, detalles de `TakePnl`.
* [`algorithms/constant-product`](/es/algorithms/constant-product) — la derivación compartida.

Fuentes:

* [Código fuente del programa Raydium AMM — `raydium-io/raydium-amm`](https://github.com/raydium-io/raydium-amm)
* Módulo `Liquidity` de Raydium SDK v2
