Эта страница переведена с помощью ИИ. За эталон принимается английская версия.Открыть английскую версию →
Зачем нужны тики
Ликвидность CLMM сосредоточена в диапазонах цен. Чтобы сделать диапазоны управляемыми в цепи, цены квантуются в целые числа тики, где каждый тик — это постоянный множитель предыдущего: Один тик соответствует движению цены на 0,01%, или примерно 1 базисный пункт. Соответствие:MIN_TICK и MAX_TICK выбраны так, чтобы sqrt_price_x64 помещался в u128 на обоих концах. Каждый пул гарантирует, что tick_lower >= MIN_TICK и tick_upper <= MAX_TICK. На практике веб-интерфейс ограничивает диапазон чем-то намного более узким, чтобы предотвратить блокировку ликвидности в недостижимых тиках.
Интервал тиков
AmmConfig пула фиксирует интервал тиков — единственные тики, которые позиция может использовать в качестве конечных точек. Если tick_spacing = 60, допустимы только тики …, −120, −60, 0, 60, 120, …. Попытка открыть позицию с конечной точкой 31 вернёт ошибку InvalidTickIndex.
Распространённые опубликованные интервалы:
Чем грубее интервал, тем меньше массивов тиков нужно инициализировать, тем дешевле открыть широкую позицию и тем менее чёткая граница цены. Волатильные пары обычно находятся в уровнях с интервалом 120; стейблкойны — в уровнях с интервалом 1.
Массивы тиков
Пул не хранит состояние для каждого тика в отдельных аккаунтах. Вместо этогоTICK_ARRAY_SIZE соседних тиков (60 в текущем Raydium CLMM) упакованы в один TickArrayState. Первый тик массива — это его start_tick_index, и он охватывает ровно TICK_ARRAY_SIZE * tick_spacing целых единиц тиков.
Для tick_spacing = 60 и TICK_ARRAY_SIZE = 60:
- Каждый массив тиков охватывает
60 × 60 = 3600целых тиков. start_tick_index— это кратное 3600:…, -7200, -3600, 0, 3600, 7200, ….
t = 2040 при tick_spacing = 60 находится в массиве тиков с start_tick_index = 0. Конечная точка позиции t = 4200 находится в массиве с start_tick_index = 3600.
Когда создаётся массив
Массив тиков ленивый: первая позиция, которая ссылается на любой тик внутри него, инициализирует массив, оплачивая ренту. Свопы не инициализируют массивы тиков — они пропускают неинициализированные массивы, используя битовую карту. Поток открытия позиции SDK проверяет выбранный диапазон, вычисляет список массивов тиков, которые он затрагивает, и добавляет инструкцииinit_tick_array в ту же транзакцию, что и OpenPosition, если какие-то отсутствуют.
Массивы тиков не закрываются
После инициализации массива тиков он сохраняется на протяжении всей жизни пула. Программа не предоставляет способ закрыть массив тиков, даже после того, какinitialized_tick_count вернётся к нулю. Нет возврата ренты для массивов тиков; рента, оплаченная первой позицией, которая коснулась массива, навсегда заблокирована в этом аккаунте. Это намеренный компромисс: повторное использование существующего массива тиков бесплатно для каждой последующей позиции, поэтому активно торгуемый пул платит стоимость ренты только один раз за слот (pool, start_tick_index) независимо от оборота.
Битовая карта
Поиск «следующего инициализированного тика слева/справа от текущего тика» должен быть быстрым — свопы могут пересекать много тиков. Пул хранит битовую карту с одним битом на массив тиков встроенной вPoolState для диапазона ±1024 массивов вокруг тика 0. За пределами этого диапазона (позиции полного диапазона, экзотические установки) TickArrayBitmapExtension предоставляет переполнение.
Свопы проходят по битовой карте: lowest_set_bit_above(tick_current_array_index) даёт следующий массив с инициализированным тиком на стороне, в которую движется свопа. Внутри этого массива аналогичное сканирование битов находит следующий инициализированный тик.
liquidity_gross и liquidity_net
Каждый инициализированный тик хранит два значения ликвидности:
liquidity_gross— суммаLпо всем позициям, которые ссылаются на этот тик как на конечную точку. Когдаliquidity_grossдостигает нуля, тик становится неинициализированным и может быть удалён из битовой карты.liquidity_net— подписанное изменение ликвидности уровня пула при пересечении этого тика в восходящем направлении (слева направо в пространстве тиков). Если этот тик — нижняя граница позиции размеромL, он вносит+L; если это верхняя граница этой позиции, он вносит−L.
- Позиция A:
tick_lower = -120,tick_upper = 0, ликвидностьL_A = 100. - Позиция B:
tick_lower = -60,tick_upper = 60, ликвидностьL_B = 50.
Ликвидность уровня пула для разных значений
tick_current:
tick_current = -180:liquidity = 0(перед любой позицией)tick_current = -90:liquidity = 100(только внутри A)tick_current = -30:liquidity = 150(внутри A и B)tick_current = 30:liquidity = 50(только внутри B)tick_current = 90:liquidity = 0(после обеих)
liquidity_net (возможно, отрицательное) к PoolState.liquidity. Это точный механизм Uniswap v3.
Позиции как NFT
Позиция Raydium CLMM — это NFT. Открытие позиции создаёт совершенно новый минт с предложением 1 в кошельке вызывающей стороны, и полномочия минта принадлежат программе CLMM. Программа привязывает владение позицией к тому, кто держит баланс в ATA этого минта во время CPI. Последствия:- Позиции обычно передаваемы. Кошелёк может продать или раздать позицию, передав NFT. Новый владелец может затем вызвать
CollectRewards,IncreaseLiquidityи т. д. Исключение — позиция, заморозенная по пути ограниченного издателя ниже. - Позиции адресуемы вне CLMM. Маркетплейсы и кошельки отображают позиции как другие NFT. SDK устанавливает разумные
name/symbolв метаданных минта. - PDA позиции получена из минта NFT. Вы можете найти
PersonalPositionStateбез знания того, кто его в данный момент держит.
Позиции ограниченного издателя
Каждый минт NFT позиции, созданный после обновления 2026-08, записывает свой CLMMpool_state как полномочие заморозки. Это не означает, что каждая новая позиция заморожена. Для обычных пулов и каждой несовпадающей позиции аккаунт токена NFT остаётся разморозенным и передаваемым. PDA пула не может подписывать вне программы CLMM, и CLMM не предоставляет инструкцию общего назначения для заморозки.
Заморозка требует обоих этих условий:
- Позиция открыта через
OpenPositionV2илиOpenPositionWithToken22Nft. - По крайней мере один минт хранилища пула имеет полномочие заморозки из списка ограниченных издателей, жёстко закодированного в программе.
OpenPosition V1 не применяет этот фильтр. См. reference/program-addresses для текущего списка.
Замороженная позиция:
- Не может передать свой NFT на другой аккаунт токена.
- Не может изменить владельца аккаунта токена NFT.
- Может по-прежнему увеличивать или уменьшать ликвидность и собирать комиссии или награды, когда подписывает записанный владелец.
- Может по-прежнему закрываться.
ClosePositionиспользует PDA пула для разморозки аккаунта NFT, затем сжигает NFT и закрывает аккаунты позиции в одной инструкции.
Позиции Token-2022
CLMM может создать NFT позиции под классическим SPL Token черезOpenPositionV2 или под Token-2022 через OpenPositionWithToken22Nft. Оба пути V2 проверяют минты хранилища пула и применяют то же правило заморозки ограниченного издателя. OpenPosition V1 — это устаревший путь классического токена и не может обслуживать пул с минтами хранилища Token-2022. Совместимость кошельков и маркетплейсов различается; пользовательский интерфейс Raydium отслеживает обе программы NFT.
Правила допустимого диапазона
При открытии позиции программа гарантирует:tick_lower < tick_upper.tick_lower % tick_spacing == 0иtick_upper % tick_spacing == 0.MIN_TICK <= tick_lowerиtick_upper <= MAX_TICK.- Вызывающая сторона предоставила массивы тиков, содержащие
tick_lowerиtick_upper— либо уже инициализированные, либо черезinit_tick_arrayв той же транзакции. - Аккаунт расширения битовой карты, если эта позиция расширяется в диапазон расширения.
InvalidTickIndex, NotApproved или InsufficientLiquidity в зависимости от того, какое ограничение. См. reference/error-codes.
«В диапазоне» против «вне диапазона»
Позиция в диапазоне, когдаtick_lower <= tick_current < tick_upper. Только позиции в диапазоне вносят вклад в PoolState.liquidity и поэтому только они получают комиссии за свопы.
Позиция вне диапазона:
- Держит 100% одного токена (того, мимо которого прошёл её диапазон). В частности, если
tick_current < tick_lower, позиция держит только token1 (она уже была «продана» движением цены); еслиtick_current >= tick_upper, она держит только token0. - Не получает комиссии за свопы.
- Продолжает накапливать награды, если потоки вознаграждений пула выдают вознаграждения вне диапазона ликвидности — но поведение Raydium по умолчанию — «выдавать только в диапазоне», соответствуя соглашению Uniswap v3. См.
products/clmm/fees.
Распространённые ошибки интеграции
- Конечные точки вне интервала. Код, который вычисляет тик из целевой цены, должен привязать его к кратному
tick_spacingперед передачей вOpenPosition. Помощники SDK (TickUtils.getTickWithPriceAndTickspacing) делают это; самодельная математика часто нет. - Отсутствующие массивы тиков. Открытие широкой позиции может потребовать инициализации нескольких массивов тиков; забывание передать их как записываемые аккаунты вернёт ошибку. SDK
openPositionFromBaseвозвращает список для вас. - Устаревший тик после свопа.
tick_currentможет пересечь много тиков в одном свопе. Если ваш UX показывает «текущий тик» из одного вызова RPC, а затем открывает позицию в более позднем, относительная позиция к живой цене может быть смещена на десятки тиков. Повторно получите данные прямо перед подписанием. - NFT позиций с дополнительными метаданными. Если вы создаёте кошелёк, который распознаёт позиции Raydium, используйте PDA позиции / данные программы, а не жёстко закодированное поле метаданных. Новые минты позиций используют PDA пула как полномочия минта и заморозки при создании; полномочия минта удаляются после создания единственного NFT.
- Предположение, что каждая позиция передаваема. Прочитайте состояние
isFrozenаккаунта токена NFT перед отображением действий передачи, маркетплейса, условного депозита или Burn & Earn.
Что дальше
- Математика — пошаговое объяснение свопа и вывод роста комиссий, в котором участвуют границы тиков.
- Аккаунты — макеты
TickArrayStateиPositionState. - Комиссии и награды — как нахождение в диапазоне управляет накоплением комиссий.
algorithms/clmm-math— общий вывод формул сосредоточенной ликвидности.
raydium-io/raydium-clmm— модулиtick_array,tick,position- Белая книга “Uniswap v3 Core”, §6 (тики), §7 (рост комиссий)

