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.
Транзакция Solana — это список инструкций, исполняемых атомарно. Понимание структуры транзакции — инструкции, аккаунты, подписанты, бюджет вычислений — необходимо для разработки, отладки или оптимизации чего-либо с Raydium. На этой странице рассматривается эта структура, лимиты, которые её ограничивают, и то, как две категории комиссий (сетевые комиссии Solana, комиссии протокола Raydium) складываются в реальном своре.
Анатомия транзакции
Транзакция Solana состоит из трёх основных компонентов:
- Message: упорядоченный список инструкций, аккаунты, на которые они ссылаются, и свежий блокхеш.
- Signatures: по одной для каждого подписанта, подтверждающие авторизацию транзакции.
- Recent blockhash: доказывает, что транзакция свежая; транзакции с устаревшими блокхешами (старше 150 слотов) отклоняются.
Инструкции
Инструкция задаёт:
program_id — программу для вызова.
accounts — аккаунты (и их флаги записываемости/подписанта), которые может задействовать программа.
data — непрозрачные байты, которые программа интерпретирует.
Одна транзакция может содержать несколько инструкций. Они исполняются по порядку; если любая терпит неудачу, все предыдущие инструкции откатываются (атомарно).
Типичная транзакция своппа Raydium включает:
ComputeBudget::SetComputeUnitLimit — увеличение лимита CU по умолчанию.
ComputeBudget::SetComputeUnitPrice — установка приоритетной комиссии.
- Опционально
CreateAssociatedTokenAccount — создание выходного ATA, если у пользователя его нет.
Raydium::SwapBaseInput — выполнение своппа.
- Опционально
CloseAccount — закрытие обёрнутого SOL ATA.
SDK автоматически упаковывает эти инструкции через raydium.trade.swap().
Аккаунты в транзакциях
Каждый аккаунт, задействованный любой инструкцией в транзакции, должен быть указан в ключах аккаунтов транзакции. Каждый аккаунт помечается:
- Подписант / не подписант: должен ли владелец аккаунта подписать транзакцию?
- Записываемый / только для чтения: может ли транзакция изменять аккаунт?
Runtime переполняет эти флаги: программа, пытающаяся писать в не записываемый аккаунт, терпит неудачу, и runtime отклоняет транзакции с отсутствующими требуемыми подписантами.
Для своппа CPMM список аккаунтов содержит примерно 13 записей (см. solana-fundamentals/account-model). Своппы CLMM с несколькими пересечениями tick array могут иметь 20+.
Лимит размера транзакции
Solana ограничивает транзакции 1232 байтами включая подписи, message и заголовки. Это наиболее распространённое препятствие для сложных транзакций — CLMM Raydium с много-хоп маршрутизацией регулярно упирается в этот лимит.
Разбор типичного своппа Raydium размером ~1000 байт:
| Компонент | Размер |
|---|
| Подпись | 64 Б |
| Количество подписей | 1 Б |
| Заголовок message | 3 Б |
| Блокхеш | 32 Б |
| Ключи аккаунтов (13 × 32 Б) | 416 Б |
| Инструкции (4 × ~100-150 Б) | 400–600 Б |
| Всего | ~900–1100 Б |
Таблицы поиска адресов (ALTs)
ALT позволяют транзакции ссылаться на аккаунты через однобайтовый индекс в опубликованную таблицу вместо полного 32-байтового публичного ключа. Это резко сжимает транзакцию:
- Транзакция со ссылками на 20 аккаунтов напрямую: ~640 Б публичных ключей.
- Та же транзакция с использованием ALT: ~20 Б индексов + ссылки на ALT.
Raydium ведёт ALT для путей своппов CPMM/CLMM на mainnet. SDK использует их автоматически. Агрегаторы, строящие много-хоп маршруты, полагаются на них широко.
import { VersionedTransaction } from "@solana/web3.js";
// SDK строит v0 (versioned) tx со ссылками на ALT
const { transaction } = await raydium.trade.swap({ /* ... */ });
// transaction это VersionedTransaction, не legacy Transaction.
Бюджет вычислений
Каждая транзакция имеет бюджет compute unit (CU). Его превышение прерывает исполнение и терпит неудачу.
- По умолчанию: 200 000 CU за транзакцию.
- Максимум: 1 400 000 CU за транзакцию (повышено через
ComputeBudget::SetComputeUnitLimit).
- Лимит на блок: 48M CU на блок (уровень протокола).
Типичное потребление CU Raydium (см. integration-guides/priority-fee-tuning для полной таблицы):
| Инструкция | CU |
|---|
| Своп CPMM | ~140 000 |
| Своп CLMM (без пересечений tick) | ~170 000 |
| Своп CLMM (4 пересечения tick) | ~320 000 |
| Стейкинг Farm v6 | ~130 000 |
| Создание пула CPMM | ~250 000 |
Всегда устанавливайте явный лимит CU через ComputeBudget; иначе вы получите 200k по умолчанию, что слишком мало для большинства инструкций Raydium.
import { ComputeBudgetProgram } from "@solana/web3.js";
tx.add(
ComputeBudgetProgram.setComputeUnitLimit({ units: 300_000 }),
);
Если установить лимит CU слишком низким, транзакция терпит неудачу при достижении лимита; слишком высокий — рискуете быть понижены в приоритете при перегрузке (и, в зависимости от модели ценообразования, вы платите за вычисления, которые никогда не использовали).
Приоритетные комиссии
Помимо базовой комиссии транзакции (5000 lamports за подпись), валидаторы всё чаще приоритизируют транзакции, платящие приоритетные комиссии: подсказку за CU в микролампортах.
priority_fee = compute_unit_price (micro-lamports) × compute_unit_limit
Пример: 10 000 µL/CU × 300 000 CU = 3 000 000 µL = 0.003 SOL.
Приоритетные комиссии локальны — они влияют только на упорядочивание внутри блока; они не улучшают ваш шанс быть включённым против не включённого. Установка разумной приоритетной комиссии необходима при перегрузке.
tx.add(
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 10_000 }),
);
См. integration-guides/priority-fee-tuning о том, как размер это динамически.
Лимиты количества инструкций и аккаунтов
Помимо общего лимита в 1232 байта:
- Макс аккаунтов за транзакцию: 128.
- Макс аккаунтов за инструкцию (CPI): 64.
- Макс инструкций за транзакцию: жёсткого лимита нет, ограничен только лимитом размера.
- Макс глубина CPI: 4 (программа может вызвать другую, которая может вызвать другую, 4 уровня глубины).
Своппы CLMM Raydium, пересекающие несколько tick array, могут упираться в лимит аккаунтов — один своп задействует пул, входные/выходные хранилища, входные/выходные ATA, несколько tick array, возможно дополнительные аккаунты программы transfer-hook, плюс обязательные ссылки на compute budget / system / token program. Конструкции, компонующие Raydium через CPI (например, auto-compounder), должны учитывать это.
Категории комиссий в своппе Raydium
Пользовательская транзакция своппа платит комиссии в двух категориях:
Сетевые комиссии Solana
Выплачиваются валидаторам в SOL.
- Базовая комиссия подписи: 5000 lamports за подпись. Почти всегда 1 подпись = 0.000005 SOL.
- Приоритетная комиссия: CU-price × CU-limit в микролампортах. Варьируется с перегрузкой; см.
integration-guides/priority-fee-tuning.
Эти комиссии идут валидаторам, не связаны с Raydium и взимаются даже за неудачные транзакции (кроме некоторых граничных случаев приоритетной комиссии).
Комиссии протокола Raydium
Вычитаются из суммы своппа.
- Комиссия своппа: процент от входа (CPMM 0.25% типично, CLMM 0.01%–1% на уровень). Делится между LP и протоколом. См.
ray/protocol-fees.
Эти комиссии являются внутренней для бухгалтерии Raydium — пользователь видит их как меньший выходной объём, чем произвёл бы пул с нулевой комиссией.
Пример: $1000 USDC → SOL через CPMM 0.25% уровень
| Категория комиссии | Сумма | Идёт |
|---|
| Базовая комиссия подписи | 0.000005 SOL (~$0.0007) | Валидатор |
| Приоритетная комиссия (10k µL × 300k CU) | 0.003 SOL (~$0.45) | Валидатор |
| Комиссия своппа CPMM (0.25%) | $2.50 | LP + протокол |
| Всего стоимость пользователя | ~$2.95 | |
Slippage (ценовой удар + движение рынка) не является комиссией, но влияет на же итоговую строку.
Versioned транзакции
Solana имеет два формата транзакций:
- Legacy: оригинальный формат, нет поддержки ALT.
- v0 (Versioned): поддерживает ALT, расширяемый для будущих версий.
Весь современный инструмент Solana использует v0. SDK Raydium выдаёт v0 транзакции по умолчанию.
// Построение v0 tx напрямую
import { VersionedTransaction, TransactionMessage } from "@solana/web3.js";
const msg = new TransactionMessage({
payerKey: owner.publicKey,
recentBlockhash: blockhash,
instructions: [ /* ... */ ],
}).compileToV0Message([lookupTableAccount]);
const tx = new VersionedTransaction(msg);
tx.sign([owner]);
Свежесть блокхеша
Транзакция должна включать блокхеш из последних ~150 слотов (~60 секунд). За пределами этого окна валидаторы её отклоняют.
Для retry циклов получайте свежий блокхеш при каждом retry:
async function sendWithRetry(tx, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
tx.message.recentBlockhash = blockhash;
tx.sign([owner]);
try {
return await connection.sendRawTransaction(tx.serialize());
} catch (e) {
if (i === maxRetries - 1) throw e;
}
}
}
См. integration-guides/priority-fee-tuning для полного retry-с-возрастающими-комиссиями паттерна.
Параллельное исполнение
Solana исполняет не конфликтующие транзакции параллельно на многоядерных валидаторах. Две транзакции конфликтуют, если обе записывают один и тот же аккаунт.
Последствия для Raydium:
- Два своппа на одном пуле не могут исполняться параллельно — оба записывают состояние пула.
- Своп на Пуле A и своп на Пуле B исполняются параллельно, если списки аккаунтов не перекрываются.
- Только-для-чтения транзакция никогда не блокирует писателя на том же аккаунте (только-для-чтения конкурирует с собой, но не с записями).
Это почему Solana может поддерживать высокий DEX throughput несмотря на сериализацию одного пула.
Уровни подтверждения транзакции
При отправке транзакции вы выбираете уровень подтверждения:
| Уровень | Ожидание | Финальность |
|---|
processed | ~400 мс | Не финализирована; может откатиться |
confirmed | ~1 с | Большинство голосовало |
finalized | ~13 с | Большинство укоренилось |
Для UX своппа confirmed стандарт. Для операций с большой ценностью (создание пула, пополнение вознаграждения), finalized безопаснее.
await connection.sendAndConfirmTransaction(tx, [owner], {
commitment: "confirmed",
});
Симуляция
Solana поддерживает симуляцию транзакции перед отправкой:
const sim = await connection.simulateTransaction(tx);
console.log(sim.value.logs);
console.log(sim.value.unitsConsumed);
SDK Raydium использует симуляцию внутри при вычислении getBestSwapInfo для проверки, что выбранный маршрут действительно работает. Симуляция не бесплатна — она потребляет RPC ёмкость — но она ловит ошибки перед оплатой.
Указатели
Источники: