Funds at risk: This guide sends real TON. Test on testnet first. Double-check recipient addresses — blockchain transactions cannot be reversed.
Objective
By the end of this guide, you will:- Send multiple transfers (up to 254) in a single transaction
- Understand the two-transaction flow for batch transfers
- Know how to calculate compute fees for the internal transaction
Prerequisites
- Completed wallet creation with funded balance and saved configuration in
.wallet.json
Step 1: Load wallet configuration
Load the wallet data and create the wallet instance:Step 2: Prepare the message batch
Create an array of messages to send:type: 'sendMsg'
— specifies that this is an outgoing message actionmode
— send mode for each individual messageoutMsg
— the internal message to send
Batch limit: You can send up to 254 messages per transaction. This limit exists because one action slot is reserved for
set_code
protection.Step 3: Send the batch
Send the batch using thesendBatch
method:
Automatic deployment: If your wallet is in
uninit
status (has balance but no code), it will automatically deploy when processing this external message. The wallet transitions to active
status, and the batch transfer is executed in the same transaction.Parameter explanation
queryId
— Unique identifier for replay protection:
- Each
query_id
can only be processed once within the protection window HighloadQueryId
is a wrapper class that represents the compositequery_id
as a sequential counter- Use
HighloadQueryId.fromSeqno(n)
to create a specific query ID - Provides
getNext()
method to increment to the next unique ID - Total range: 8,380,416 unique IDs
- See Query ID structure for details
createdAt
— Message timestamp for expiration:
- Set to 30 seconds before current time:
Math.floor(Date.now() / 1000) - 30
- Compensates for blockchain time lag (lite-servers use last block time, not current time)
- See Timestamp validation for why this is necessary
value
— Compute fee for the internal transaction:
- The internal receiver (Transaction 2) consumes a fixed 1,756 gas to process the action list
- At current gas prices, this equals ~0.0007024 TON
- This fee is sent to the wallet itself to cover internal message processing
- If insufficient, the internal transaction may fail (but replay protection remains intact)
Compute fee requirement: The
value
parameter covers gas for the internal transaction that processes the action list. This is additional to the gas costs of the external message itself.How it works
Batch transfers use a two-transaction pattern: the external message marks thequery_id
as processed and sends an internal message to itself with the action list, then the internal transaction processes the actions and sends all outgoing messages.
See Message sending flow for the complete validation sequence.
Next steps
You can send multiple batches in parallel, each with a uniquequery_id
.
To verify that your batch was fully processed, see How to verify message is processed.