Skip to main content
Эта страница переведена с помощью ИИ. За эталон принимается английская версия.Открыть английскую версию →
Эта страница дополняет products/clmm/accounts (описание аккаунтов) и products/clmm/math (математика). Она является авторитетным источником для аргументов и порядка аккаунтов; конкретные макеты байтов берутся из IDL.Обновление программы 2026-09 переписало CLMM на Anchor 1.0.2 / Solana 3.1.10, добавило админ-инструкцию CollectExcessLamports и изменило, что CreateAmmConfig записывает в owner / fund_owner. Ни одна пользовательская инструкция не изменила свои аккаунты, аргументы или математику. См. запись в журнале изменений от 2026-09-30.Обновление программы 2026-10-22 переименовывает CreatePermissionedPool в CreateCustomizablePoolV2, делает её вызываемой кем угодно и удаляет аккаунт Permission с его двумя админ-инструкциями. См. запись в журнале изменений от 2026-10-22.

Инвентарь инструкций

Нет инструкции инициализации tick array, и она не требуется. Tick array создаётся внутри OpenPosition* / IncreaseLiquidity* через TickArrayState::get_or_create_tick_array, оплачивается payer. Передайте (возможно, ещё неинициализированный, принадлежащий системе) PDA tick array как tick_array_lower / tick_array_upper и программа выделит его, если он отсутствует. OpenLimitOrder делает то же самое для своего единственного tick_array.
Большинство админ-только инструкций (CreateAmmConfig, UpdateAmmConfig, UpdatePoolStatus, CreateOperationAccount, UpdateOperationAccount, CloseProtocolPosition) защищены hardcoded admin pubkey программы. CreateSupportMintAssociated / CloseSupportMintAssociated принимают либо admin pubkey либо выделенный ключ владельца support-mint; CollectExcessLamports принимает либо admin pubkey либо выделенный кошелёк для сбора lamports. Админ-инструкции потока вознаграждения (TransferRewardOwner, CollectRemainingRewards) защищены финансистом вознаграждения, а не админом программы. Суффикс V2 означает “поддерживает Token-2022 на хранилищах / NFT, требует слота расширения bitmap”. SDK по умолчанию выбирает V2 для новых пулов.

CreatePool

Аргументы
Аккаунты (сокращённо)
Слоты 10 и 11 — по mint, а не “SPL Token затем Token-2022”. Каждый ограничен mint::token_program на соответствующем mint, поэтому для пула, чей token_mint_0 — Token-2022 и token_mint_1 — классический SPL, вы должны передать Token-2022 в слот 10 и SPL Token в слот 11. CreateCustomizablePool и CreateCustomizablePoolV2 используют те же два слота.
Предусловия
  • token_mint_0 < token_mint_1 по порядку байтов.
  • amm_config.disable_create_pool == false.
  • Mints не отклонены списком разрешённых расширений Token-2022.
Постусловия
  • pool_state.sqrt_price_x64 = sqrt_price_x64, tick_current = floor(log_{1.0001}(price)).
  • pool_state.liquidity = 0 (позиций нет).
  • pool_state.fee_on = FromInput (устаревшее значение по умолчанию).
  • pool_state.dynamic_fee_info обнулен (динамическая комиссия отключена).

CreateCustomizablePool

Рекомендуется для новых пулов. Тот же эффект, что CreatePool, плюс режим сбора комиссии для каждого пула и опциональное включение динамической комиссии. Аргументы
Аккаунты — ровно 13 объявленных аккаунтов CreatePool. dynamic_fee_config — не объявленный аккаунт.
Когда enable_dynamic_fee = true, DynamicFeeConfig для снимка должен быть предоставлен как последний remaining_account — обработчик читает ctx.remaining_accounts.last(). Любые PDA обхода SupportMintAssociated должны поэтому идти перед ним, или программа снимает неправильный аккаунт и не может десериализовать. Его пропуск при установленном флаге завершается с AccountLack.
Предусловия — те же, что CreatePool. Если enable_dynamic_fee = false, никакой remaining_account не требуется и любые переданные сканируются только на предмет записей support-mint. Постусловия
  • pool_state.fee_on установлен на выбранный вариант CollectFeeOn.
  • Если динамическая комиссия была включена: pool_state.dynamic_fee_info инициализирован из предоставленного DynamicFeeConfig (пять параметров калибровки скопированы; поля состояния обнулены).
  • В противном случае: pool_state.dynamic_fee_info обнулен (= динамическая комиссия неактивна навсегда для этого пула).
fee_on и бит включения динамической комиссии устанавливаются только при создании пула. Нет встроенного обновления — пулы, созданные через устаревший CreatePool, не могут ретроактивно получить динамическую комиссию или одностороннюю комиссию. Новые развёртывания должны по умолчанию использовать эту инструкцию.

CreateCustomizablePoolV2

Как CreatePool, так и CreateCustomizablePool выводят PDA пула из ["pool", amm_config, token_mint_0, token_mint_1], поэтому существует ровно один канонический адрес пула на каждую тройку (config, mint0, mint1) — второй вызов init с теми же seeds завершится ошибкой. CreateCustomizablePoolV2 снимает это ограничение, добавляя предоставленный клиентом seed_index: u16 в seeds PDA пула, что позволяет создавать несколько пулов для одной пары и уровня комиссии — каждый по своему адресу. Может быть вызвана кем угодно. Всё остальное в пуле идентично CreateCustomizablePool: она принимает те же CreateCustomizableParams и поддерживает одностороннюю комиссию и опцию динамической комиссии.
До обновления от 2026-10-22 эта инструкция называлась CreatePermissionedPool и требовала, чтобы плательщик владел PDA Permission, выданным администратором. Обновление переименовало её, удалило аккаунт permission и удалило механизм разрешений. Дискриминатор изменился вместе с названием, поэтому клиенты, собранные для CreatePermissionedPool, должны быть пересобраны.
Аргументы
Аккаунты remaining_accounts: PDA реестра поддерживаемых минтов для Token-2022 минтов, которые их требуют, и DynamicFeeConfig в конце, когда enable_dynamic_fee = true — как в CreateCustomizablePool. Предусловия
  • seed_index != 0. seed_index равный 0 зарезервирован для устаревших пулов и отклоняется здесь; компонент seed [0, 0] — это то, что заставляет адрес устаревшего пула свернуться в классическую четырёхсидовую форму.
  • Пул не существует по выведённому адресу.
  • Те же правила для минтов и списков разрешений, что и в CreatePool.
Постусловия
  • Новый pool_state существует по адресу, выведённому из seed_index, с pool_state.seed_index = seed_index.
  • Все остальные постусловия совпадают с CreateCustomizablePool (режим комиссии, опциональная динамическая комиссия).
Поскольку pool_creator не проверяется, любой плательщик может записать любой адрес в pool_state.owner. Этот адрес может вызвать InitializeReward на пуле, но это не доказательство того, кто создал пул. Интеграторы не должны помечать или ранжировать V2 пулы по их owner.

OpenPositionV2 / OpenPositionWithToken22Nft

Создайте новую позицию внутри существующего пула. Аргументы
Аккаунты — два варианта имеют разные списки аккаунтов. OpenPositionV2 объявляет 22; OpenPositionWithToken22Nft объявляет 20. OpenPositionV2, по порядку: OpenPositionWithToken22Nft — это тот же список с удалёнными metadata_account (5) и metadata_program (19) — вместо этого она записывает метаданные позиции через расширение метаданных Token-2022 на минте NFT — итого 20 аккаунтов. Её position_nft_mint — это простой Signer, а position_nft_account — UncheckedAccount.
tick_array_bitmap_extension не является объявленным аккаунтом ни в одном из вариантов. Когда диапазон позиции выходит за пределы встроенного tick_array_bitmap пула (±512 массива тиков), добавьте PDA TickArrayBitmapExtension с seeds ["pool_tick_array_bitmap_extension", pool_state] как remaining_accounts[0].
Математика — см. products/clmm/math. Учитывая base_flag, программа разрешает либо liquidity, либо (amount_0_max, amount_1_max) в фактическое L и фактические потреблённые суммы токенов. Предусловия
  • tick_lower < tick_upper, оба кратны pool.tick_spacing, в пределах [MIN_TICK, MAX_TICK].
  • Передаются два PDA массива тиков. Они не обязаны уже существовать — get_or_create_tick_array выделяет отсутствующий за счёт payer внутри этой инструкции. Нет отдельной инструкции инициализации массива тиков.
  • Пользователь имеет как минимум amount_0_max и amount_1_max в исходных ATA.
Постусловия
  • personal_position существует, liquidity установлена, fee_growth_inside_last снята.
  • Записи массива тиков в tick_lower и tick_upper обновлены (liquidity_gross += L, liquidity_net ± L, снимки роста комиссии поддерживаются).
  • pool_state.liquidity += L, если позиция в диапазоне (tick_lower ≤ tick_current < tick_upper).
  • Минт NFT позиции записывает pool_state как орган заморозки. Полномочия минта удаляются после чеканки единственного NFT. Запись органа заморозки не изменяет состояние аккаунта токена NFT.
  • Аккаунт токена NFT остаётся разморозным, если инструкция — это OpenPositionV2 или OpenPositionWithToken22Nft и полномочия заморозки любого из минтов хранилища совпадают со списком ограниченных издателей CLMM. Только этот совпадающий путь V2 замораживает аккаунт. OpenPosition V1 не замораживает.
Распространённые ошибки — TickInvalidOrder (tick_lower >= tick_upper), TickAndSpacingNotMatch (конечная точка не кратна tick_spacing), InvalidTickIndex (вне [MIN_TICK, MAX_TICK]), MissingTickArrayBitmapExtensionAccount (диапазон вне встроенного растра и расширение не добавлено), NotApproved (pool_state.status блокирует открытие), ZeroAmountSpecified.
Заморозка позиции не добавляет объявленные аккаунты инструкции или аргументы. Клиенты могут открывать эти позиции с существующими макетами V2. Поведение выбирается на цепи из vault_0_mint и vault_1_mint.

IncreaseLiquidityV2

Добавьте ликвидность в уже открытую позицию. Аргументы
Аккаунты — 15, и не выводимы из OpenPosition: нет rent, нет system_program, нет associated_token_program и нет аккаунта метаданных. Добавьте PDA TickArrayBitmapExtension как remaining_accounts[0], когда диапазон позиции находится вне встроенного растра. Эффект
  • Переводит amount_0_actual / amount_1_actual из пользователя → хранилища.
  • Увеличивает personal_position.liquidity и pool_state.liquidity (если в диапазоне), а также liquidity_gross / liquidity_net конечных тиков соответственно.
  • Собирает комиссии и награды, накопленные с последнего касания, и кредитует их на token_fees_owed_{0,1} / reward_amount_owed. Они выплачиваются только при DecreaseLiquidity / DecreaseLiquidityV2, а не при увеличении — нет отдельной инструкции сбора.

DecreaseLiquidityV2

Удалите ликвидность из позиции. Аргументы
Аккаунты — 16, и не той же формы или порядка, что и IncreaseLiquidityV2: personal_position и pool_state поменялись местами, хранилища идут перед массивами тиков, аккаунты со стороны пользователя названы recipient_token_account_*, и есть дополнительный memo_program. Оставшиеся аккаунты — три на каждую активную собираемую награду, в порядке reward_token_vault(W), recipient_token_account(W), reward_vault_mint. Добавьте PDA TickArrayBitmapExtension в начало, когда диапазон позиции находится вне встроенного растра.
Это также единственный способ собрать комиссии и награды. Чтобы собрать без изменения позиции, вызовите с liquidity = 0, amount_0_min = 0, amount_1_min = 0.
Эффект
  • Вычисляет (amount_0, amount_1) для удалённого L с учётом текущего sqrt_price_x64.
  • Рассчитывает комиссии/награды, накопленные с последнего касания, как в IncreaseLiquidity.
  • Переводит amount_0 + fees_owed_0 и amount_1 + fees_owed_1 из хранилищ пользователю.
  • Уменьшает счётчики ликвидности; если новое personal_position.liquidity == 0, позиция имеет право на ClosePosition.
Проскальзывание — amount_0_min и amount_1_min — это минимумы, которые пользователь принимает за вычетом комиссий передачи Token-2022 на выходной стороне.

ClosePosition

Сжечь NFT позиции и закрыть PersonalPositionState. Объявленные аккаунты Оставшиеся аккаунты
  • Незамороженный NFT: не требуется; дополнительный аккаунт пула безвреден, так как обработчик его не читает.
  • Замороженный NFT: добавьте personal_position.pool_id как первый оставшийся аккаунт. Программа загружает его как PoolState и использует его PDA-семена для подписания разморозки.
Предусловия
  • personal_position.liquidity == 0.
  • tokens_fees_owed_{0,1} == 0.
  • Все счётчики вознаграждений reward_amount_owed == 0.
(То есть сначала соберите всё и уменьшите до нуля.) Эффект
  • Если аккаунт NFT токена заморожен, проверяет, что первый оставшийся аккаунт равен personal_position.pool_id, затем размораживает его с помощью PDA пула.
  • Сжигает NFT.
  • Закрывает аккаунт NFT токена и personal_position, возвращая ренту nft_owner. Если NFT позиции использует Token-2022, также закрывает минт NFT; классические минты SPL Token не могут быть закрыты и остаются с нулевым предложением.
Разморозка, сжигание и закрытие атомарны. NFT не может стать передаваемым между этими шагами. Условный разрыв клиента — объявленный макет IDL не изменился, поэтому старые клиенты продолжают закрывать существующие и незамороженные позиции. Старый построитель, который опускает оставшийся аккаунт пула, завершается с ошибкой AccountLack при закрытии замороженной позиции. Передача пула при каждом закрытии — это самая простая совместимая стратегия.

SwapV2

Пройти по кривой ликвидности; точный вход или точный выход в зависимости от is_base_input. Аргументы
Аккаунты (сокращённо) Вызывающие стороны передают ранжированный список массивов тиков, охватывающих ожидаемый проход своп; программа использует столько, сколько ей нужно. SDK вычисляет этот список через PoolUtils.computeAmountOutFormat или конечную точку котировки API. Предусловия
  • pool_state.status разрешает своп.
  • now >= open_time.
  • sqrt_price_limit_x64 находится на правильной стороне sqrt_price_x64 для направления.
Распространённые ошибки — TooLittleOutputReceived (проскальзывание при точном входе), TooMuchInputPaid (проскальзывание при точном выходе), SqrtPriceLimitOverflow, NotEnoughTickArrayAccount, InvalidFirstTickArrayAccount, MissingTickArrayBitmapExtensionAccount, LiquidityInsufficient, NotApproved (бит своп установлен на pool_state.status). CLMM не имеет варианта ExceededSlippage — это имя принадлежит CPMM — и не имеет TickArrayNotFound. Что SwapV2 делает внутри, что должны знать вызывающие стороны (выпуск после 2025 года):
  1. Динамическая надбавка комиссии — если pool.dynamic_fee_info ненулевой, программа обновляет накопитель волатильности, используя расстояние тика, пройденное с момента последнего своп (с правилами фильтра/затухания из products/clmm/fees), и добавляет dynamic_fee_component поверх AmmConfig.trade_fee_rate. Общая комиссия ограничена 10% (MAX_FEE_RATE_NUMERATOR / 1_000_000).
  2. Сопоставление лимитных ордеров — когда проход цены пересекает тик, содержащий открытые лимитные ордера, программа сначала заполняет доступную ликвидность лимитного ордера на этом тике (FIFO по order_phase), затем продолжает вдоль кривой ликвидности LP. Заполненные суммы обновляют tick.unfilled_ratio_x64 и tick.part_filled_orders_remaining для последующего урегулирования; сами ордера остаются неиспользованными до тех пор, пока их владелец не вызовет SettleLimitOrder.
  3. Маршрутизация комиссии с одной стороны — когда pool.fee_on = Token0Only или Token1Only, шаг своп всё ещё вычисляет одинаковый ввод-вывод торговли; комиссия затем маршрутизируется на настроенную сторону. Для направлений, где настроенная сторона комиссии является выходом, комиссия вычитается из выхода своп (пользователь получает out − fee); для направлений, где это вход, поведение совпадает с FromInput. См. is_fee_on_input(zero_for_one) и is_fee_on_token0(zero_for_one) на PoolState.
Swap (V1) реализует ту же динамическую комиссию, маршрутизацию комиссии с одной стороны и сопоставление лимитных ордеров, что и SwapV2; единственная функция, которой ему не хватает, — это поддержка Token-2022 — оба хранилища должны быть классическим SPL Token. Пулы с любым минтом Token-2022 должны быть своп через SwapV2. Агрегатор и SDK уже предпочитают V2 для каждого этапа CLMM, поэтому вызывающим сторонам не нужно ветвиться по типу минта.

OpenLimitOrder

Разместить ордер на продажу на определённом тике. Ордер находится в когорте FIFO для каждого тика и заполняется по мере прохода цены. Аргументы
Аккаунты (сокращённо) Оставшиеся аккаунты — [0] tick_array_bitmap_extension, требуется только при инициализации массива тиков, чей начальный индекс выходит за пределы встроенной битовой карты пула. Передайте ничего в противном случае.
Нет аккаунта rent: структура заканчивается на system_program, 13 объявленных аккаунтов. Случайный rent в позиции 14 попадает ровно туда, где читается опциональное расширение битовой карты, поэтому ордер кажется работающим до первого раза, когда нужно создать массив тиков вне встроенной битовой карты — и затем завершается с ошибкой.
Изменение списка аккаунтов (выпуск 2026-07). OpenLimitOrder теперь также принимает аккаунты выходной стороны — output_token_account, output_vault и output_vault_mint — в дополнение к входной стороне. Они используются только для валидации: программа отклоняет ордер, если входной или выходной аккаунт токена владельца заморожен. Это гарантирует, что заполнение может быть фактически урегулировано на выходной ATA владельца, что важно для минтов Token-2022 с разрешением / замораживанием по умолчанию (например, разрешённые токены), где аккаунт может быть ещё не разморожен. Клиенты, построенные на основе старого односторонного списка аккаунтов, должны добавить три выходных аккаунта.
Предусловия
  • Ни input_token_account, ни output_token_account не заморожены (иначе NotApproved).
  • pool_state.status разрешает как операцию своп (бит 4), так и операцию лимитного ордера (бит 5) (иначе NotApproved).
  • tick_index % pool.tick_spacing == 0 и в пределах [MIN_TICK, MAX_TICK].
  • tick_index находится на правой стороне pool.tick_current для выбранного направления (продажа token0 → тик должен быть выше текущего, и наоборот). Продажа на уже пересечённом тике будет сопоставлена немедленно и отклонена.
Постусловия
  • limit_order существует, снимая снимок tick.order_phase и tick.unfilled_ratio_x64 во время открытия.
  • tick.orders_amount += amount (в текущей когорте).
  • limit_order_nonce.order_nonce += 1.
  • Испущено OpenLimitOrderEvent.
Распространённые ошибки — NotApproved (входной или выходной аккаунт токена заморожен, или пул имеет отключённый своп / лимитный ордер), ZeroAmountSpecified (amount == 0 после комиссии передачи входной стороны), InvalidLimitOrderAmount (сумма будет производить выход ниже 1 базовой единицы на этом тике, или переполнение u64), InvalidTickIndex (вне [MIN_TICK, MAX_TICK], или на неправильной стороне tick_current для выбранного направления), TickAndSpacingNotMatch (tick_index % pool.tick_spacing != 0), OrderPhaseSaturated.

IncreaseLimitOrder

Добавить к существующему открытому ордеру. Может быть вызвано только owner ордера. Аргументы
Аккаунты — 8, только входная сторона. Опускает аккаунт nonce, все три аккаунта выходной стороны и system_program. Предусловия
  • limit_order.owner == signer.
  • Ордер всё ещё находится в той же когорте (tick.order_phase == limit_order.order_phase). Если когорта уже начала заполняться, ордер частично урегулирован — вызывающей стороне следует сначала вызвать DecreaseLimitOrder или SettleLimitOrder для продвижения вперёд.
Эффект
  • Передаёт amount из ATA владельца в input_vault.
  • limit_order.total_amount += amount; tick.orders_amount += amount.

DecreaseLimitOrder

