Skip to main content
Эта страница переведена с помощью ИИ. За эталон принимается английская версия.Открыть английскую версию →
На этой странице описаны структура и назначение каждого аккаунта. Семена (seeds) канонические и перечислены в reference/program-addresses. Пул CLMM требует больше аккаунтов, чем пул CPMM, потому что ликвидность хранится разреженно по диапазону тиков; понимание этой разреженности — основная часть этой страницы.

Инвентарь аккаунтов

Активный пул CLMM описывается следующими семействами аккаунтов. Все принадлежат программе CLMM, кроме двух минтов и их хранилищ.

PoolState

Живое состояние пула, читается при каждом свопе и каждом изменении позиции.
Поля, которые вы действительно будете использовать:
  • sqrt_price_x64 и tick_current — состояние цены пула. Обновляются вместе при каждом свопе. tick_current — это пол от log_{1.0001}(price).
  • liquidity — это активная ликвидность — сумма значений L для всех позиций, диапазон которых содержит tick_current. Изменяется каждый раз, когда своп пересекает тик, и каждый раз, когда позиция открывается/закрывается/изменяется.
  • fee_growth_global_{0,1}_x64 — кумулятивные комиссии, заработанные на единицу ликвидности по всей истории пула. Позиции читают это, чтобы вычислить, что им причитается.
  • tick_spacing заблокирован на AmmConfig при инициализации и никогда не меняется. Он определяет, какие индексы тиков могут быть конечными точками позиции.
  • tick_array_bitmap — это встроенная битовая карта, охватывающая часто используемый диапазон тиков около спотовой цены. Для пулов, позиции которых простираются далеко, отслеживание переполнения находится в отдельном TickArrayBitmapExtension.
  • fee_on фиксируется при создании пула. 0 (FromInput) воспроизводит классическое поведение Uniswap-V3. 1 и 2 направляют комиссию своп на одну сторону книги — см. products/clmm/fees для компромиссов.
  • seed_index — это [0, 0] для каждого пула, созданного через CreatePool / CreateCustomizablePool (один канонический пул на пару). Ненулевое значение означает, что пул был создан через CreatePermissionedPool, и индекс является частью семян PDA пула, позволяя нескольким пулам сосуществовать для одной и той же (config, mint0, mint1). Чтобы повторно вывести адрес такого пула, вы должны знать его seed_index.
  • dynamic_fee_info содержит состояние волатильности для надбавки динамической комиссии. Когда включено, каждый своп пересчитывает dynamic_fee_component поверх AmmConfig.trade_fee_rate. Структура документирована под DynamicFeeInfo ниже; пулы без динамической комиссии оставляют всю структуру нулевой.

AmmConfig

Начиная с обновления 2026-09, CreateAmmConfig записывает жестко закодированный protocol_fee_owner::ID программы в owner и fund_fee_owner::ID в fund_owner. До этого он копировал ключ подписавшего администратора в оба. Существующие конфиги сохраняют то, на что они были созданы или повернуты, поэтому читайте оба поля с аккаунта. Параметры UpdateAmmConfig 3 / 4 по-прежнему их поворачивают. Адреса находятся в reference/program-addresses. Типичный опубликованный набор уровней комиссий CLMM (подтвердите против GET https://api-v3.raydium.io/main/clmm-config): protocol_fee_rate и fund_fee_rate — это доли торговой комиссии; то же соглашение, что и CPMM. См. products/clmm/fees.

TickArrayState

CLMM не хранит одну запись на тик. Это были бы миллиарды аккаунтов. Вместо этого он группирует TICK_ARRAY_SIZE соседних инициализированных или нет тиков (обычно 60 или 88 в зависимости от версии программы) в TickArrayState, который лениво создается при первом использовании.
Четыре поля лимитного ордера равны нулю на любом тике, который никогда не использовался для лимитного ордера. Когда ордера открываются на тике, программа отслеживает их как последовательность когорт:
  • order_phase — это id когорты. Он увеличивается каждый раз, когда когорта переходит из “полностью невыполненной” в “частично выполненную”.
  • orders_amount — это общее количество входного токена текущей (новейшей) когорты.
  • part_filled_orders_remaining отслеживает предыдущую когорту, которая в настоящее время заполняется текущими свопами.
  • unfilled_ratio_x64 — это множитель Q64.64, переносимый на когорту: когда своп заполняет X% когорты, коэффициент умножается на (1 − X). Каждый открытый ордер хранит свой собственный снимок (order_phase, unfilled_ratio_x64) во время открытия, поэтому математика расчета сводится к сравнению снимков.
Правила:
  • Конечный тик позиции t должен удовлетворять t % tick_spacing == 0. Программа отклоняет позиции вне интервала.
  • Массив тика расположен в floor(t / (TICK_ARRAY_SIZE * tick_spacing)) * (TICK_ARRAY_SIZE * tick_spacing).
  • Массив тиков инициализируется лениво: первая позиция или своп, который трогает неинициализированный массив, создает его, оплачивая ренту.
  • Массив тиков никогда не закрывается программой. После выделения он сохраняется на протяжении всей жизни пула, даже после того, как каждый тик внутри него вернется к liquidity_gross == 0. Последующие позиции и свопы переиспользуют существующий аккаунт без дополнительной ренты. Нет пути очистки ClosePosition для массивов тиков.

TickArrayBitmapExtension

PoolState.tick_array_bitmap (встроенная) охватывает диапазон “близко к спот” — ±512 массивов тиков (TICK_ARRAY_BITMAP_SIZE = 512; поле [u64; 16] — это 1,024 бита, разделенные поровну между отрицательными и положительными начальными индексами, поэтому индексы массива −512 … +511). За пределами этого диапазона (для экстремальных значений тиков) программа поддерживает аккаунт расширения:
Если диапазон вашей позиции “нормальный”, вы никогда не думаете об аккаунте расширения. Позиции полного диапазона (например, (MIN_TICK, MAX_TICK)) требуют его; SDK разрешает его для вас.

Позиции

Позиция CLMM — это пакет из трех аккаунтов плюс минт:

Position NFT mint

Минт SPL Token или Token-2022 с предложением 1. NFT позиции в кошельке владельца — это ATA, содержащий этот единственный токен. Программа привязывает авторизацию к текущему держателю баланса ATA NFT, а не к Pubkey, хранящемуся в состоянии. Новые минты NFT позиции устанавливают pool_state как их freeze authority перед минтингом единственного токена и удалением mint authority. Установка freeze authority не замораживает сам аккаунт NFT. Аккаунт остается разморожен и передаваем, если не выполнены оба условия: вызывающий использует OpenPositionV2 или OpenPositionWithToken22Nft, и freeze authority хотя бы одного базового минта хранилища появляется в списке restricted-issuer CLMM. Только тогда CLMM замораживает аккаунт NFT после минтинга. Это не изменяет ни один байт PersonalPositionState или PoolState.

PersonalPositionState

По одному на открытую позицию. Привязан к минту NFT.

ProtocolPositionState (устарело)

Более старые выпуски CLMM хранили агрегированное бухгалтерское учета на (pool, tick_lower, tick_upper) в PDA ProtocolPositionState. Более новые выпуски больше не создают и не читают этот аккаунт. Слот по-прежнему появляется в списках аккаунтов OpenPosition / IncreaseLiquidity / DecreaseLiquidity как UncheckedAccount для совместимости ABI, но программа не пишет в него. Существующие аккаунты в цепи — это остатки; администратор может вызвать CloseProtocolPosition, чтобы вернуть ренту для них.Агрегированное бухгалтерское учета диапазона теперь выводится непосредственно из двух конечных тиков (liquidity_gross, liquidity_net и fee_growth_outside_* / reward_growths_outside_x64 на тик) в TickArrayState. Формула fee-growth-inside fee_growth_inside = global − outside_lower − outside_upper продолжает работать без аккаунта агрегированной позиции.

Observation

Буфер наблюдений CLMM хранит кумулятивный тик, а не кумулятивную цену. Внешние потребители вычисляют геометрическую среднюю цену за интервал из (tick_cumulative[t1] − tick_cumulative[t0]) / (t1 − t0), а затем price = 1.0001 ** tick. См. algorithms/clmm-math.

DynamicFeeConfig и DynamicFeeInfo

Параметры динамической комиссии находятся в двух местах. Переиспользуемый шаблон — DynamicFeeConfig — управляется администратором и общий для пулов, которые подключаются. Состояние выполнения на пул — DynamicFeeInfo — встроено в PoolState и обновляется каждым свопом.

DynamicFeeConfig

Семя PDA: ["dynamic_fee_config", index.to_be_bytes()]. Создается через create_dynamic_fee_config (с ограничением администратора) и изменяется через update_dynamic_fee_config. Пул, созданный с enable_dynamic_fee = true, снимает пять параметров калибровки конфига (filter_period, decay_period, reduction_factor, dynamic_fee_control, max_volatility_accumulator) в свой собственный DynamicFeeInfo при создании; более поздние правки DynamicFeeConfig не влияют ретроактивно на существующие пулы.

DynamicFeeInfo (встроено в PoolState)

Нижние четыре поля — это состояние; верхние пять — это калибровка, скопированная из DynamicFeeConfig. Математика комиссии и правила затухания документированы под products/clmm/math и products/clmm/fees. Константы, используемые формулой:

LimitOrderState

Один аккаунт на открытый лимитный ордер.
Жизненный цикл:
  1. Открыть — пользователь вызывает open_limit_order, депонирует total_amount входного токена, ордер привязан к когорте TickState.
  2. (опционально) Увеличить / Уменьшить — increase_limit_order добавляет к total_amount; decrease_limit_order возвращает невыполненные токены (и любой выполненный выход до этого момента).
  3. Расчет — когда когорта полностью или частично заполнена, владелец или оперативный хранитель вызывает settle_limit_order, чтобы отправить выходные токены на ATA владельца.
  4. Закрыть — как только unfilled_amount == 0, аккаунт закрываем. Рента всегда возвращается owner.
Семя PDA: [owner.as_ref(), limit_order_nonce.key().as_ref(), limit_order_nonce.order_nonce.to_be_bytes().as_ref()]. Ордер PDA уникален на (owner, nonce_index, order_nonce).

LimitOrderNonce

Счетчик на (wallet, nonce_index), который позволяет одному пользователю запускать несколько параллельных конвейеров лимитных ордеров без столкновения на PDA.
Семя PDA: [user_wallet.as_ref(), &[nonce_index]]. Большинство клиентов используют nonce_index = 0 и позволяют order_nonce нести кардинальность.

Permission

Аккаунт возможности, чье существование является грантом: если PDA Permission выведена для данного authority, этот authority может вызвать CreatePermissionedPool. Он не хранит ничего, кроме authority, для которого он был создан.
Семя PDA: ["permission", authority.as_ref()]. Создается администратором через CreatePermissionPda и удаляется через ClosePermissionPda (рента возвращается вызывающему). Обе инструкции администратора принимают либо программный admin, либо выделенный ключ permission_pda_admin. Закрытие PDA отзывает грант — authority больше не может создавать дополнительные пулы, но пулы, которые он уже создал, не затронуты.

Вывод ключевых аккаунтов

Точные строки семян всегда должны быть перепроверены против IDL в цепи и reference/program-addresses.

Краткая справка по жизненному циклу

Аккаунты TickArrayState никогда не закрываются программой — они сохраняются на протяжении всей жизни пула. После инициализации массива тиков он остается в цепи, даже когда каждый тик внутри него вернется к liquidity_gross == 0. Переиспользование существующего массива тиков бесплатно; только первая позиция, которая трогает никогда не инициализированный массив, платит его ренту.

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

Источники: