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

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.

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

Кривая таблицы поиска

Stable AMM заменяет формулу x·y=k на разреженную таблицу поиска кортежей (x, y, price). При определении цены swap программа:
  1. Вычисляет текущее соотношение пула из резервов.
  2. Выполняет двоичный поиск в таблице, чтобы найти две записи, которые охватывают это соотношение.
  3. Линейно интерполирует между ними, чтобы получить промежуточную цену.
  4. Применяет комиссии и возвращает котировку.
Такой подход обменивает детерминированность формулы на гибкость администратора в формировании цены, и он достаточно эффективен, чтобы укладываться в бюджет вычислений Solana.

Макет таблицы и двоичный поиск

ModelDataInfo содержит до 50 000 записей DataElement, индексированных администратором. Активными являются только первые valid_data_count. Каждая запись:
DataElement {
  x: u64,      // Координата X (сумма на стороне монеты, масштабированная)
  y: u64,      // Координата Y (сумма на стороне ПК, масштабированная)
  price: u64,  // price = x/y, масштабированная на множитель
}
Для поиска цены при текущих резервах пула (x_real, y_real):
  1. Вычислите соотношение: target_ratio = (x_real * multiplier) / y_real.
  2. Выполните двоичный поиск записей, где (element.x * multiplier) / element.y охватывает target_ratio.
  3. При нахождении скобок [min_idx, max_idx] выполните интерполяцию.
Код двоичного поиска программы занимает ~150 строк в state.rs::ModelDataInfo::get_mininum_range_by_xy_real. Ключевой инвариант: записи должны быть отсортированы (x по возрастанию, y по убыванию, price по возрастанию) для работы поиска.

Линейная интерполяция

Когда две точки таблицы охватывают соотношение, интерполяция вычисляет промежуточную цену и пару резервов:
target = (x_real * multiplier) / y_real

[x1, y1, p1] = table[min_idx]
[x2, y2, p2] = table[max_idx]

// Интерполяция цены
p = p1 + (p2 - p1) * (target - ratio1) / (ratio2 - ratio1)

// Интерполяция резерва
x = x1 + (x2 - x1) * (target - ratio1) / (ratio2 - ratio1)
y = y1 + (y2 - y1) * (target - ratio1) / (ratio2 - ratio1)
Результат — кусочно-линейная кривая, которая плавно соединяет точки таблицы.

Масштабирование: множитель

Резервы пула и цены хранятся в разных масштабах. Поле multiplier на ModelDataInfo это учитывает. Общий паттерн:
  • Монета имеет 6 десятичных знаков, ПК имеет 18 десятичных знаков.
  • Множитель = 10^6 (или подобный).
  • Записи таблицы хранятся в уменьшенном масштабе, чтобы соответствовать границам u64.
Программа переmasштабирует при чтении/записи через:
real_value = table_value * ratio / multiplier
table_value = real_value * multiplier / ratio

Определение цены swap: SwapBaseIn и SwapBaseOut

SwapBaseIn (точный ввод)

При вводе суммы amount_in:
  1. Получите текущее соотношение из (coin_vault, pc_vault).
  2. Найдите охватывающие записи таблицы и интерполируйте, чтобы получить соотношение в пространстве таблицы.
  3. Преобразуйте вход в пространство таблицы: dx_table = amount_in * multiplier / ratio.
  4. Запросите таблицу с новой координатой X, чтобы найти новый Y.
  5. dy_table = y_old - y_new.
  6. Преобразуйте назад: dy_real = dy_table * ratio / multiplier.
  7. Примените комиссию за trade: dy_output = dy_real - (dy_real * trade_fee_numerator / trade_fee_denominator).
  8. Вернитесь к dy_output.

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

Симметрично: при требуемом amount_out решите, сколько требуется amount_in. Оба пути сначала расчищают заполненные ордера OpenBook (через логику, подобную MonitorStep), поэтому эффективные резервы отражают любые заполнения из предыдущего блока.

Применение комиссий

Идентично AMM v4: см. products/amm-v4/math для полного вывода.
gross_fee = amount_in * (swap_fee_numerator / swap_fee_denominator)    // например, 0.25%
lp_portion = gross_fee - (gross_fee * pnl_numerator / pnl_denominator) // например, 0.22%
pnl_portion = gross_fee * (pnl_numerator / pnl_denominator)            // например, 0.03%
pnl_portion идет на need_take_pnl_* и очищается администратором через WithdrawPnl. lp_portion остается в хранилище, увеличивая k и принося пользу держателям LP токенов.

MonitorStep и OpenBook

Как и в AMM v4, MonitorStep является инструкцией crankа, которая:
  1. Расчищает ожидающие заполнения ордеров OpenBook (перемещает токены из хранилищ в пул).
  2. Обновляет AmmInfo.target_orders с новой сеткой слотов лимитных ордеров.
  3. Публикует новую сетку на OpenBook.
Сетка вычисляется из таблицы: программа использует таблицу поиска для поиска ценовых точек и преобразует их в ордера OpenBook. Стоимость вычислений MonitorStep: ~150k–180k CU (аналогично AMM v4).

Резюме: почему это работает

Дизайн таблицы поиска + интерполяция является эффективным и гибким:
  • Эффективность: двоичный поиск O(log 50,000) ≈ 16 итераций, каждая ~ 300–500 CU. Интерполяция — несколько умножений/делений. Общая стоимость котировки ~5k–15k CU, намного дешевле, чем перевычисление формулы при каждом swap.
  • Гибкость: администратор может кодировать любую кусочно-линейную кривую. Пары стейблкойнов получают высокую плотность около 1:1; обеспеченные пары получают пользовательские кривые.
  • Совместимость с OpenBook: та же логика MonitorStep / TargetOrders из AMM v4 применима. Обнаружение цены через таблицу питает поколение сетки ордеров.
Для углубленного изучения логики интерполяции см. raydium-stable/program/src/state.rs, методы get_data_by_x, get_data_by_y, get_dy_by_dx_base_in и т.д.

Что дальше

  • Accounts — справочник полей ModelDataInfo и DataElement.
  • InstructionsInitModelData, UpdateModelData для заполнения таблицы.
  • Fees — применение комиссий и WithdrawPnl.
  • products/amm-v4/math — для логики определения цены ордеров OpenBook с учетом комиссий.
Источники:
  • raydium-stable/program/src/state.rs (реализации интерполяции и двоичного поиска)
  • raydium-stable/program/src/math.rs (утилиты калькулятора)