> ## Documentation Index
> Fetch the complete documentation index at: https://cobo.com/developers/llms.txt
> Use this file to discover all available pages before exploring further.

# Setting Up Token Sweeping

<Note>This content applies to WaaS 1.0 only. We highly recommend that you upgrade to [WaaS 2.0](https://www.cobo.com/developers/v2/guides/overview/introduction).</Note>

## Overview

Digital asset platforms and crypto exchanges often deal with the management of a substantial number of wallet addresses.
These addresses are assigned to various end-users, each of whom deposits assets by initiating transfers to designated wallet addresses.
In such cases, these platforms often conduct token sweeping to consolidate assets dispersed across different wallet addresses into a select few addresses.
The rationale behind this approach is to curtail the number of on-chain transactions, thereby minimizing associated gas fees.

Token sweeping may be triggered based on the following considerations:

1. Total amount of assets on a single address
2. Frequency (e.g., daily, weekly)
3. Current network gas fees

Do note that protracted trigger intervals may leave an end user's address with an insufficient balance in the event of a withdraw request.
In such cases, the client may need to submit another token sweeping request to ensure the availability of funds.

## Code Samples

Below are code samples along with corresponding explanations for your references.
You can choose to optimize the token sweeping strategy according to your business needs.
Token sweeping includes two categories: token sweeping for native tokens and non-native tokens.

Java: [https://github.com/CoboGlobal/cobo-java-api/blob/main/example/src/main/java/com/cobo/custody/mpc/MPCFundCollection.java](https://github.com/CoboGlobal/cobo-java-api/blob/main/example/src/main/java/com/cobo/custody/mpc/MPCFundCollection.java)

Python: [https://github.com/CoboGlobal/cobo-python-api/blob/main/mpc\_fund\_collection.py](https://github.com/CoboGlobal/cobo-python-api/blob/main/mpc_fund_collection.py)

## Token Sweeping Logics

1. Verify if the destination address is valid. If validation fails, please exit directly as the token sweeping will be marked as a failure.

<CodeGroup>
  ```java Java theme={null}
  ApiResponse<Boolean> response = mpcClient.isValidAddress(coin, toAddr);
          if (!response.isSuccess()) {
              return false;
          }
          if (!response.getResult()) {
              return false;
          }
  ```

  ```python Python theme={null}
  resp = self.mpc_client.is_valid_address(coin=coin, address=to_addr)
  if not resp or not resp.success or not resp.result:
  return False
  ```
</CodeGroup>

2. Query the coin type used for settling transaction fees.

<CodeGroup>
  ```java Java theme={null}
  ApiResponse<EstimateFeeDetails> feeResponse = mpcClient.estimateFee(coin, toAmount, toAddr, null);
          if (!feeResponse.isSuccess()) {
              return false;
          }
  ```

  ```python Python theme={null}
  fee_resp = self.mpc_client.estimate_fee(coin=coin, amount=to_amount, address=to_addr)
  if not resp:
         		return False
  ```
</CodeGroup>

3. Consolidate the balances of the queried coin type across all addresses under the MPC Wallet. If the aggregated balance falls below the estimated transaction fees amount, please exit directly as the token sweeping will be marked as a failure.

<CodeGroup>
  ```java Java theme={null}
     // Query the total number of addresses with remaining balances
          Integer pageIndex = 0;
          Integer pageLength = 50;
          ApiResponse<MPCListBalances> balances = mpcClient.listBalances(coin, pageIndex, pageLength);
          if (!balances.isSuccess()) {
              return false;
          }
          Integer total = balances.getResult().getTotal();
          if (total <= 0) {
              return false;
          }
          // Retrieve the balance data from all addresses with remaining balances
          List<MPCCoinBalanceDetail> allBalances = new ArrayList<>();
          while (pageIndex * pageLength < total) {
              balances = mpcClient.listBalances(coin, pageIndex, pageLength);
              allBalances.addAll(balances.getResult().getCoinData());
              pageIndex += pageLength;
          }
          // Summarize the total balance across all addresses with remaining balances; if the address matches the toAddr, the balance will not be swept
          BigInteger allBalanceAmount = new BigInteger("0");
          for (MPCCoinBalanceDetail balanceDetail : allBalances) {
              if (Objects.equals(balanceDetail.getAddress(), toAddr)) {
                  continue;
              }
              BigInteger balance = new BigInteger(balanceDetail.getBalance());
              allBalanceAmount = allBalanceAmount.add(balance);
          }
  ```

  ```python Python theme={null}

  page_index = 0
          page_length = 50
          #  Query the total number of addresses with remaining balances
          balance_resp = self.mpc_client.list_balances(coin=coin, page_index=page_index, page_length=page_length)
          if not balance_resp or not balance_resp.success or int(balance_resp.result.get('total')) <= 0:
              return False
          balance_total = int(balance_resp.result.get('total'))
          #  Retrieve the balance data from all addresses with remaining balances
          all_balances = []
          while page_index * page_length < balance_total:
              balance_resp = self.mpc_client.list_balances(coin=coin, page_index=page_index, page_length=page_length)
              all_balances.extend(balance_resp.result.get('coin_data'))
              page_index += page_length
          # Summarize the total balance across all addresses with remaining balances; if the address matches the toAddr, the balance will not be swept

          all_balance_amount = 0
          for balance in all_balances:
              if balance.get('address') == to_addr:
                  continue
              all_balance_amount += balance.get('balance')
  if all_balance_amount > to_amount:
              transfer_all_amount = 0
              for balance in all_balances:
                  if balance.get('address') == to_addr:
                      continue
  ```
</CodeGroup>

4. Transfer the balances of the specified coin type across all addresses to the destination address. The token sweeping process concludes when the total swept amount reaches the predefined threshold.
   1. When you sweep native tokens, the amount to sweep is computed based on the total address balances, your pre-set sweeping threshold, and the estimated transaction fees.
   2. When you sweep non-native tokens, verify first that "fromAddr" has sufficient balance to cover the estimated transaction fees. If insufficient, please transfer funds from "feeAddr" to "fromAddr" to ensure the success of token sweeping.

<CodeGroup>
  ```java Java theme={null}
  if (allBalanceAmount.compareTo(toAmount) >= 0) {
      BigInteger transferAllAmount = new BigInteger("0");
      for (MPCCoinBalanceDetail balanceDetail : allBalances) {
          if (Objects.equals(balanceDetail.getAddress(), toAddr)) {
              continue;
          }
          if (feeResponse.getResult().getFeeCoin().equals(coin)) {
              // sweep native tokens
              BigInteger transferAmount = transfer(balanceDetail.getCoin(), balanceDetail.getAddress(), toAddr, toAmount.subtract(transferAllAmount));
              transferAllAmount = transferAllAmount.add(transferAmount);
          } else {
              // sweep non-native tokens
              BigInteger transferAmount = tokenTransfer(balanceDetail.getCoin(), balanceDetail.getAddress(), toAddr, feeFromAddress, toAmount.subtract(transferAllAmount));
              transferAllAmount = transferAllAmount.add(transferAmount);
          }
          if (transferAllAmount.compareTo(toAmount) >= 0) {
              return true;
          }
      }
      // transfer funds from "feeAddr" to "fromAddr" to ensure the success of token sweeping
      return transferAllAmount.compareTo(toAmount) >= 0;
      } else {
      return false;
      }
  ```

  ```python Python theme={null}

  if all_balance_amount > to_amount:
              transfer_all_amount = 0
              for balance in all_balances:
                  if balance.get('address') == to_addr:
                      continue
                  if fee_resp.result.get('fee_coin') == coin:
                      # sweep native tokens
                      transfer_all_amount += self.transfer(coin=coin, from_addr=balance.get('address'), to_addr=to_addr, to_amount=to_amount - transfer_all_amount)
                  else:
                      transfer_all_amount += self.token_transfer(coin=coin, from_addr=balance.get('address'), to_addr=to_addr, fee_addr=fee_from_addr, to_amount=to_amount - transfer_all_amount)
                  if transfer_all_amount > to_amount:
                      return True
              # transfer funds from "feeAddr" to "fromAddr" to ensure the success of token sweeping
              return transfer_all_amount > to_amount
          else:
              return False
  ```
</CodeGroup>
