Перейти к основному содержанию

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.

Эта страница переведена с помощью ИИ. За эталон принимается английская версия.Открыть английскую версию →

Инвариант

Пул поддерживает coin_reserve × pc_reserve = k, где:
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
На что нужно обратить внимание:
  1. Резервы включают суммы, зафиксированные на OpenBook. Лимит-ордера AMM остаются частью его ликвидности — они не «теряются» в ордербуке, а просто там хранятся. Вычисление k только по остаткам на цепи недооценивает резервы.
  2. Начисление PnL (need_take_pnl_*) вычитается, чтобы сохранить кривую, когда администратор снимает комиссии. То же самое в CPMM — исключение protocol_fees_*.
Каждая операция Swap* гарантирует k' ≥ k после добавления доли комиссии LP обратно в резервы.

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

AMM v4 использует пропорциональные комиссии (пары числитель/знаменатель) вместо соглашения 1/1_000_000 CPMM/CLMM. Структура Fees на цепи (см. Fees::initialize в исходниках программы) по умолчанию имеет значения:
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_fee_numerator:       25,
  swap_fee_denominator:     10_000,    // 25/10_000 = 0.25% — валовая комиссия на AMM-своп
}
Интерпретация (опубликованные стандартные значения мейннета):
  • Общая комиссия своп: swap_fee = amount_in × 25 / 10_000 = 0.25% от валового входа.
  • Доля протокола: pnl_numerator / pnl_denominator = 12 / 100 = 12% от комиссии своп, что составляет 0.25% × 12% = 0.03% от объёма. Эта доля накапливается в счётчиках PnL и выводится WithdrawPnl.
  • Доля LP: остальные 88% комиссии своп, что составляет 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; по умолчанию равно swap_fee, но читается из другого пути кода. Отклонения от этих стандартов редки, но существуют на нескольких старых пулах; всегда читайте комиссии из AmmInfo.fees перед цитированием.

Математика прямого своп (AMM путь)

Самый простой случай: пользователь свопит против хранилищ пула без взаимодействия с 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)
Резервы, используемые здесь, — это эффективные резервы. Исторически это было coin_vault_balance + coin_posted_on_openbook + ... (хранилище AMM плюс токены, заблокированные в ордерах OpenBook). После деактивации OpenBook баланс на ордербуке равен нулю, поэтому эффективные резервы равны сырым остаткам хранилища. Путь 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)

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

Больше не активно. Конструкция сетки, описанная в этом разделе, отражает, как AMM v4 первоначально отражала кривую на рынок OpenBook. Интеграция OpenBook деактивирована; пулы больше не выставляют и не поддерживают ордера на OpenBook. Математика ниже сохранена для контекста — она объясняет, для чего имели размер учётные записи target_orders / amm_open_orders и почему программа всё ещё проверяет параметры, связанные с MonitorStep, хотя киппер больше их не обновляет.
Отдельно от своп пользователей 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)

// Из 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.

Ограничения vs CPMM

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

Что дальше

Источники: