Skip to main content
Эта страница переведена с помощью ИИ. За эталон принимается английская версия.Открыть английскую версию →
Эта страница — авторитетный справочник инструкций. Для кода, который фактически составляет эти инструкции, см. products/cpmm/code-demos. Для значений кодов ошибок см. reference/error-codes.Обновление программы 2026-09 переписало CPMM на Anchor 1.0.2 / Solana 3.1.10, добавило админ-инструкцию CollectExcessLamports, удалило жёстко закодированный список разрешённых минтов Token-2022 и изменило, что CreateAmmConfig записывает в protocol_owner / fund_owner. Ни одна пользовательская инструкция не изменила свои счёты, аргументы или математику. См. запись в журнале изменений от 2026-09-09.
Обе инструкции сбора комиссии создателя изменили свои списки счётов 2026-09-19. CollectCreatorFee получает creator_fee_share; CollectCreatorFeePermissionless получает amm_config и creator_fee_share. Обе добавлены в конец, после system_program, поэтому каждый счёт, который уже передаёт существующий клиент, сохраняет свой индекс — но новые счёты обязательны, поэтому транзакции, собранной для прежней схемы, не хватает счётов, и Anchor отклоняет её с AccountNotEnoughKeys (3005). Добавлены две админ-инструкции — CreateCreatorFeeShare и CloseCreatorFeeShare — и UpdateAmmConfig принимает новый param = 8. См. запись в журнале изменений от 2026-09-19.

Сводка инструкций

Битовая маска статуса: status каждого пула — это u8, где бит 0 = депозит отключен, бит 1 = вывод отключен, бит 2 = своп отключен (PoolStatusBitIndex { Deposit, Withdraw, Swap } в программе). Очищенный бит означает, что операция разрешена; установленный бит означает, что она приостановлена. UpdatePoolStatus принимает сырой u8 и перезаписывает существующее значение. Следующие разделы подробно рассматривают каждую инструкцию. Порядок счётов соответствует IDL CPMM; SDK и Rust-клиент в raydium-cp-swap/programs/cp-swap/src/instructions соответствуют этому порядку.

Initialize

Создать новый пул CPMM. Аргументы
Счёты (W = записываемый, S = подписывающий) * pool_state подписывает только на пути со случайной парой ключей; путь с каноническим PDA работает без подписи pool_state. Предусловия
  • Минты отсортированы (token_0_mint < token_1_mint по порядку байтов).
  • Ни один минт не использует расширение вне списка разрешений CPMM (TransferFeeConfig, MetadataPointer, TokenMetadata, InterestBearingConfig, ScaledUiAmount) — см. products/cpmm/accounts. Минт, для которого существует PDA SupportMintAssociated (seed [b"support_mint", mint]), пропускает проверку расширения — но вы должны добавить этот PDA в remaining_accounts. Программа сканирует только переданные вами счёты и никогда не загружает PDA самостоятельно, поэтому полагаться на реестр без предоставления счёта всё равно не удаётся с NotSupportMint (6007). Порядок не имеет значения (сопоставление по ключу); передайте одну запись на минт, которому нужен обход. Этот реестр — единственный обход с тех пор, как обновление 2026-09 удалило жёстко закодированный список четырёх минтов.
  • creator имеет по крайней мере init_amount_0 и init_amount_1 в соответствующих ATA.
  • amm_config.disable_create_pool == false.
Постусловия
  • pool_state.lp_supply = sqrt(init_amount_0 * init_amount_1) — полный квадратный корень. Создателю выдаётся lp_supply − 100; 100 заблокированных базовых единиц учитываются в lp_supply, но никогда не выпускаются.
  • Таким образом, lp_mint.supply == pool_state.lp_supply − 100 на протяжении всей жизни пула. Вся математика LP-доли (депозит, вывод) делится на lp_supply, поэтому используйте это поле и не подставляйте предложение минта в цепи. Возвращает InitLpAmountTooLess, если sqrt(...) < 100.
  • observation_state инициализируется; observation_index = 0 и pool_id = pool_state.key().
  • Лампорты create_pool_fee передаются от создателя получателю и синхронизируются как нативный SOL (это ATA wSOL).
  • Битовая маска статуса пула — 0 (депозит / вывод / своп все включены).
  • enable_creator_fee = false и creator_fee_on = BothToken. Initialize не поддерживает включение комиссии создателя — этот путь — InitializeWithPermission.
  • open_time увеличивается до block_timestamp + 1, если вызывающий передал значение <= block_timestamp. Своп отклоняется до open_time; депозиты и выводы работают немедленно.
Распространённые ошибки (полный список в reference/error-codes)
  • InvalidInput — минты не отсортированы или идентичны.
  • NotSupportMint — заблокировано расширение Token-2022.
  • ExceededSlippage — редко; если init_amount_0/1 приводят к нулевому LP из-за несовпадения десятичных знаков.

Deposit

Добавить ликвидность в оба токена пропорционально пулу. Аргументы
Счёты Математика
Два момента, которые стоит уточнить: база пропорции — это исключённое комиссии хранилище (vault_amount_without_fee, т.е. сырой баланс минус накопленные счётчики протокола, фонда и создателя), а не сырой баланс хранилища; и крышка проскальзывания проверяется против того, что плательщик фактически передаёт, после добавления комиссии передачи Token-2022, а не против валового движения хранилища. Нет изменения пропорциональности k — обе суммы и lp_supply масштабируются на один и тот же коэффициент. Постусловия
  • lp_supply += lp_token_amount.
  • vault_0 += needed_token_0 (за вычетом любой комиссии передачи Token-2022 на входе).
  • vault_1 += needed_token_1 (за вычетом любой комиссии передачи Token-2022 на входе).
Распространённые ошибки — ExceededSlippage, ZeroTradingTokens, InvalidStatus, если депозит приостановлен.

Withdraw

Сжечь LP-токены и получить оба базовых токена пропорционально. Аргументы
Счёты Первые 13 счётов идентичны Deposit, и lp_mint записываемый, потому что LP-токены сжигаются. Withdraw дополнительно принимает 14-й счёт, memo_program (ограничение address = memo::ID) — Deposit не принимает. Withdraw с 13 счётами не проходит десериализацию Anchor, поэтому LP не может выйти. Математика
Постусловия
  • lp_supply -= lp_token_amount.
  • Хранилища отправляют out_token_0 / out_token_1 (валовой; пользователь получает за вычетом любой комиссии передачи Token-2022).

SwapBaseInput

Своп с точным входом. Аргументы
Счёты Порядок вход → выход определяется направлением пользователя, а не каноническим token_0 / token_1 пула. Программа определяет, какое хранилище какое, сопоставляя минты. Математика — см. products/cpmm/math. Предусловия
  • open_time <= now.
  • pool_status разрешает своп.
  • Ни один минт не приостановлен или заморожен для этого органа власти.
  • amount_in > 0.
Распространённые ошибки
  • ExceededSlippage — amount_out < minimum_amount_out.
  • ZeroTradingTokens — сделка округляется до нуля.
  • NotApproved — пул приостановлен для своп через UpdatePoolStatus.
  • InvalidInput — минты не совпадают ни с одним из минтов хранилища пула.

SwapBaseOutput

Своп с точным выходом. Аргументы
Счёты — то же, что SwapBaseInput. Математика — обратная кривая с потолком, см. products/cpmm/math. Распространённые ошибки — ExceededSlippage (gross_in > max_amount_in), ZeroTradingTokens, InvalidInput, NotApproved.

CollectProtocolFee

Собрать накопленные комиссии протокола из хранилищ на целевой адрес протокола. Аргументы — нет. Счёты Эффект
Нет изменения эффективных балансов кривой (накопленные комиссии уже исключены). Распространённая ошибка — InvalidOwner (6001), если подписывающий ни amm_config.protocol_owner, ни админ программы. (На этом пути нет NotApproved.)

CollectFundFee

Та же форма, что CollectProtocolFee, но подписана amm_config.fund_owner — или, опять же, админом программы — и обнуляет счётчики fund_fees_*. Та же InvalidOwner при неправильном подписывающем.

CollectCreatorFee

Подписана pool_state.pool_creator. Она рассчитывает накопленную комиссию создателя и передаёт часть создателя на токен-счёты создателя. Аргументы — нет. Счёты Эффект
Доля протокола никогда не покидает хранилище здесь — она переклассифицируется как комиссия протокола и ждёт CollectProtocolFee. Оба счётчика уже исключены из представления кривой о хранилище, поэтому цена пула не движется. Полный вывод в products/cpmm/fees. Распространённые ошибки — NoFeeCollect, когда оба счётчика создателя равны нулю (проверяется перед разделением), InvalidInput (6003), если разрешённый share_rate превышает 1_000_000, MathOverflow (6011), если бронирование доли переполнит protocol_fees_token_*, и ошибка Anchor ConstraintSeeds, если creator_fee_share не является каноническим PDA.

CollectCreatorFeePermissionless

Кто угодно может запустить сбор комиссии создателя. Инструкция всегда отправляет часть создателя на канонические связанные токен-счёты, принадлежащие pool_state.pool_creator; вызывающий не может выбрать другого создателя или целевой адрес. Если какой-либо ATA отсутствует, плательщик финансирует его создание. Оригинальный CollectCreatorFee остаётся вызываемым, поэтому создатель, который хочет подписать для своего собственного сбора, всё ещё может. Аргументы — нет. Счёты
Два новых счёта добавлены в конец, после system_program, а не вставлены в середину списка. Каждый счёт от payer до system_program сохраняет позицию, которая была у него до обновления, поэтому разрыв получился чистым: транзакция, собранная для прежней схемы с четырнадцатью счётами, не читает хранилище как счёт конфига — она просто передаёт слишком мало счётов, и Anchor отклоняет её с AccountNotEnoughKeys (3005) до выполнения каких-либо ограничений. Счёты по-прежнему обязательны, поэтому добавьте оба и обновите IDL; пути совместимости со старой схемой нет.
Эффект — идентичен CollectCreatorFee выше: доля разрешается из creator_fee_share или amm_config, часть протокола учитывается в protocol_fees_token_{0,1}, часть создателя передаётся на ATA создателя, оба счётчика создателя обнуляются и recent_epoch обновляется. Возвращает NoFeeCollect, когда оба счётчика равны нулю.

UpdatePoolStatus

Приостановить или возобновить отдельные операции на пуле. Поле status — это битовая маска: Аргументы
Счёты Ключ админа — это публичный ключ, скомпилированный в программу (crate::admin::ID), а не орган власти обновления BPF — изменение его требует обновления программы. См. reference/program-addresses для значения и security/admin-and-multisig для того, кто его держит.

CreateAmmConfig

Создать новый уровень комиссий. Аргументы
Счёты Предусловия
  • Нет существующего AmmConfig с тем же index.
  • protocol_fee_rate + fund_fee_rate <= FEE_RATE_DENOMINATOR_VALUE.
Изменено в 2026-09: владельцы комиссий нового конфига больше не берутся из подписывающего. create_amm_config теперь записывает жёстко закодированный protocol_fee_owner::ID программы в protocol_owner и fund_fee_owner::ID в fund_owner, вместо копирования ключа подписывающего админа в оба. Адреса находятся в reference/program-addresses.Последствия: комиссии на вновь созданном AmmConfig попадают в выделенные кошельки комиссий, а не в кошелёк админа. Админ остаётся принятым подписывающим для сбора — CollectProtocolFee / CollectFundFee принимают amm_config.protocol_owner / fund_owner или crate::admin::ID — поэтому ничего не нужно ротировать для сбора; что изменилось, это только то, куда по умолчанию идут доходы. Существующие счёты AmmConfig не переписываются — всё, что на них хранится, всё ещё управляет, поэтому всегда читайте protocol_owner / fund_owner со счёта вместо предположения любого значения. Параметры UpdateAmmConfig 3 и 4 всё ещё их ротируют.

UpdateAmmConfig

Изменить ставки комиссий или владение на существующем AmmConfig. Принимает param: u8 (какое поле обновить) и value: u64. Полная таблица диспетчеризации:
  • param = 0 → trade_fee_rate (утверждает trade_fee_rate + creator_fee_rate < 1_000_000)
  • param = 1 → protocol_fee_rate (утверждает ≤ 1_000_000 и + fund_fee_rate ≤ 1_000_000)
  • param = 2 → fund_fee_rate (утверждает ≤ 1_000_000 и + protocol_fee_rate ≤ 1_000_000)
  • param = 3 → protocol_owner. Новый ключ не в value: добавьте его как remaining_accounts[0] (только для чтения в порядке). Он не должен быть ключом по умолчанию, и пропуск счёта паникует на unwrap().
  • param = 4 → fund_owner. Тот же механизм, что 3.
  • param = 5 → create_pool_fee
  • param = 6 → disable_create_pool (любое ненулевое value отключает)
  • param = 7 → creator_fee_rate (утверждает creator_fee_rate + trade_fee_rate < 1_000_000)
  • param = 8 → creator_fee_share_rate (утверждает ≤ 1_000_000). Добавлено 2026-09-19. Доля протокола по умолчанию комиссии создателя на этом уровне; см. products/cpmm/fees. Это не связано с protocol_fee_rate, который разделяет комиссию торговли.
Любой другой param возвращает InvalidInput. Изменения подписаны админом и влияют на каждый пул, привязанный к этому AmmConfig при следующем своп. Нет миграции; пулы просто читают новые значения.

CreateCreatorFeeShare

Установить пользовательскую долю протокола комиссии создателя для одной пары (creator, amm_config), переопределяя AmmConfig.creator_fee_share_rate для каждого пула, который этот создатель владеет на этом уровне комиссий. Добавлено в обновление creator-fee-share 2026-09-19. Аргументы
Счёты Предусловия
  • share_rate <= 1_000_000, иначе InvalidInput (6003).
  • PDA не должен уже существовать — Anchor init не проходит при втором вызове для одной пары. Чтобы изменить ставку, закройте счёт и создайте его снова.
Постусловия
  • creator_fee_share хранит bump, creator, amm_config и share_rate.
  • Каждый последующий CollectCreatorFee / CollectCreatorFeePermissionless на пуле, созданном creator под amm_config, разрешает долю из этого счёта вместо конфига.
Создатель пула не является стороной этой инструкции и не подписывает её. Ставка читается во время сбора, поэтому переопределение, созданное после того, как комиссии уже накопились, применяется к этому накопленному балансу тоже.

CloseCreatorFeeShare

Удалить переопределение. Пара возвращается к AmmConfig.creator_fee_share_rate. Аргументы — нет. Счёты Постусловия
  • Счёт закрыт и его лампорты идут на owner.
  • Сборы для этой пары разрешают долю из amm_config.creator_fee_share_rate снова — что 0, если админ не установил UpdateAmmConfig param 8.

CollectExcessLamports

Админ-сбор лампортов, сидящих выше минимума для освобождения от аренды на счётах, контролируемых CPMM. Добавлено в обновление 2026-09, чтобы протокол мог вернуть избыточное финансирование, которое SIMD-0437 rent reduction оставляет на счётах, созданных до каждого шага. Движется только избыток. Балансы токенов, данные счёта, владельцы, состояние пула и кривая не трогаются, и инструкция — это no-op для счёта, уже находящегося на минимуме — поэтому безопасно переиспользовать после каждого развёртывания шага. Аргументы — нет. Счёты
Исправление порядка, 2026-09-19. Программа теперь делает два прохода по remaining_accounts — каждый CPI токен-программы сначала, затем прямые дебеты CPMM-управляемых PDA. Чередование их прерывалось с UnbalancedInstruction рантайма (“сумма балансов счётов до и после инструкции не совпадают”) всякий раз, когда PDA дебетовался перед CPI, потому что ожидающие изменения лампортов вызывающего только сбрасываются в счёта, которые CPI фактически несёт. Вызывающие не должны группировать или сортировать список сами.
Как каждый исходный счёт обрабатывается Программа диспетчеризует по owner исходного счёта: Потому что он принимает неограниченный список remaining_accounts, размер транзакции — это реальный лимит — то же ограничение, что и сбор со стороны кошелька, описанный в solana-fundamentals/rent-and-reclaimable-rent. Распространённые ошибки — InvalidOwner (6001, неправильный подписывающий), LamportsCalculateError (6015, wSOL round-trip не нетировал до нуля) и InsufficientFunds из пути, управляемого программой, когда счёт держит меньше, чем его собственный минимум аренды. Нет SDK-построителя. @raydium-io/raydium-sdk-v2 не поставляет построитель для этой инструкции, и ни raydium-sdk-V2-demo репо — это админ-путь. Кодируйте вручную, как сбор со стороны кошелька в solana-fundamentals/rent-and-reclaimable-rent делает для инструкции токен-программы.

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

Куда дальше

  • products/cpmm/code-demos — запускаемые примеры TypeScript для вышеперечисленного.
  • reference/error-codes — полная таблица ошибок Anchor.
  • products/cpmm/fees — модель накопления комиссий, которую инструкции Collect*Fee осушают.
Источники: