> ## 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.

# Математика AMM v4

> Инвариант constant-product с соглашением о комиссиях AMM v4, преобразование цены резерва в ордербук, построение целевой сетки ордеров и этап расчёта PnL.

<Info>
  **Эта страница переведена с помощью ИИ. За эталон принимается английская версия.**

  [Открыть английскую версию →](/products/amm-v4/math)
</Info>

## Инвариант

Пул поддерживает `coin_reserve × pc_reserve = k`, где (после удаления OpenBook в июле 2026 г.):

```
coin_reserve = coin_vault_balance - accrued_pnl_coin
pc_reserve   = pc_vault_balance   - accrued_pnl_pc
```

Обратите внимание на два момента:

1. Резервы теперь **только из хранилищ**. Исторический термин открытого ордера (токены, которые пул держал в залоге как лимит-ордера OpenBook) был удалён — на практике он был нулевым задолго до удаления. Вы можете вычислить `k` прямо из балансов хранилищ в блокчейне.
2. Начисление PnL (`need_take_pnl_*`) вычитается, чтобы кривая сохранялась, когда администратор снимает комиссии. Тот же принцип, что и исключение `protocol_fees_*` в CPMM.

Программа вычисляет это через `calc_total_without_take_pnl_no_orderbook` (старый вариант с поддержкой ордербука удалён).

Каждая операция `Swap*` обеспечивает `k' ≥ k` после добавления доли комиссии LP обратно в резервы.

## Соглашение о комиссиях

