Перейти к основному содержанию
Эта страница переведена с помощью ИИ. За эталон принимается английская версия.Открыть английскую версию →
Информация о версии. Все демо ориентированы на @raydium-io/raydium-sdk-v2@0.2.42-alpha для Solana mainnet-beta, проверено в апреле 2026 г. Идентификаторы программ берутся из reference/program-addresses через SDK.

Настройка

Каждый демо-пример на этой странице соответствует файлу в raydium-sdk-V2-demo/src/clmm; ссылка на GitHub указана рядом с каждым разделом. Инициализация следует шаблону config.ts.template из репозитория демо (исходник) — disableFeatureCheck: true рекомендуется для любой нетривиальной интеграции:

Создание пула CLMM

Исходник: src/clmm/createPool.ts
SDK выполняет следующие действия:
  • Сортирует mint1/mint2 по байтовому порядку перед деривацией.
  • Вычисляет sqrt_price_x64 = floor(sqrt(initialPrice × 10^(dB−dA)) × 2^64).
  • Создаёт аккаунты observation и tick_array_bitmap_extension.
  • Оплачивает комиссию за создание пула, определённую в ammConfig.

Открытие позиции в выбранном диапазоне

Исходник: src/clmm/createPosition.ts
SDK автоматически определяет, каких tick-массивов касается диапазон, и добавляет инструкции InitTickArray для тех из них, что ещё не инициализированы.

Увеличение ликвидности существующей позиции

Исходник: src/clmm/increaseLiquidity.ts

Уменьшение ликвидности (с одновременным сбором комиссий)

Исходники: src/clmm/decreaseLiquidity.ts и src/clmm/closePosition.ts
Чтобы только собрать комиссии, вызовите decreaseLiquidity с liquidity = new BN(0). Побочный эффект инструкции — погашение tokens_fees_owed_{0,1} и их перевод владельцу. Чтобы полностью закрыть позицию после обнуления ликвидности и сбора комиссий, передайте closePosition: true в финальный вызов decreaseLiquidity. SDK добавит ClosePosition и сожжёт NFT.

Сбор наград

Исходник: src/clmm/harvestAllRewards.ts
harvestAllRewards перебирает все позиции во всех переданных пулах, пакует инструкции CollectRewardUpdateRewardInfos при необходимости) и при нужде разбивает их на несколько транзакций.

Swap

Исходник: src/clmm/swap.ts
computeAmountOutFormat обходит карту тиков офф-чейн по той же логике, что и программа на чейне, и возвращает:
  • ожидаемое количество выходных токенов,
  • минимальное количество выходных токенов с учётом slippage,
  • список аккаунтов tick-массивов, которые затронет реальный swap (remainingAccounts).
Всегда передавайте remainingAccounts, полученный от симуляции: при нехватке аккаунтов swap упадёт на середине обхода с ошибкой TickArrayNotFound, а при передаче устаревших — впустую потратится compute budget.

Создание настраиваемого пула CLMM

createCustomizablePool — новая точка входа, открывающая переключатели динамических комиссий и одностороннего сбора комиссий прямо при создании пула. Принимает те же параметры, что и createPool, плюс три дополнительных поля:
createPool по-прежнему работает для пути с комиссией по умолчанию без лимитных ордеров и динамических комиссий. Используйте createCustomizablePool, когда нужен хотя бы один из трёх новых параметров. Список аккаунтов on-chain см. в products/clmm/instructions.

Лимитные ордера

Лимитный ордер размещает вводимые пользователем токены на одном тике и исполняется по принципу FIFO при пересечении этого тика swap-ом. Выходные токены переводятся на ATA владельца в момент расчёта; присутствие владельца онлайн для исполнения ордера не требуется.

Открытие лимитного ордера

SDK выводит PDA LimitOrderState из (pool, owner, tick, nonce), инкрементирует LimitOrderNonce для пары (pool, owner) и вставляет ордер в очередь FIFO на данном тике.

Увеличение / уменьшение открытого ордера

decreaseLimitOrder может уменьшать только неисполненную часть ордера; исполненная часть заморожена до расчёта. Обе инструкции завершаются с ошибкой InvalidOrderPhase, если ордер уже полностью исполнен.

Расчёт по исполненному ордеру

settleLimitOrder считывает unfilled_ratio_x64 ордера относительно трекера когорты, вычисляет исполненный выход и переводит его на ATA владельца. Владелец может вызвать это самостоятельно; limit_order_admin (офф-чейн-кипер) также может вызвать это от имени владельца — выходные токены в любом случае отправляются владельцу. Для закрытия полностью рассчитанных ордеров с возвратом ренты используйте closeLimitOrder (единичный) или closeAllLimitOrder (пакетный). Для пакетного расчёта нескольких ордеров settleAllLimitOrder упаковывает максимальное количество вызовов SettleLimitOrder, умещающееся в одну v0-транзакцию.

Просмотр активных ордеров кошелька (офф-чейн)

Эндпоинт активных ордеров возвращает как неисполненные, так и частично исполненные ордера в одном ответе (поля totalAmount / filledAmount / pendingSettle различают фазы). Для истории закрытых ордеров используйте /limit-order/history/order/list-by-user?wallet=… (по кошельку, с пагинацией через nextPageId); для полного журнала событий конкретного ордера — /limit-order/history/event/list-by-pda?pda=….

Скелет Rust CPI

Порядок remaining-аккаунтов для SwapV2:
Если swap не требует расширения, его можно опустить; в противном случае оно идёт первым среди remaining-аккаунтов.

Типичные ошибки

  • Несоответствие тиков шагуInvalidTickIndex. Всегда выравнивайте через TickUtils.getPriceAndTick.
  • Недостаточно tick-массивов в SwapV2TickArrayNotFound. Используйте computeAmountOutFormat для получения полного списка.
  • Полнодиапазонная позиция без bitmap-расширения → PDA расширения должен быть записываемым; SDK обрабатывает это автоматически.
  • Путаница между sqrt_price_x64 и price → ошибка в 2 раза здесь особенно болезненна. При сомнениях доверьте вычисление SDK, передав ему человекочитаемую цену.
  • Слишком частый сбор наград → каждый сбор стоит одну транзакцию. Используйте harvestAllRewards для пакетного сбора по многим позициям.
  • Сожжение NFT при наличии непогашенного долга по рентеClosePosition также закрывает mint NFT и ATA; не закрывайте их отдельно, иначе программа вернёт ошибку.
  • Открытие лимитного ордера на тике, не кратном шагуInvalidTickIndex. Всегда квантизируйте через TickUtils.getPriceAndTick.
  • Вызов decreaseLimitOrder на полностью исполненном ордереInvalidOrderPhase. Используйте settleLimitOrder, а затем closeLimitOrder.
  • Отсутствие dynamicFeeConfigId при enableDynamicFee: trueCreateCustomizablePool вернёт ошибку InvalidDynamicFeeConfigParams. Либо отключите динамическую комиссию, либо выберите конфигурацию из /main/clmm-dynamic-config.

Что делать дальше

Источники: