Skip to main content
Эта страница переведена с помощью ИИ. За эталон принимается английская версия.Открыть английскую версию →
ID программы и seeds PDA для CPMM перечислены в reference/program-addresses. На этой странице основное внимание уделяется назначению каждого аккаунта и инвариантам, которые он поддерживает, а не жёстко закодированным адресам.

Шесть аккаунтов пула CPMM

Каждый пул CPMM полностью описывается шестью адресами, производными от программы (PDA), под программой CPMM, плюс один общий аккаунт AmmConfig, на который он ссылается. Имея два mint’а, вы можете детерминированно вывести всё остальное без обращения к сети. И общая конфигурация:

Вывод пула из двух mint’ов

Всегда сортируйте mint’ы перед выводом PDA пула. Seed хеширует два mint’а в порядке байтов, а не в порядке пользователя. Два пула с (A, B) и (B, A) столкнулись бы в цепи — сортировка — это то, как программа делает отображение каноническим.
ID пула не всегда является каноническим PDA. Initialize принимает произвольную пару ключей подписанта как pool_state в дополнение к PDA выше. Если переданный аккаунт не совпадает с каноническим PDA, программа требует, чтобы он был подписантом — то есть создатель передаёт свежую пару ключей, которую они подписывают. Это защита от фронт-раннинга: любая третья сторона, спешащая захватить канонический PDA, может быть обойдена легитимным создателем, использующим вместо этого случайную пару ключей. Нижестоящие PDA (lpMint, vault0, vault1, observation) по-прежнему выводятся из poolState.key(), поэтому они остаются уникальными для любого использованного адреса. При индексировании пулов всегда обнаруживайте ID пула из состояния в цепи (например, аккаунты PoolState под программой CPMM), а не путём вывода канонического PDA — последний пропустит пулы со случайными парами ключей.

Макеты аккаунтов

Полные определения на Rust находятся в исходном коде raydium-cp-swap. Поля ниже — это те, которые вы будете читать при интеграции.

PoolState

Что на самом деле читать:
  • lp_supply — внутреннее зеркало пула от общего предложения LP mint’а. Используйте его для математики LP-доли; значение должно совпадать с предложением mint’а в цепи, но чтение его из PoolState избегает дополнительной выборки аккаунта.
  • protocol_fees_token{0,1}, fund_fees_token{0,1}начисленные комиссии, ещё не собранные. Они не влияют на цену swap’а; они находятся в хранилищах до вызова CollectProtocolFee / CollectFundFee.
  • status — битовая маска, контролирующая, разрешены ли Swap, Deposit, Withdraw. Обновляется администратором через UpdatePoolStatus. SDK проверяет это перед построением транзакции; если вы CPI’ите напрямую, проверьте это сами.
  • token0_program / token1_program — программа токена для CPI в каждое хранилище. Одна может быть классическим SPL Token, а другая Token-2022; они независимы.
  • open_time — временная метка Unix. Swap’ы до этого времени не удаются. Депозиты разрешены до open_time, чтобы пул мог быть заполнен.
  • creator_fee_on / enable_creator_fee — вместе контролируют, активна ли опциональная комиссия создателя для этого пула и с какой стороны swap’а она собирается. enable_creator_fee == false полностью обнуляет путь комиссии создателя. Когда включено, creator_fee_on выбирает: 0 = взять комиссию из любого токена, который является входом swap’а (BothToken); 1 = взять комиссию только из token_0 (пропустить на swap’ах token_1 → token_0); 2 = взять комиссию только из token_1. Устанавливается при создании пула через InitializeWithPermission; не может измениться позже.
  • creator_fees_token_{0,1} — начисленные комиссии создателя, собираемые через CollectCreatorFee или CollectCreatorFeePermissionless. Оба пути обнуляют полные счётчики; путь без разрешения фиксирует получателей на канонические ATA pool_creator.

AmmConfig

Три вещи, на которые нужно обратить внимание:
  1. trade_fee_rate и creator_fee_rate — доли объёма, обе обозначены в единицах 1/1_000_000. 2500 означает 0.25% от объёма торговли. protocol_fee_rate и fund_fee_rate — доли торговой комиссии (не объёма), в том же знаменателе 1/1_000_000. Комиссия создателя не является долей торговой комиссии — это её собственная независимая ставка. Полная арифметика находится в products/cpmm/fees.
  2. index — это u16, поэтому seed хеш использует 2 байта big-endian. Ошибка на один в порядке байтов — частая ошибка интеграции.
  3. AmmConfig неизменяем на уровне пула. Пул указывает на один AmmConfig при создании и никогда не переключается. Изменения комиссий распространяются, потому что пул читает конфиг при каждом swap’е — но пул не может быть перемещён между уровнями комиссий.
Заметка о комиссиях создателя: сама ставка (creator_fee_rate) находится на AmmConfig и общая для уровня комиссии. Взимает ли конкретный пул её на самом деле (enable_creator_fee) и с какой стороны swap’а она приземляется (creator_fee_on) находятся на PoolState. Комиссия создателя независима от торговой комиссии — это её собственная ставка, начисляемая на её собственные счётчики (creator_fees_token_{0,1}), и никогда не уменьшает доли LP / протокола / фонда торговой комиссии. Сбор осуществляется через CollectCreatorFee или ограниченный по назначению CollectCreatorFeePermissionless. Полная механика в products/cpmm/fees.

Permission

Небольшой аккаунт контроля доступа, используемый InitializeWithPermission. Программа CPMM поддерживает путь создания пула с разрешением, чтобы другие программы (например, LaunchLab при переводе токена в CPMM) могли доказать, что они имеют право создать пул против данного AmmConfig.
Permission PDA создаётся через CreatePermissionPda либо администратором CPMM, либо выделенным создателем authority Permission-PDA. Только администратор CPMM может отозвать его через ClosePermissionPda. Конечные пользователи не взаимодействуют с этим аккаунтом напрямую — это сантехника для кросс-программных потоков. См. security/admin-and-multisig для границы роли и reference/program-addresses для канонических адресов.

Хранилища и Token-2022

vault0 и vault1 принадлежат PDA authority CPMM, и их владелец программы токена (token_program) — это либо SPL Token, либо Token-2022, определяется при создании пула программой mint’а. Пул прозрачно обрабатывает оба случая — вы передаёте правильный ID программы токена для каждой стороны в аккаунты инструкции Swap / Deposit / Withdraw. CPMM применяет строгий список разрешённых расширений при создании пула (is_supported_mint в utils/token.rs). Mint Token-2022 может быть использован в пуле CPMM только если каждое расширение, которое он несёт, находится в этом списке:
  • TransferFeeConfig. Применяется mint’ом при каждом переводе. Пул находится на принимающей стороне для депозитов SwapBaseInput и на отправляющей стороне для снятий. Программа вычисляет чистую сумму, попадающую в хранилище, и устанавливает кривую соответственно. См. algorithms/token-2022-transfer-fees.
  • MetadataPointer и TokenMetadata. Стандартные метаданные на mint’е. Никакого влияния на математику swap’а.
  • InterestBearingConfig. UI сумма mint’а начисляет проценты. Хранилище хранит сырые суммы; кривая работает только с сырыми суммами. UI’ы, которые показывают APR, должны вызывать помощники Token-2022 для отображения UI суммы.
  • ScaledUiAmount. Расширение масштабирования UI-отображения. Такая же обработка, как InterestBearingConfig — кривая использует сырые суммы.
Любое другое расширение — PermanentDelegate, TransferHook, DefaultAccountState, NonTransferable, ConfidentialTransfer, Group/GroupMember, MintCloseAuthority и т.д. — вызывает отклонение Initialize с NotSupportMint. Исключение — небольшой жёстко закодированный список разрешённых mint’ов в программе (несколько конкретных pubkey’ей), который обходит проверку расширений; он используется для подключения конкретных mint’ов в индивидуальном порядке. Проверенный список расширений и список разрешённых mint’ов находятся в исходном коде CP-Swap в programs/cp-swap/src/utils/token.rs и могут измениться при будущих обновлениях программы.

Observation

Аккаунт observation — это кольцевой буфер записей ObservationState, каждая хранит block_timestamp и кумулятивную цену. При каждом swap’е программа добавляет новое наблюдение, если прошло достаточно времени с последнего. TWAP’ы вычисляются путём чтения двух наблюдений и деления Δcumulative / Δtime.
Кольцевой буфер рассчитан на 100 наблюдений. Каждое наблюдение — 40 байт, поэтому массив один — 4,000 байт; полный PDA ObservationState — около 4,100 байт после окружающих полей и дискриминатора. Два правила для потребителей:
  • Не используйте одно наблюдение как цену. Это кумулятив, а не спотовая цена. Используйте два из них для вычисления TWAP.
  • Выбирайте наблюдения по крайней мере на один блок друг от друга. Swap’ы в одном блоке могут не создать новое наблюдение; чтение подряд может вернуть одну и ту же запись.
Больше математики в products/clmm/accounts.

Жизненный цикл аккаунта

Пулы CPMM и их PDA никогда не закрываются. Даже при нулевой ликвидности poolState остаётся. Это намеренно: повторное заполнение того же пула позже сохраняет его исторический буфер наблюдений и его вывод PDA остаётся стабильным.

Что читать где

  • Списки аккаунтов инструкций (какие из вышеперечисленных доступны для записи/подписи для каждой инструкции): products/cpmm/instructions.
  • Семантика начисления комиссий: products/cpmm/fees.
  • Математика swap’а / правило обновления наблюдений: products/cpmm/math.
  • Канонические seeds / ID программ: reference/program-addresses.
Источники: