Перейти к основному содержанию

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 включает:
  1. ComputeBudget::SetComputeUnitLimit — увеличение лимита CU по умолчанию.
  2. ComputeBudget::SetComputeUnitPrice — установка приоритетной комиссии.
  3. Опционально CreateAssociatedTokenAccount — создание выходного ATA, если у пользователя его нет.
  4. Raydium::SwapBaseInput — выполнение своппа.
  5. Опционально 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 Б
Заголовок message3 Б
Блокхеш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.50LP + протокол
Всего стоимость пользователя~$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 ёмкость — но она ловит ошибки перед оплатой.

Указатели

Источники: