Bulk Withdrawal ERC20 Tokens

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. Your transaction is processed through a batcher contract specific to your network.
  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).
  • Batch transfers are not supported for CryptoPunks and other non-standard ERC20 tokens.

Prerequisites

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 recipients array is consolidated into a single transaction that interacts with the batcher contract. 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