AMM v4 использует **комиссии в виде отношений** (пара числитель/знаменатель) вместо соглашения `1/1_000_000` в CPMM / CLMM. Структура `Fees` в блокчейне (см. [`Fees::initialize`](https://github.com/raydium-io/raydium-amm/blob/master/program/src/state.rs) в исходном коде программы) по умолчанию имеет:

```
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% — используется для ценообразования лимит-ордеров OpenBook

  pnl_numerator:            12,
  pnl_denominator:          100,       // 12/100   = 12%   — доля протокола ОТ комиссии swap

  swap_fee_numerator:       25,
  swap_fee_denominator:     10_000,    // 25/10_000 = 0.25% — валовая комиссия на swap-ах по пути AMM
}
```

Интерпретация (опубликованные значения по умолчанию на mainnet):

* **Общая комиссия swap:** `swap_fee = amount_in × 25 / 10_000 = 0.25%` от валового входа.
* **Доля протокола:** `pnl_numerator / pnl_denominator = 12 / 100 = 12%` **от комиссии swap**, что составляет `0.25% × 12% = 0.03%` от объёма. Эта доля начисляется на счётчики PnL и снимается через `WithdrawPnl`.
* **Доля LP:** оставшиеся `88%` комиссии swap, что составляет `0.25% × 88% = 0.22%` от объёма. Остаётся в пуле и увеличивает `k`.
* **Нет доли фонда.** AMM v4 не имеет разделения комиссии фонда, как в CPMM/CLMM.

Обратите внимание, что `pnl_numerator / pnl_denominator` — это доля **от комиссии**, а не от объёма торговли — частая ошибка при чтении этих имён полей.

`trade_fee_numerator / trade_fee_denominator` (также `25 / 10_000`) исторически использовалась интеграцией OpenBook при вычислении цен с учётом комиссии для сетки лимит-ордеров AMM. После удаления кода OpenBook это поле остаточное; активная комиссия swap — это `swap_fee_*`.

Отклонения от этих значений по умолчанию редки, но существуют на нескольких устаревших пулах; всегда читайте комиссии из `AmmInfo.fees` перед котировкой.

## Прямая математика swap (путь AMM)

Простейший случай: пользователь делает swap против хранилищ пула без взаимодействия с OpenBook. Внутренние резервы пула (включая размещения в книге) — это знаменатель.

**SwapBaseIn (точный вход):**

```
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)
```

Резервы, используемые здесь, — это балансы хранилищ (минус начисленный PnL). Исторически формула также добавляла токены, которые AMM заблокировал в ордерах OpenBook; **этот термин был удалён** — эффективные резервы теперь равны сырым балансам хранилищ минус ожидающий PnL. Путь `MonitorStep` / неявного расчёта, который раньше обновлял сторону OpenBook, был удалён.

**SwapBaseOut (точный выход):**

```
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)
```

## Взаимодействие с ордербуком (историческое)

<Note>
  **Удалено.** Построение сетки, описанное в этом разделе, отражает, как AMM v4 *первоначально* отражала кривую на рынке OpenBook. Интеграция OpenBook — включая кран `MonitorStep` и логику сетки `build_orders` — была **удалена из программы** (обновление июля 2026 г.). Математика ниже сохранена исключительно как исторический контекст для того, на что когда-то были рассчитаны счета `target_orders` / `amm_open_orders` в блокчейне.
</Note>

Отдельно от пользовательских swap-ов AMM v4 исторически размещала **сетку** лимит-ордеров на рынке OpenBook. Сетка вычислялась из параметров `AmmInfo`:

* **`depth`** — количество уровней цены с каждой стороны.
* **`amount_wave`** — базовая единица размера на уровень.
* **`min_size`**, **`coin_lot_size`**, **`pc_lot_size`** — ограничения рынка OpenBook.
* **`state_data.swap_acc_coin_fee`**, **`swap_acc_pc_fee`** — кумулятивные счётчики комиссий с момента последнего `TakePnl`.

Программа выводит цены на уровень, проходя от текущей цены кривой в шагах с постоянным отношением:

```
price_level(k) = curve_price × (1.0001 ^ k)       # концептуально
size_level(k)  = amount_wave × f(depth, k)        # сужается по depth
```

Точные цены и размеры определяются `target_orders`, вычисленными в `build_orders` и сравниваемыми с `amm_open_orders` на каждом `MonitorStep`. Любое расхождение приводит к отмене + новым размещениям. Недавно заполненные ордера на OpenBook расчитываются в хранилища пула при следующей операции, которая обновляет сторону OpenBook.

Интеграторам редко нужно вычислять сетку — хранитель Raydium её поддерживает — но полезно знать, что:

* Пул со значительной **ликвидностью в книге** имеет эту ликвидность, способствующую `k`, а не простаивающей.
* Устаревший рынок OpenBook (очередь событий полна, краны заблокированы) предотвращает обновления сетки; AMM может затем котировать цены, которые отличаются от видимого ордербука, пока не произойдёт следующий кран.

## Этап расчёта (PnL)

Доля протокола 0.03% начисляется в `state_data.need_take_pnl_coin` и `state_data.need_take_pnl_pc`. `TakePnl` перемещает эти суммы из хранилищ в указанное администратором место назначения, затем обнуляет счётчики.

Критическое свойство: резервы в инварианте всегда вычисляются **минус** начисленный PnL, поэтому `TakePnl` не перемещает кривую. Это соответствует соглашению CPMM.

## Проработанный пример

Состояние пула:

* `coin_reserve = 1_000_000_000_000` (1 000 000 на стороне coin; 6 десятичных)
* `pc_reserve   = 2_000_000_000_000` (2 000 000 на стороне pc; 6 десятичных)
* Комиссии: по умолчанию `swap = 25/10_000`, `pnl = 3/10_000`.

Пользователь: `SwapBaseIn` точный вход `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)

// Из комиссии swap 2_500_000:
pnl_share = 2_500_000 * 3 / 25  = 300_000    (идёт протоколу через need_take_pnl_coin)
lp_share  = 2_500_000 * 22 / 25 = 2_200_000  (остаётся в coin_reserve)

new coin_reserve = 1_000_000_000_000 + 1_000_000_000                 = 1_001_000_000_000
                   (из которых 300_000 — начисленный PnL)
  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   ✓
```

Доля LP (`2_200_000`) не выделяется отдельно — это просто остаток, который увеличивает `k'`.

## Правила точности

* Умножения резервов используют `u128`; финальные деления округляют к нулю.
* `swap_fee` округляется вверх (чтобы пул не недозарядил).
* `amount_in` для `SwapBaseOut` округляется вверх (чтобы пользователь не недоплатил).
* Пулы с экстремальными соотношениями резервов могут получить `ZeroTradingTokens` на очень малых входах; то же соглашение, что и в CPMM.

## Ограничения по сравнению с CPMM

* Резервы AMM v4 теперь только из хранилищ, поэтому вы **можете** котировать прямо из балансов хранилищ (минус `need_take_pnl_*`) — предыдущее требование добавлять суммы `open_orders.free` / `open_orders.locked` больше не применяется. Котировка SDK / API остаётся самым простым вариантом.
* AMM v4 не предоставляет структурированный TWAP в блокчейне. Внешние потребители, которые хотят цену, поддерживаемую AMM v4, должны вычислить её сами из логов торговли.
* Token-2022 не поддерживается.

## Что дальше

* [`products/amm-v4/instructions`](/ru/products/amm-v4/instructions) — где подключаются `SwapBaseIn`, `Deposit` и т. д.
* [`products/amm-v4/fees`](/ru/products/amm-v4/fees) — полная механика комиссий, детали `TakePnl`.
* [`algorithms/constant-product`](/ru/algorithms/constant-product) — общий вывод.

Источники:

* [Исходный код программы Raydium AMM — `raydium-io/raydium-amm`](https://github.com/raydium-io/raydium-amm)
* Модуль `Liquidity` Raydium SDK v2
