Enable Bulk Withdrawals of ERC20 Tokens

Overview

To make bulk withdrawals of ERC20 tokens, you must approve a batcher smart contract transferring tokens on your behalf. When granting permission, you can set a limit that ensures transactions of the token can't exceed a specified amount.

Approving the batcher smart contract is a one-time operation, but each token requires a separate approval in each wallet. For example, once you enable token A in wallet 1:

  • To bulk withdraw token A from wallet 2, make a separate approval for token A in wallet 2.
  • To bulk withdraw token B from wallet 1, make a separate approval for token B in wallet 1.

In addition, if you want to change the limit amount for bulk withdrawals, you must make another approval.

Prerequisites

1. (Optional) Check Token Allowance

Before approving tokens, you can check if your wallet has already approved the batcher contract:

Endpoint: Get the token allowance for a specific token contract address

export COIN="<ASSET_ID_OF_NATIVE_COIN>"
export WALLET_ID="<YOUR_WALLET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"

curl -X GET \
  https://app.bitgo-test.com/api/v2/$COIN/wallet/$WALLET_ID/allowance \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Step Result

In this example, the large number shown in the response is 2^256-1, which is the maximum approval amount (unlimited).

{
  "allowance": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
}

2. Approve Batcher Smart Contract

Endpoint: Build an approval transaction for ERC20 token

async function approveToken() {
  const walletInstance = await bitgo
    .coin('opeth')
    .wallets()
    .get({ id: '<YOUR_WALLET_ID>' });
  
  // For custodial MPC wallets, use sendMany with type: 'tokenApproval'
  const result = await walletInstance.sendMany({
    isTss: true,
    type: 'tokenApproval',
    tokenName: 'opeth:usdc'
  });
  
  return result;
}
export COIN="<ASSET_ID_OF_NATIVE_COIN>"
export WALLET_ID="<YOUR_WALLET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export TOKEN_NAME="<ASSET_ID_OF_TOKEN>"

curl -X POST \
  https://app.bitgo-test.com/api/v2/$COIN/wallet/$WALLET_ID/token/approval/build \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "intent": {
      "intentType": "tokenApproval",
      "tokenName": "'"$TOKEN_NAME"'"
    }
  }'

Step Result

{
  "pendingApproval": {
    "id": "63727a81cdbc820007b27caa7b76016d",
    "coin": "eth",
    "wallet": "63726fde0a3c94000758f2790536041d",
    "state": "pendingFinalApproval",
    "scope": "wallet",
    "info": {
      "type": "transactionRequest",
      "transactionRequest": {
        "coinSpecific": {
          "eth": {
            "eip1559": {
              "maxPriorityFeePerGas": 1500000000,
              "maxFeePerGas": 133302263906
            },
            "recipients": [
              {
                "amount": "0",
                "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
                "data": "0x095ea7b3000000000000000000000000..."
              }
            ]
          }
        }
      }
    }
  }
}

Next Steps

Since no assets are withdrawing in this transaction, BitGo automatically bypasses any policies to require additional admin approval.

You can now Bulk Withdraw ERC20 Tokens to multiple recipients in a single transaction.

See Also