Skip to main content
Эта страница переведена с помощью ИИ. За эталон принимается английская версия.Открыть английскую версию →
Информация о версии. Все примеры на TypeScript ориентированы на @raydium-io/raydium-sdk-v2@0.2.64-alpha; они были последний раз выполнены для 0.2.42-alpha (2026-04), а их сигнатуры вызовов перепроверены для исходного кода 0.2.64-alpha 09.09.2026 на Solana mainnet-beta. Скелет Rust CPI в конце ориентирован на raydium-clmm в ветке master, которая закрепляет Anchor =0.32.1 — не 1.0.2, используемый на странице CPMM; они не могут находиться в одном крейте. Идентификаторы программ берутся из 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 вычисляет, какие массивы тиков касается диапазон, и передаёт их как аккаунты. Ему не нужно включать инструкцию инициализации — нет инструкции init-tick-array; OpenPosition* сам выделяет недостающий массив тиков за счёт платящей стороны.

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

Источник: src/clmm/increaseLiquidity.ts

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

Источник: src/clmm/decreaseLiquidity.ts и src/clmm/closePosition.ts
Чтобы собрать только комиссии и вознаграждения, вызовите decreaseLiquidity с liquidity = new BN(0). Побочный эффект инструкции — урегулирование token_fees_owed_{0,1} и reward_amount_owed и их передача — это единственный способ собрать любое из них. Чтобы полностью закрыть позицию после обнуления ликвидности и комиссий, передайте ownerInfo: { closePosition: true } в финальный вызов decreaseLiquidity. SDK добавляет ClosePosition и сжигает NFT.
Позиции с ограниченным эмитентом требуют совместимого построителя закрытия. Эти позиции имеют замороженный аккаунт токена NFT. ClosePosition должен добавить ID пула позиции как первый оставшийся аккаунт, чтобы CLMM мог разморозить аккаунт перед сжиганием. Ветка исходного кода не включает изменение SDK. Убедитесь, что ваш выпуск SDK явно поддерживает путь замороженного закрытия перед включением создания позиций с ограниченным эмитентом.
Для прямого клиента Anchor оставьте объявленные аккаунты без изменений и добавьте пул:
Вы можете передать poolId при каждом закрытии. CLMM читает его только когда positionNftAccount заморожен, что сохраняет один путь клиента совместимым со старыми и новыми позициями.

Сбор вознаграждения(й)

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

Своп

Источник: src/clmm/swap.ts
Моделирование проходит по карте тиков в автономном режиме с той же логикой, что и программа на цепи, и возвращает выходное количество (amountCalculated) плюс точный список аккаунтов, которые коснётся своп (accounts). Всегда передавайте remainingAccounts, которые возвращает моделирование: слишком мало — своп откатится в середине прохода с NotEnoughTickArrayAccount; устаревшие просто тратят вычисления.
PoolUtils.computeAmountOutFormat всё ещё существует, но ему нужна ComputeClmmPoolInfo ( computePoolInfo из getPoolInfoFromRpc, а не объект пула API) плюс два дополнительных обязательных аргумента — tickarrayBitmapExtension и blockTimestamp — и нет метода raydium.clmm.fetchTickArrays (fetchTickArrays — свободная функция; помощники уровня модуля — PoolUtils.fetchMultiplePoolTickArrays и tickData / tickArrays, возвращаемые getPoolInfoFromRpc).

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

createCustomizablePool — точка входа, которая раскрывает переключатели динамической комиссии и односторонней комиссии во время создания пула. Она принимает форму createPool плюс два дополнения:
Нет флага enableDynamicFee и нет параметра dynamicFeeConfigId, и нет startTime. Передача dynamicFeeConfig — это то, что включает динамические комиссии — опустите его и вы получите пул со статической комиссией, без ошибки. Также обратите внимание, что члены перечисления SDK — TokenOnlyA / TokenOnlyB, тогда как перечисление Rust на цепи пишет их как Token0Only / Token1Only; числовые значения совпадают (FromInput = 0).
createPool продолжает работать для пути с комиссией по умолчанию и без динамической комиссии. Используйте createCustomizablePool всякий раз, когда вам нужен любой из переключателей. См. products/clmm/instructions для списка аккаунтов на цепи.

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

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

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

SDK выводит PDA LimitOrderState из (owner, nonce PDA, order nonce), увеличивает LimitOrderNonce для каждого кошелька и вставляет ордер в когорту FIFO на этом тике.

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

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

Урегулирование заполненного ордера

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

Список припаркованных ордеров кошелька (в автономном режиме)

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

Скелет Rust CPI

Порядок оставшихся аккаунтов для SwapV2:
Если своп никогда не нуждается в расширении, опустите его; в противном случае это первый оставшийся аккаунт.

Распространённые ошибки

  • Конечные точки тика вне интервала → TickAndSpacingNotMatch. Всегда привязывайте через TickUtil.getPriceAndTick (единственное число TickUtil).
  • Недостаточно массивов тиков в SwapV2 → NotEnoughTickArrayAccount. Возьмите список из swapInternal(...).accounts.
  • Позиция полного диапазона без расширения битовой карты → расширение PDA должно быть записываемым; SDK обрабатывает это автоматически.
  • Путаница sqrt_price_x64 с price → ошибка в коэффициенте 2 здесь особенно болезненна. Если сомневаетесь, позвольте SDK вычислить это из читаемой человеком цены.
  • Слишком ранний сбор вознаграждений → каждый сбор — это DecreaseLiquidity с нулевой ликвидностью и стоит одну транзакцию. Группируйте через harvestAllRewards по многим позициям и помните, что его execute нуждается в { sequentially: true }.
  • Самостоятельное закрытие аккаунтов NFT → ClosePosition сжигает NFT и закрывает его ATA. Он также закрывает минт NFT Token-2022; классический минт SPL Token остаётся с нулевым предложением, потому что эта программа не может закрывать минты. Не закрывайте поддерживаемые аккаунты отдельно или инструкция откатится.
  • Открытие лимитного ордера на тике без интервала → TickAndSpacingNotMatch. Всегда квантуйте через экспортированный помощник getOrderTick.
  • Вызов decreaseLimitOrder на полностью заполненном ордере → InvalidOrderPhase. Вместо этого используйте settleLimitOrder затем closeLimitOrder.
  • Ожидание флага enableDynamicFee → его нет. Опущение dynamicFeeConfig просто создаёт пул со статической комиссией, молча и без ошибки. Если вы хотели динамические комиссии, передайте PublicKey аккаунта конфигурации, выбранный из /main/clmm-dynamic-config.

Что дальше

Источники: