Bulk Withdrawal ERC20 Tokens - MPC
Send multiple ERC20 token transfers in a single transaction using an MPC wallet. See the Guide.
-
Build a bulk withdrawal transaction by providing multiple recipients in your transaction request, each specifying the recipient address, amount, and token name. For MPC wallets, use
sendManywithtype: 'transfer'and includefeeOptionsfor gas configuration. The SDK consolidates the recipients array into a single transaction that interacts with the batcher contract.All transfers in a batch must use the same token type. Maximum batch size varies by network (typically around 100 recipients per transaction).
Prerequisites: Complete Get Started, Create Wallets, Deposit Assets, and Enable Bulk Withdrawals of ERC20 Tokens. You must have sufficient balance of the native coin to cover gas fees.
-
Sign and send the transaction using the MPC signing flow. Pass either your unencrypted
prvkey or yourwalletPassphrasewith theencryptedPrvin the keychain. BitGo Express handles the signature-share exchange with BitGo and broadcasts the transaction to the blockchain.For more details on the full MPC signing flow, see Withdraw from Wallet - Self-Custody MPC (Manual).
// 1. Build a Bulk Withdrawal Transaction
// Use the JavaScript SDK for this step (see JavaScript tab)
// 2. Sign and Send Transaction
export BITGO_EXPRESS_HOST="<YOUR_LOCAL_HOST>"
export COIN="<ASSET_ID>"
export WALLET_ID="<YOUR_WALLET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export TX_REQUEST_ID="<TX_REQUEST_ID>"
curl -X POST \
http://$BITGO_EXPRESS_HOST/api/v2/$COIN/wallet/$WALLET_ID/signtxtss \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"txRequestId": "'"$TX_REQUEST_ID"'",
"prv": "string, # Either pass just your `prv` or pass your `walletPassphrase`, `keychain`, and `encryptedPrv`
"walletPassphrase": "string",
"keychain": {
"encryptedPrv": "string"
}
}'
// 1. Build a Bulk Withdrawal Transaction
async function sendBulkTokenWithdrawal() {
const walletInstance = await bitgo
.coin('opeth')
.wallets()
.get({ id: '<YOUR_WALLET_ID>' });
// Send a transaction with multiple recipients
return walletInstance.sendMany({
type: 'transfer',
recipients: [
{
address: '0x1111111111111111111111111111111111111111',
amount: '100000000',
tokenName: 'opeth:usdc',
},
{
address: '0x2222222222222222222222222222222222222222',
amount: '200000000',
tokenName: 'opeth:usdc',
},
{
address: '0x3333333333333333333333333333333333333333',
amount: '300000000',
tokenName: 'opeth:usdc',
}
],
walletPassphrase: 'VerySecurePassword1234',
feeOptions: {
maxFeePerGas: '81130354893',
maxPriorityFeePerGas: '71130354893',
}
});
}
// 2. Sign and Send Transaction
import dotenv from "dotenv";
dotenv.config();
import { BitGoAPI } from "@bitgo/sdk-api";
import { Tsol } from "@bitgo/sdk-coin-sol";
import { z } from "zod";
const env = z
.object({
USERNAME: z.string().min(1),
PASSWORD: z.string().min(1),
ENV: z.union([z.literal("test"), z.literal("staging"), z.literal("prod")]),
OTP: z.string().optional(),
WALLET_ID: z.string(),
})
.parse(process.env);
const bitgo = new BitGoAPI({ env: env.ENV });
bitgo.register("tsol", Tsol.createInstance);
const coin = bitgo.coin("tsol");
async function auth() {
await bitgo.authenticate({
username: env.USERNAME,
password: env.PASSWORD,
otp: env.OTP,
});
await bitgo.lock();
await bitgo.unlock({ otp: "000000", duration: 3600 });
}
async function main() {
await auth();
const wallet = await coin.wallets().get({ id: env.WALLET_ID });
const params = {
txRequestId: "string", // previously created txRequestId
// one of:
prv: "un-encrypted prv",
// or
keychain: {
encryptedPrv: "encrypted prv"
},
walletPassphrase: "password to decrypt the encryptedPrv"
};
wallet.signTransaction(params).then(function (result) {
// print result details
console.dir(result);
});
// 2. Sign and Send Transaction Response
{
"transfer": {
"coin": "opeth:usdc",
"id": "63727a81cdbc820007b27caa7b76016d",
"wallet": "63726fde0a3c94000758f2790536041d",
"txid": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"height": 0,
"date": "2023-11-14T17:27:29.128Z",
"type": "send",
"value": "-600000000",
"valueString": "-600000000",
"baseValueString": "-600000000",
"baseValueWithoutFeesString": "-600000000",
"feeString": "0",
"payGoFee": 0,
"payGoFeeString": "0",
"state": "signed",
"instant": false
},
"txid": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"status": "signed"
}