Пакетные платежи

Транзакция Solana — это контейнер, который содержит одну или несколько инструкций. Каждая инструкция — это операция: перевод токенов, создание аккаунта, вызов программы. Сеть выполняет все инструкции в транзакции последовательно и атомарно: либо каждая инструкция выполняется успешно, либо вся транзакция откатывается и считается неудачной.

Это означает, что вы можете объединить несколько переводов в одну транзакцию. Вместо того чтобы отправлять три отдельные транзакции для оплаты трем получателям, вы отправляете одну транзакцию с тремя инструкциями перевода. Это быстрее (одно подтверждение вместо трёх) и дешевле (одна базовая комиссия вместо трёх). Вот наглядный пример того, как платежи (на изображении они называются «дропами») объединяются в одну транзакцию, а для обработки большого количества платежей отправляется несколько транзакций.

Диаграмма пакетных платежейДиаграмма пакетных платежей

Источник: QuickNode — Как отправлять массовые транзакции в Solana

Больше информации о транзакциях и инструкциях вы найдете в разделах Транзакции и Инструкции.

В этом пошаговом руководстве показано, как загрузить несколько инструкций перевода в одну транзакцию для пакетных платежей.

Объединение инструкций в одну транзакцию

Транзакция Solana может содержать несколько переводов разным получателям. Вы подписываете один раз, платите одну комиссию за транзакцию, и все переводы выполняются одновременно. Если какой-либо перевод не удастся, вся транзакция будет отклонена.

См. раздел Как работают платежи в Solana для ознакомления с основными понятиями.

Для объединения нескольких переводов необходимо создать каждую инструкцию отдельно, а затем собрать их в одну транзакцию.

Далее приведены основные этапы процесса. Полный рабочий код смотрите в разделе Демо.

Получение адресов token account

Сначала получите адреса Associated Token Account (ATA) для отправителя и каждого получателя. ATA — это детерминированные адреса, основанные на кошельке и mint.

Batch Payments
const [senderAta] = await findAssociatedTokenPda({
mint: mint.address,
owner: sender.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipient1Ata] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient1.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipient2Ata] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient2.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

Создание инструкций для перевода

Создайте отдельную инструкцию перевода для каждого получателя. В каждой инструкции указываются:

  • адрес исходного token account
  • адрес целевого token account
  • authority (адрес владельца исходного token account)
  • сумма в базовых единицах (с учётом знаков после запятой у mint)
Batch Payments
const [senderAta] = await findAssociatedTokenPda({
mint: mint.address,
owner: sender.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipient1Ata] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient1.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipient2Ata] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient2.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const transfer1Instruction = getTransferInstruction({
source: senderAta,
destination: recipient1Ata,
authority: sender.address,
amount: 250_000n
});
const transfer2Instruction = getTransferInstruction({
source: senderAta,
destination: recipient2Ata,
authority: sender.address,
amount: 250_000n
});

Отправка одной транзакцией

Добавьте все инструкции перевода в одну транзакцию. Это позволит выполнить все переводы атомарно: либо все переводы проходят успешно, либо вся транзакция откатывается.

Проверка балансов

После пакетного перевода проверьте балансы токенов для всех участников с помощью splToken хелпера.

Batch Payments
const [senderAta] = await findAssociatedTokenPda({
mint: mint.address,
owner: sender.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipient1Ata] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient1.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipient2Ata] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient2.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const transfer1Instruction = getTransferInstruction({
source: senderAta,
destination: recipient1Ata,
authority: sender.address,
amount: 250_000n
});
const transfer2Instruction = getTransferInstruction({
source: senderAta,
destination: recipient2Ata,
authority: sender.address,
amount: 250_000n
});
const signature = await client.transaction.prepareAndSend({
authority: sender,
instructions: [transfer1Instruction, transfer2Instruction],
version: 0
});
const splToken = client.splToken({
mint: mint.address,
tokenProgram: "auto"
});
const senderBalance = await splToken.fetchBalance(sender.address);
const recipient1Balance = await splToken.fetchBalance(recipient1.address);
const recipient2Balance = await splToken.fetchBalance(recipient2.address);

Получение адресов token account

Сначала получите адреса Associated Token Account (ATA) для отправителя и каждого получателя. ATA — это детерминированные адреса, основанные на кошельке и mint.

Создание инструкций для перевода

Создайте отдельную инструкцию перевода для каждого получателя. В каждой инструкции указываются:

  • адрес исходного token account
  • адрес целевого token account
  • authority (адрес владельца исходного token account)
  • сумма в базовых единицах (с учётом знаков после запятой у mint)

Отправка одной транзакцией

Добавьте все инструкции перевода в одну транзакцию. Это позволит выполнить все переводы атомарно: либо все переводы проходят успешно, либо вся транзакция откатывается.

Проверка балансов

После пакетного перевода проверьте балансы токенов для всех участников с помощью splToken хелпера.

Batch Payments
const [senderAta] = await findAssociatedTokenPda({
mint: mint.address,
owner: sender.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipient1Ata] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient1.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipient2Ata] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient2.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

Демонстрация

Demo
// Generate keypairs for sender and two recipients
const sender = (await generateKeypair()).signer;
const recipient1 = (await generateKeypair()).signer;
const recipient2 = (await generateKeypair()).signer;
console.log("Sender Address:", sender.address);
console.log("Recipient 1 Address:", recipient1.address);
console.log("Recipient 2 Address:", recipient2.address);
// Demo Setup: Create client, mint account, token accounts, and fund with initial tokens
const { client, mint } = await demoSetup(sender, recipient1, recipient2);
console.log("\nMint Address:", mint.address);
// Derive the Associated Token Accounts addresses (ATAs) for sender and recipients
const [senderAta] = await findAssociatedTokenPda({
mint: mint.address,
owner: sender.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipient1Ata] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient1.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipient2Ata] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient2.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
console.log("Sender Token Account:", senderAta.toString());
console.log("Recipient 1 Token Account:", recipient1Ata.toString());
console.log("Recipient 2 Token Account:", recipient2Ata.toString());
// =============================================================================
// Batch Token Payment Demo
// =============================================================================
// Create instructions to transfer tokens from sender to both recipients
// Transferring 250,000 base units = 0.25 tokens (with 6 decimals) to each
const transfer1Instruction = getTransferInstruction({
source: senderAta,
destination: recipient1Ata,
authority: sender.address,
amount: 250_000n // 0.25 tokens
});
const transfer2Instruction = getTransferInstruction({
source: senderAta,
destination: recipient2Ata,
authority: sender.address,
amount: 250_000n // 0.25 tokens
});
// Prepare and send both transfers in a single transaction using @solana/client
const signature = await client.transaction.prepareAndSend({
authority: sender,
instructions: [transfer1Instruction, transfer2Instruction],
version: 0
});
console.log("\n=== Batch Token Payment Complete ===");
console.log("Transaction Signature:", signature.toString());
// Fetch final token account balances using @solana/client SPL token helper
const splToken = client.splToken({
mint: mint.address,
tokenProgram: "auto"
});
const senderBalance = await splToken.fetchBalance(sender.address);
const recipient1Balance = await splToken.fetchBalance(recipient1.address);
const recipient2Balance = await splToken.fetchBalance(recipient2.address);
console.log("\nSender Token Account Balance:", senderBalance);
console.log("Recipient 1 Token Account Balance:", recipient1Balance);
console.log("Recipient 2 Token Account Balance:", recipient2Balance);
// =============================================================================
// Demo Setup Helper Function
// =============================================================================
Console
Click to execute the code.

Масштабирование с помощью планирования транзакций

Одна транзакция имеет ограничения по размеру — примерно 1232 байта. Для крупных пакетных операций (например, начисление зарплаты сотням сотрудников, массовые airdrop) вы превысите этот лимит и потребуется разбивать работу на несколько транзакций.

Хотя вы можете реализовать собственную логику распределения транзакций, пакет @solana/instruction-plans (часть Solana Kit) решает эту задачу на двух уровнях:

Планы инструкций определяют ваши операции и ограничения по их порядку выполнения:

  • Последовательные — инструкции, которые должны выполняться по порядку
  • Параллельные — инструкции, которые могут выполняться в любом порядке
  • Неделимые — инструкции, которые должны оставаться вместе в одной транзакции

Планы транзакций формируются на основе планов инструкций. Планировщик интеллектуально группирует инструкции в транзакции оптимального размера с учетом ваших ограничений по порядку. Полученный план транзакций может быть:

  • Выполнен — подписан и отправлен в сеть, при этом параллельные транзакции отправляются одновременно
  • Симулирован — тестовый запуск в сети для проверки перед отправкой
  • Сериализован — скомпилирован в base64 для внешних сервисов подписи или мультипользовательских сценариев

Такой двухуровневый подход позволяет вам мыслить в терминах операций ("перевести Алисе, затем перевести Бобу"), а библиотека берет на себя механику определения размера транзакций, их упаковки и параллельного выполнения.

Is this page helpful?

Содержание

Редактировать страницу

Управляется

© 2026 Фонд Solana.
Все права защищены.
Подключиться