Overview

The ERC20 Bulk Withdrawal enables you to send multiple token transfers to different addresses in a single transaction. This functionality utilizes a special batcher contract to combine multiple token transfers, reducing gas costs and simplifying transaction management compared to sending multiple individual token transfers.

Key benefits:

  • Lower gas costs: Consolidate multiple transfers into a single on-chain transaction
  • Simplified transaction management: Single approval workflow for multiple transfers
  • Supported on multiple EVM chains: Available on Ethereum, Polygon, Arbitrum, Optimism, and other EVM-compatible networks

Technical Details

When using the bulk withdrawal feature:

  1. A batcher contract specific to your network processes your transaction.
  2. The contract calls batchTransferFrom to send tokens to multiple recipients.
  3. The batcher contract uses the ERC20 transferFrom method to move tokens from your wallet to the recipients.
  4. The transaction appears on-chain as a single contract interaction.
  5. Each recipient receives their tokens directly from your wallet.

Limitations

  • All transfers in a batch must use the same token type.
  • Maximum batch size varies by network (typically around 100 recipients per transaction).
  • BitGo does not support batch transfers for CryptoPunks and other non-standard ERC20 tokens.

Prerequisites

Cookbooks

Need just the steps? Expand a cookbook below to get started:

Bulk Withdrawal ERC20 (MPC)Open Cookbook Bulk Withdrawal ERC20 (Multisig)Open Cookbook

1. Build a Bulk Withdrawal Transaction

To create a bulk withdrawal transaction, you'll provide multiple recipients in your transaction request, each specifying the recipient address and amount.

async function buildBulkTokenWithdrawal() {
  const walletInstance = await bitgo
    .coin('opeth')
    .wallets()
    .get({ id: '<YOUR_WALLET_ID>' });
  
  // Build a transaction with multiple recipients
  const buildResult = await walletInstance.prebuildTransaction({
    recipients: [
      {
        address: '0x1111111111111111111111111111111111111111',
        amount: '100000000'
      },
      {
        address: '0x2222222222222222222222222222222222222222',
        amount: '200000000'
      },
      {
        address: '0x3333333333333333333333333333333333333333',
        amount: '300000000'
      }
    ],
    tokenName: 'opeth:usdc'
  });
  
  return buildResult;
}
POST /api/v2/{coin}/wallet/{walletId}/tx/build

{
  "recipients": [
    {
      "address": "0x1111111111111111111111111111111111111111",
      "amount": "100000000"
    },
    {
      "address": "0x2222222222222222222222222222222222222222",
      "amount": "200000000"
    },
    {
      "address": "0x3333333333333333333333333333333333333333",
      "amount": "300000000"
    }
  ],
  "tokenName": "opeth:usdc"
}

In a bulk withdrawal transaction, the batcher contract consolidates the recipients array into a single on-chain interaction. The batcher contract then distributes the tokens to each recipient address according to the specified amounts.

2. Sign and Send Transaction

After building the transaction, sign it and send it to BitGo for processing. The transaction signing process follows the standard pattern for your wallet type.

async function sendBulkTokenWithdrawal() {
  const walletInstance = await bitgo
    .coin('opeth')
    .wallets()
    .get({ id: '<YOUR_WALLET_ID>' });
  
  // Build, sign and send in one operation
  const result = await walletInstance.sendMany({
    recipients: [
      {
        address: '0x1111111111111111111111111111111111111111',
        amount: '100000000'
      },
      {
        address: '0x2222222222222222222222222222222222222222',
        amount: '200000000'
      },
      {
        address: '0x3333333333333333333333333333333333333333',
        amount: '300000000'
      }
    ],
    tokenName: 'opeth:usdc',
    walletPassphrase: 'VerySecurePassword1234',
  });
  
  return result;
}

Step Result

The response includes the transaction details and the status of the transaction:

{
  "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"
}

See Also