Send batch transactions
The solana:signAndSendAllTransactions Wallet Standard feature lets you sign and send multiple
Solana transactions in a single wallet interaction.
This is useful for operations that span several transactions, such as initializing multiple accounts,
batch token transfers, or multi-step program interactions.
Prerequisites
Set up a Solana client and connect to the user's wallet:
import { createSolanaClient } from '@metamask/connect-solana'
import {
Connection,
Transaction,
SystemProgram,
PublicKey,
LAMPORTS_PER_SOL,
} from '@solana/web3.js'
const solanaClient = await createSolanaClient({
dapp: {
name: 'My Solana Dapp',
url: window.location.origin,
},
})
const wallet = solanaClient.getWallet()
const { accounts } = await wallet.features['standard:connect'].connect()
const account = accounts[0]
const publicKey = new PublicKey(account.address)
const connection = new Connection('https://solana-devnet.infura.io/v3/<YOUR_INFURA_API_KEY>')
Build and send batch transactions
1. Build the transactions
Construct each transaction with a new block hash and fee payer.
Serialize each with verifySignatures: false since the wallet adds signatures:
const { blockhash } = await connection.getLatestBlockhash()
const recipients = ['RECIPIENT_ADDRESS_1', 'RECIPIENT_ADDRESS_2', 'RECIPIENT_ADDRESS_3']
const serializedTransactions = recipients.map(recipient => {
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: publicKey,
toPubkey: new PublicKey(recipient),
lamports: 0.001 * LAMPORTS_PER_SOL,
})
)
transaction.recentBlockhash = blockhash
transaction.feePayer = publicKey
return transaction.serialize({ verifySignatures: false })
})
2. Sign and send all transactions
Use the solana:signAndSendAllTransactions feature to submit the batch:
const batchFeature = wallet.features['solana:signAndSendAllTransactions']
const results = await batchFeature.signAndSendAllTransactions({
account,
transactions: serializedTransactions,
chain: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',
})
3. Confirm each transaction
Always confirm transactions before updating the UI:
for (const { signature } of results) {
const confirmation = await connection.confirmTransaction(
{
signature,
blockhash,
lastValidBlockHeight: (await connection.getLatestBlockhash()).lastValidBlockHeight,
},
'confirmed'
)
if (confirmation.value.err) {
console.error('Transaction failed on-chain:', confirmation.value.err)
} else {
console.log('Transaction confirmed:', signature)
}
}
Error handling
try {
const results = await batchFeature.signAndSendAllTransactions({
account,
transactions: serializedTransactions,
chain: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',
})
} catch (err) {
if (err.code === 4001) {
// User rejected the batch — show retry UI
} else if (err.code === -32002) {
// Request already pending — ask user to check MetaMask
} else {
console.error('Batch transaction error:', err)
}
}
Important considerations
- New block hash: Block hashes expire after ~60 seconds.
Call
getLatestBlockhashimmediately before building the batch. - Transaction size: Each individual transaction is limited to 1,232 bytes. If a single transaction exceeds this limit, split it into smaller transactions.
- Confirmation: A submitted transaction is not finalized until
confirmTransactionreturns. Always confirm before reporting success to the user. - Devnet and testnet are only supported in the MetaMask browser extension, not the mobile wallet.
Next steps
- Send a legacy transaction for single transactions.
- Send a versioned transaction for transactions with Address Lookup Tables.
- MetaMask Connect Solana methods for the full API reference.