I am following the tutorial to send a token to a specific recipient (https://spl.solana.com/token#example-transferring-tokens-to-an-explicit-recipient-token-account). Below is the code that works where I can send the transactions 1 by one, but it would take forever for large amounts of wallets.
const walletsTo = [wallet1, 'wallet2, 'wallet3'...]
walletsTo.forEach(async function (addressTo) {
const toWallet = new PublicKey(addressTo);
const toTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
fromWallet,
new PublicKey(mintToken),
toWallet
);
let signature = await transfer(
connection,
fromWallet,
fromTokenAccount.address,
toTokenAccount.address,
fromWallet.publicKey,
1
);
console.log("Signature tx: ", signature);
});
Is there a way to do the same but send the token to dozens or hundreds of recipients by batching the transactions?
EDIT: Based on Rudra Sarkar help, I was able to edit the code and have it work on Devnet as below, but still getting some Server responded with 429 Too Many Requests. Retrying after 500ms delay...
import {
getOrCreateAssociatedTokenAccount,
createTransferInstruction,
Account,
} from "@solana/spl-token";
import {
Connection,
Keypair,
PublicKey,
clusterApiUrl,
Transaction,
TransactionInstruction,
} from "@solana/web3.js";
// Your passphrase in Uint8 format
const fromWalletSecretPassphrase = [];
//List of wallets
const walletsTo = [
"wallet1",
"wallet2",
];
const mintToken = "yourMintTokenAddress";
const transfer_amount = 30;
const numberDecimals = 6;
const batchSize = 1; // adjust your batch size according to your need
const fromWallet = Keypair.fromSecretKey(
new Uint8Array(fromWalletSecretPassphrase)
);
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const getBatchInstructions = async (
batch: string[],
fromTokenAccount: Account
) => {
const instructions = await Promise.all(
batch.map(async (addressTo: string) => {
const toWallet = new PublicKey(addressTo);
const toTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
fromWallet,
new PublicKey(mintToken),
toWallet
);
return createTransferInstruction(
fromTokenAccount.address,
toTokenAccount.address,
fromWallet.publicKey,
transfer_amount * Math.pow(10, numberDecimals)
);
})
);
return instructions;
};
const sendBatches = async () => {
const batches: TransactionInstruction[][] = [];
// let batches = [];
const fromTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
fromWallet,
new PublicKey(mintToken),
fromWallet.publicKey
);
console.log(
`Sending ${transfer_amount} ${mintToken} from ${fromWallet.publicKey.toString()}`
);
for (let i = 0; i < walletsTo.length; i += batchSize) {
const batch = walletsTo.slice(i, i + batchSize);
const instructions = await getBatchInstructions(batch, fromTokenAccount);
batches.push(instructions);
}
for (const batch of batches) {
const transaction = new Transaction().add(...batch);
transaction.feePayer = fromWallet.publicKey;
transaction.recentBlockhash = (
await connection.getLatestBlockhash("confirmed")
).blockhash;
transaction.sign({
publicKey: fromWallet.publicKey,
secretKey: new Uint8Array(fromWalletSecretPassphrase),
});
const txid = await connection.sendRawTransaction(transaction.serialize());
console.log("Batch transaction:", txid);
}
};
sendBatches();