Уменьшить или полностью отменить открытый ордер. Возвращает незаполненный остаток владельцу, плюс любой выход, уже урегулированный предыдущими частичными заполнениями. Аргументы
Аккаунты — входная и выходная стороны токена: Эффект
  • Пересчитывает заполненную сумму ордера из unfilled_ratio_x64 когорты с момента открытия.
  • Отправляет заполненный выход на output_token_account.
  • Отправляет amount незаполненного входа обратно на input_token_account.
  • Обновляет limit_order соответственно. Если новый незаполненный остаток равен нулю, программа закрывает аккаунт и возвращает ренту owner.

SettleLimitOrder

Отправить заполненные выходные токены владельцу без изменения незаполненного остатка ордера. Полезно, когда auto_withdraw киперы хотят постепенно выплачивать долгосрочные частичные заполнения. Вызывающая сторона — либо owner ордера, либо limit_order_admin программы (горячий кошелек для операций, работающий в автоматизированном цикле киперов). Кипер не имеет других полномочий — он не может перемещать средства пользователя за пределы отправки заполненного выхода на ATA owner ордера. Аккаунты Эффект
  • Вычисляет накопленный выход, используя (limit_order.unfilled_ratio_x64, tick.unfilled_ratio_x64).
  • Переводит дельту на output_token_account.
  • Обновляет limit_order.settled_output.
  • Не закрывает ордер; он остаётся открытым для любого оставшегося входа.

CloseLimitOrder

Закрыть полностью использованный аккаунт ордера. Рента всегда возвращается limit_order.owner независимо от того, кто подписывает. Вызывающая сторона — либо owner, либо limit_order_admin. Предусловия
  • Ордер имеет нулевой незаполненный остаток (либо amount == total_amount был заполнен и урегулирован, либо владелец ранее уменьшил ордер до нуля и забыл его закрыть).
Эффект
  • Закрывает limit_order; рента отправляется limit_order.owner.

CreateDynamicFeeConfig (admin)

Создать переиспользуемый набор параметров под индексом u16. Аргументы
Аккаунты Частые ошибки — InvalidDynamicFeeConfigParams, если decay_period <= filter_period или любое поле с нулевым значением выходит за границы.

UpdateDynamicFeeConfig (admin)

Изменить существующий DynamicFeeConfig. Пулы, которые уже сделали снимок конфига при создании, не обновляются ретроактивно; только вновь созданные пулы, ссылающиеся на этот конфиг, получат новые значения. Аргументы — те же пять полей калибровки, что и в CreateDynamicFeeConfig (filter_period, decay_period, reduction_factor, dynamic_fee_control, max_volatility_accumulator); index фиксирован при создании и не передаётся здесь повторно.

CollectProtocolFee / CollectFundFee

Собрать накопленные комиссии протокола/фонда из vaults пула в адрес получателя, обнулив соответствующие поля PoolState.protocol_fees_* / fund_fees_*. Это не макет CPMM — CLMM не имеет аккаунта authority, и поля получателя названы recipient_token_account_{0,1} вместо recipient_token_{0,1}_account. Аргументы — amount_0_requested: u64, amount_1_requested: u64.
Изменено в 2026-09: новые конфиги больше не берут владельцев комиссий от подписывающей стороны. create_amm_config теперь записывает жёстко закодированный protocol_fee_owner::ID программы в owner и fund_fee_owner::ID в fund_owner. Ранее он копировал ключ подписывающего администратора в оба. На mainnet это уже те же ключи, хранящиеся на всех 21 существующих конфигах. Адреса находятся в reference/program-addresses.Принимаемые подписывающие стороны выше не изменились. Администратор может по-прежнему собирать с любого конфига, и существующие аккаунты AmmConfig не переписываются. Читайте owner / fund_owner с аккаунта вместо предположения о любом значении. Параметры UpdateAmmConfig 3 и 4 по-прежнему их ротируют.

CollectExcessLamports

Административный сбор lamports сверх минимума, освобождённого от ренты, на аккаунтах, которыми управляет CLMM. Он был добавлен в обновлении 2026-09 для возврата избыточного финансирования, которое снижение ренты SIMD-0437 оставляет на аккаунтах, созданных до каждого шага. Движется только избыток. Балансы токенов, данные аккаунта, владельцы, состояние пула и кривая цены остаются нетронутыми. Аккаунт, уже находящийся на минимуме, остаётся как есть, поэтому инструкция может быть безопасно переиспользована после каждого этапа развёртывания. Аргументы: нет. Аккаунты Область: один пул за вызов. CLMM не имеет полномочий vault на уровне программы. Vaults каждого пула принадлежат его собственному PoolState. Каждый исходный аккаунт программы токенов должен поэтому иметь pool_state в слоте 2 как свой полномочия: token_vault_0, token_vault_1 или один из reward vaults этого пула. Если вы передадите vault другого пула или аккаунт токена пользователя, проверка владельца программы токенов не пройдёт и вся инструкция откатится. Она не пропускается. Минты NFT позиций не могут быть собраны, потому что их полномочия mint отозваны при открытии позиции. Как обрабатывается каждый исходный аккаунт Программа делает два прохода по remaining_accounts: сначала каждый CPI программы токенов, затем прямые дебеты. Чередование двух прерывается ошибкой UnbalancedInstruction среды выполнения, поэтому порядок фиксирован в программе и вам не нужно самостоятельно сортировать список.
Pass 2 охватывает аккаунты, чья рента была оплачена пользователем. PersonalPositionState или LimitOrderState, переданные здесь, отказываются от своего избытка как любой другой аккаунт, принадлежащий CLMM. Он остаётся освобождённым от ренты и сохраняет свои данные. Когда он позже закрывается, владелец получает обратно всё, что аккаунт содержит в этот момент, что после сбора является текущим минимумом ренты.
Размер транзакции — это реальное ограничение на то, сколько источников поместится в один вызов. Это то же ограничение, что и сбор на стороне кошелька, описанный в solana-fundamentals/rent-and-reclaimable-rent. Частые ошибки:
  • NotApproved (6000): неправильный подписывающий.
  • LamportsCalculateError (6052): круговой оборот wSOL не дал нулевой результат.
  • Ошибка несовпадения владельца программы токенов: исходный токен не принадлежит pool_state.
  • InsufficientFunds: аккаунт, принадлежащий программе, содержит меньше, чем его собственный минимум ренты.
Нет SDK builder. @raydium-io/raydium-sdk-v2 не поставляет builder для этого пути администратора. Кодируйте вручную из IDL.

InitializeReward

Добавить новый поток вознаграждения в пул. Одновременно может быть активно до 3 потоков. Аргументы — одна структура, param: InitializeRewardParam:
Кодирование на проводе — это три поля подряд, поэтому ручно построенная инструкция не затронута — но клиент, управляемый IDL, должен передать один объект param вместо трёх позиционных аргументов. Аккаунты Предусловия
  • На пуле в настоящее время активно менее 3 потоков.
  • Финансист вносит total_emission = emissions_per_second × (end_time − open_time) стоимости токена вознаграждения в vault как часть этой инструкции.
  • Mint токена вознаграждения в белом списке согласно operation_state.

SetRewardParams

Продлить, пополнить или изменить скорость выпуска на существующем потоке вознаграждения. Обычно вызывается создателем пула или мультиподписью Raydium. Ограничения находятся в цепи: вы обычно можете продлить end_time или увеличить выпуск, но не сокращать их ретроактивно. Проверьте список владельцев operation_state.

UpdateRewardInfos

Чистая бухгалтерия — урегулирует reward_growth_global_x64 на текущее время путём умножения emissions_per_second × Δt / liquidity. Вызывается внутренне каждой инструкцией, касающейся ликвидности. Предоставляется как отдельная инструкция, потому что внешние акторы (UI, cranks) иногда хотят её запустить.

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

Нет отдельной инструкции сбора вознаграждения. Программа не предоставляет точку входа CollectReward, и опубликованный IDL её тоже не содержит.
Вознаграждения, причитающиеся позиции, выплачиваются DecreaseLiquidity / DecreaseLiquidityV2. Чтобы собрать без изменения позиции, вызовите её с liquidity = 0, amount_0_min = 0, amount_1_min = 0. Vaults вознаграждений и аккаунты получателей идут в remaining_accounts группами по три на активное вознаграждение в порядке reward_token_vault(W), recipient_token_account(W), reward_vault_mint. CollectRemainingRewards — это другое: это позволяет финансисту вознаграждения после end_time потока собрать токены, которые никогда не были распределены ни одной позиции.

Матрица изменения состояния

Что дальше

Источники: