Documentation Index
Fetch the complete documentation index at: https://docs.raydium.io/llms.txt
Use this file to discover all available pages before exploring further.
Эта страница переведена с помощью ИИ. За эталон принимается английская версия.Открыть английскую версию →
PDA (program-derived addresses) и CPI (cross-program invocation) — два примитива, на которых построен Raydium. PDA позволяет программе владеть детерминированными адресами без приватных ключей — так работают органы управления пулами и хранилища токенов. CPI позволяет одной программе вызвать другую — так Raydium обменивает токены через программу SPL Token и так интеграторы используют Raydium в своих потоках. Оба механизма важно понимать перед тем, как читать исходный код Raydium.
PDA: адреса без ключей
Program-Derived Address — это публичный ключ, который:- не лежит на кривой ed25519 (у него нет приватного ключа).
- детерминировано вычисляется из ID программы и набора seeds.
- может быть подписан только той программой, которая его вывела, через
invoke_signed.
Вычисление
PDA вычисляется путём хеширования ID программы с seeds и последующего поиска byte-значения “bump”, которое выводит результат за пределы кривой. Первый bump (обычно начиная с 255 и убывая), который даёт off-curve адрес, становится каноническим bump.u64 значения в виде little-endian байтов. Соглашение Raydium — человеко-читаемый префикс, за которым следуют уникальные идентификаторы.
Паттерны PDA в Raydium
Часто используемые PDA в программах Raydium:| PDA | Seeds | Программа |
|---|---|---|
| AMM authority (AMM v4) | [b"amm authority"] + bump | AMM v4 |
| Pool state (CPMM) | [b"pool", amm_config, mint_a, mint_b] | CPMM |
| Pool vault (CPMM) | [b"pool_vault", pool, mint] | CPMM |
| Authority (CPMM) | [b"vault_and_lp_mint_auth_seed"] | CPMM |
| Pool state (CLMM) | [b"pool", amm_config, mint_0, mint_1] | CLMM |
| Tick array (CLMM) | [b"tick_array", pool, start_tick_index] | CLMM |
| Observation (CLMM) | [b"observation", pool] | CLMM |
| Personal position (CLMM) | [b"position", position_nft_mint] | CLMM |
| Farm state (Farm v6) | [b"pool_farm_state", farm_id] | Farm v6 |
| User ledger (Farm v6) | [b"user_ledger", farm, user] | Farm v6 |
Канонический bump
Хотя в принципе может быть несколько bumps, дающих off-curve адреса, программы Raydium всегда используют канонический bump (найденный декрементированием от 255). Он сохраняется в данных учётной записи PDA, чтобы в последующих транзакциях его можно было передать и избежать дорогостоящего цикла вычисления:CPI: вызов других программ
Cross-Program Invocation позволяет программе вызвать инструкцию другой программы встроенно в одной транзакции. Raydium интенсивно использует CPI:- Инструкции swap вызывают программу SPL Token для переноса токенов.
- CLMM вызывает Metaplex для минтинга NFT позиции.
- Создание пула вызывает System Program для выделения учётных записей.
- Farm v6 вызывает SPL Token для перевода награды.
integration-guides/cpi-integration.
invoke vs invoke_signed
Среда выполнения Solana предоставляет два примитива CPI:invoke: вызов другой программы; вызванная программа наследует подписантов из внешней транзакции.invoke_signed: вызов другой программы от имени PDA; среда выполнения проверяет seeds PDA и авторизует подпись.
invoke_signed — это волшебство, которое позволяет программам владеть учётными записями без управления приватными ключами.
Пример: Raydium переводит токены из хранилища пула
Хранилище пула — это Token Account, органом управления которого является PDA программы пула. Чтобы перевести токены во время swap, программа пула должна подписать как этот PDA:invoke_signed вызывается программой CPMM, проверяет, что vault_and_lp_mint_auth_seed + bump при хешировании с ID программы CPMM производит адрес pool_authority, и разрешает подпись органа управления на передачу токена. Никаких приватных ключей не требуется.
Пример: интегратор вызывает Raydium CPMM
Программа интегратора (например, escrow) может вызватьswap_base_input Raydium через CPI:
integration-guides/cpi-integration для полного примера escrow.
Ограничение глубины CPI
Solana ограничивает глубину CPI 4 уровнями. Инструкция верхнего уровня транзакции считается глубиной 0; каждый вызов CPI увеличивает глубину на 1. Практическое следствие: собственный swap Raydium уже использует 1-2 уровня CPI (Raydium → SPL Token). Интегратор, вызывающий Raydium, использует 2. Если этого интегратора вызывает другой интегратор, это 3. 4-й уровень — предел. Большинство композиций легко остаются под этим ограничением, но глубокое вложение (aggregator → router → Raydium → hook) может его превысить. Проектируйте плоские структуры, а не глубокие.Оставшиеся учётные записи
Когда инструкция Raydium нуждается в переменном числе учётных записей (например, CLMM swap пересекает неизвестное число tick arrays), дополнительные учётные записи передаются как remaining accounts — добавляются к списку фиксированных учётных записей, интерпретируются по позиции.SwapV2 CPMM использует remaining accounts для дополнительных требуемых учётных записей программ transfer-hook. Клиенты получают нужные учётные записи и добавляют их:
Подводные камни PDA
Неправильные seeds → неправильный адрес
Ошибка, когда seeds находятся в неправильном порядке, неправильной кодировке, или включают/исключают дополнительный байт, молча производит другой PDA. Транзакция завершается неоднозначно (программа пытается прочитать учётную запись, которая не существует). Всегда unit-тестируйте вычисление seeds против известных эталонных значений.Несохранённый bump
Если вы пересчитываете bump на каждой транзакции, вы платите за цикл вычисления. Сохраняйте канонический bump в данных PDA и читайте его оттуда.Путаница между каноническим и неканоническим bump
Неканонические bumps (если кто-то найдёт один, дающий off-curve) разрешеныinvoke_signed, но отклоняются программами Raydium через assert_eq!(bump, canonical_bump). Если кто-то попытается заявить PDA с неканоническим bump, транзакция завершится с ошибкой.
Передача PDA как подписантов, когда вы не владеющая программа
Только программа, чей ID находится в вычислении PDA, может вызватьinvoke_signed с его seeds. Если вы попытаетесь, среда выполнения отклонит.
Подводные камни CPI
Забывчивость пробросить remaining_accounts
Если ваша внешняя инструкция передаёт transfer-hook учётные записи в remaining_accounts, но CPI в Raydium их не пробрасывает, Raydium завершается с ошибкой, потому что не может найти hook учётные записи. Всегда включайте with_remaining_accounts в CPI, которые их требуют.
Несоответствие флагов writable
Учётная запись, которую внешняя инструкция помечает как writable, также должна быть writable в вызове CPI, если вызванная программа намерена её писать. Несоответствие → отклонение средой выполнения.Не учитывание rent
CPI в программу, которая создаёт учётную запись (например, создание ATA), требует, чтобы плательщик имел достаточно SOL для rent. Неудачные проверки rent выглядят как неясные ошибки.Рабочий пример: вычисление PDA Raydium CPMM
getPoolInfoFromRpc({ poolId }) — вычисляет ассоциированные PDA без туда-сюда запросов.
Ссылки
solana-fundamentals/account-model— как PDA вписываются в модель учётных записей.solana-fundamentals/programs-and-anchor— помощники Anchor для объявления PDA.integration-guides/cpi-integration— построение интеграций, которые вызывают CPI в Raydium.sdk-api/rust-cpi— типы Rust CPI Raydium.


