Thanh toán hàng loạt

Một giao dịch Solana là một container chứa một hoặc nhiều lệnh. Mỗi lệnh là một thao tác—chuyển token, tạo tài khoản, gọi chương trình. Mạng lưới thực thi tất cả các lệnh trong một giao dịch theo thứ tự và nguyên tử: hoặc mọi lệnh đều thành công, hoặc toàn bộ giao dịch thất bại và được hoàn tác.

Điều này có nghĩa là bạn có thể đóng gói nhiều lần chuyển vào một giao dịch duy nhất. Thay vì gửi ba giao dịch riêng biệt để thanh toán cho ba người nhận, bạn gửi một giao dịch với ba lệnh chuyển. Cách này nhanh hơn (một xác nhận thay vì ba) và rẻ hơn (một phí cơ bản thay vì ba). Dưới đây là một ví dụ minh họa về cách các khoản thanh toán (được gọi là "drops" trong hình ảnh này) được đóng gói thành một giao dịch duy nhất và nhiều giao dịch được gửi để xử lý lô lớn hơn.

Sơ đồ thanh toán hàng loạtSơ đồ thanh toán hàng loạt

Nguồn: QuickNode - How to Send Bulk Transactions on Solana

Để biết thêm thông tin về giao dịch và lệnh, xem hướng dẫn Giao dịchLệnh.

Hướng dẫn dưới đây cho thấy cách tải nhiều lệnh chuyển vào một giao dịch duy nhất để thanh toán hàng loạt.

Đóng gói lệnh vào một giao dịch duy nhất

Một giao dịch Solana có thể chứa nhiều lần chuyển đến các người nhận khác nhau. Bạn ký một lần, trả một phí giao dịch, và tất cả các lần chuyển được thanh toán cùng nhau. Nếu bất kỳ lần chuyển nào thất bại, toàn bộ giao dịch sẽ bị từ chối.

Xem Cách thanh toán hoạt động trên Solana để hiểu các khái niệm thanh toán cốt lõi.

Đóng gói nhiều lần chuyển yêu cầu xây dựng từng lệnh riêng biệt, sau đó kết hợp chúng vào một giao dịch duy nhất.

Các bước dưới đây cho thấy quy trình cốt lõi. Xem Demo để có mã hoàn chỉnh có thể chạy được.

Tạo token account

Đầu tiên, tạo địa chỉ associated token account (ATA) cho người gửi và từng người nhận. ATA là địa chỉ xác định dựa trên ví và 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
});

Tạo lệnh chuyển

Tạo một lệnh chuyển riêng biệt cho từng người nhận. Mỗi lệnh chỉ định:

  • địa chỉ token account nguồn
  • địa chỉ token account đích
  • quyền hạn (địa chỉ chủ sở hữu token account nguồn)
  • số lượng theo đơn vị cơ bản (điều chỉnh theo số thập phân của 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
});

Gửi dưới dạng giao dịch đơn

Thêm tất cả lệnh chuyển vào một giao dịch duy nhất. Điều này thực thi tất cả các lần chuyển một cách nguyên tử, hoặc tất cả đều thành công hoặc toàn bộ giao dịch thất bại.

Xác minh số dư

Sau khi chuyển hàng loạt, xác minh số dư token cho tất cả các bên bằng cách sử dụng trình trợ giúp 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);

Tạo token account

Đầu tiên, tạo địa chỉ associated token account (ATA) cho người gửi và từng người nhận. ATA là địa chỉ xác định dựa trên ví và mint.

Tạo lệnh chuyển

Tạo một lệnh chuyển riêng biệt cho từng người nhận. Mỗi lệnh chỉ định:

  • địa chỉ token account nguồn
  • địa chỉ token account đích
  • quyền hạn (địa chỉ chủ sở hữu token account nguồn)
  • số lượng theo đơn vị cơ bản (điều chỉnh theo số thập phân của mint)

Gửi dưới dạng giao dịch đơn

Thêm tất cả lệnh chuyển vào một giao dịch duy nhất. Điều này thực thi tất cả các lần chuyển một cách nguyên tử, hoặc tất cả đều thành công hoặc toàn bộ giao dịch thất bại.

Xác minh số dư

Sau khi chuyển hàng loạt, xác minh số dư token cho tất cả các bên bằng cách sử dụng trình trợ giúp 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

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.

Mở rộng quy mô với lập kế hoạch giao dịch

Một giao dịch đơn có giới hạn kích thước—khoảng 1232 byte. Đối với các hoạt động hàng loạt lớn (bảng lương cho hàng trăm nhân viên, airdrop hàng loạt), bạn sẽ vượt quá giới hạn này và cần chia công việc thành nhiều giao dịch.

Mặc dù bạn có thể tự tạo logic phân phối giao dịch của riêng mình, gói @solana/instruction-plans (một phần của Solana Kit) xử lý điều này ở hai cấp độ:

Kế hoạch chỉ thị xác định các thao tác của bạn và các ràng buộc về thứ tự của chúng:

  • Tuần tự — các chỉ thị phải thực thi theo thứ tự
  • Song song — các chỉ thị có thể thực thi theo bất kỳ thứ tự nào
  • Không thể chia — các chỉ thị phải ở cùng nhau trong cùng một giao dịch

Kế hoạch giao dịch được tạo ra từ kế hoạch chỉ thị. Trình lập kế hoạch thông minh đóng gói các chỉ thị vào các giao dịch có kích thước tối ưu, tuân thủ các ràng buộc về thứ tự của bạn. Kế hoạch giao dịch kết quả sau đó có thể được:

  • Thực thi — ký và gửi đến mạng, với các giao dịch song song được gửi đồng thời
  • Mô phỏng — chạy thử nghiệm trên mạng để xác minh trước khi gửi
  • Tuần tự hóa — biên dịch sang base64 cho các dịch vụ ký bên ngoài hoặc quy trình làm việc đa bên

Cách tiếp cận hai cấp này cho phép bạn suy nghĩ theo các thao tác ("chuyển cho Alice, sau đó chuyển cho Bob") trong khi thư viện xử lý các cơ chế về kích thước giao dịch, đóng gói và thực thi song song.

Is this page helpful?

Mục lục

Chỉnh sửa trang

Quản lý bởi

© 2026 Solana Foundation.
Đã đăng ký bản quyền.
Kết nối