Skip to main content
Fireblocks supports two vault structures suited to different market segments: segregated account and omnibus account. In an omnibus setup, three vault types work together:
  • Intermediate vault accounts: Assigned per end-client for deposits. Use the Fireblocks API to generate as many as needed.
  • Omnibus deposits: The central vault where end-client funds are swept and stored.
  • Withdrawal pool: Vault accounts containing funds allocated for end-client withdrawals. More than one may be required due to blockchain limitations.
Learn more about best practices for structuring your Fireblocks Vault.

Sweeping

Sweeping moves funds from intermediate vault accounts into your omnibus account via an on-chain transfer. Because it is an on-chain transfer, fees apply. Set the trigger for when sweeping runs based on your business needs — for example:
  • When the balance in an intermediate vault account reaches a threshold
  • On a fixed schedule (daily, weekly)
  • When network fees are favorable
See also: Reconciliation & crediting and Deposit control & Confirmation policy.

Fueling

When sweeping non-base assets such as ERC-20 tokens, the transaction fee must be paid in the base asset — for example, sweeping USDC on Ethereum requires ETH. Fireblocks offers two automated approaches for managing gas fees across your intermediate vault accounts: Gas Station pushes ETH directly into each intermediate vault account before a sweep, so the vault itself holds and spends the gas. This is the right fit if you’re comfortable holding ETH in your source vaults and want automated per-vault fueling. See the Gas Station setup and usage guide. Universal Gasless takes a different approach: a designated relay sponsors gas fees on behalf of your intermediate vault accounts during the transaction, so those vaults never need to hold ETH. It supports sweeping all Ethereum-based tokens (ERC-20, ERC-721, and ERC-1155), but does not relay native ETH transfers — Gas Station remains the right choice for sweeping ETH itself. Three relay options are available:
  • This workspace: a single dedicated vault in your workspace holds ETH and covers gas fees for all other vault accounts — you still hold ETH, but only in one place.
  • External workspace: a separate Fireblocks workspace acts as the relay, suited for multi-workspace setups or compliance requirements that prohibit holding ETH in the sweeping workspace.
  • Fireblocks relay: Fireblocks sponsors the gas directly, with no ETH holding required anywhere in your workspace.
To configure Universal Gasless, see the Universal Gasless setup guide.

Example

Step 1: Create the vault accounts in batch

This guide assumes you use a backend “internal ledger” that correlates your internal customer ref IDs with Fireblocks vault account IDs. The following example:
  1. Creates vault accounts for your end-users using a naming convention you define.
  2. Creates an ETH deposit address under each vault account.
  3. Creates your omnibus vault account to serve as the treasury.
It calls createVaultAccounts (TypeScript/JavaScript) or create_vault_accounts (Python), passing the number of accounts to create, the asset ID, the name prefix, and the treasury account.
const createVaultAccounts = async (
  amountOfVaultAccounts: number,
  assetId: string,
  vaultAccountNamePrefix: string
): Promise<Array<{}> | undefined> => {
  const result: Array<{}> = [];
  try {
    for (let i = 1; i <= amountOfVaultAccounts; i++) {
      const vaultAccountResponse = await fireblocks.vaults.createVaultAccount(
        {
          createVaultAccountRequest:
          {
            name: vaultAccountNamePrefix.toString() + i.toString()
          }
        }
      );
      let vaultWalletAddress = await fireblocks.vaults.createVaultAccountAsset(
        {
          vaultAccountId: vaultAccountResponse.data.id as string,
          assetId
        }
      );
      result.push({
        "Vault Account Name": vaultAccountResponse.data.name,
        "Vault Account ID": vaultAccountResponse.data.id,
        "Asset ID": assetId,
        "Address": vaultWalletAddress.data.address
      })
      console.log("Vault Account Details: ", result);
    }

    return result;
  }
  catch (error) {
    console.error(error);
  }
}

createVaultAccounts(2, "ETH_TEST6", "END-USER#22223");

Step 2: Create the sweeping logic

This guide assumes your internal ledger can produce a list of vault accounts ready for sweeping. For a basic internal ledger description, see the section at the bottom of this article. Define which vault accounts to sweep and the minimum balance threshold. The example below sweeps any intermediate vault account that meets the threshold into the treasury.
  • Filter intermediate vault accounts by name prefix and minimum balance.
  • Initiate a create transaction loop for each qualifying account.

Testing

Add this code to the vault creation code from Step 1.
const createTagWithdrawalVaultAccounts = async (
  assetId: string,
  name: string,
): Promise<Array<{}> | undefined> => {
  const result: Array<{}> = [];

  try {
    const vaultAccount = await fireblocks.vaults.createVaultAccount({
      createVaultAccountRequest: {
        name,
      },
    });

    if (vaultAccount.data) {
      const vaultWallet = await fireblocks.vaults.createVaultAccountAsset({
        vaultAccountId: vaultAccount.data.id as string,
        assetId,
      });

      result.push({
        "Vault Account Name": vaultAccount.data.name,
        "Vault Account ID": vaultAccount.data.id,
        "Asset ID": assetId,
        Address: vaultWallet.data.address,
      });

      console.log(JSON.stringify(result, null, 2));
    }

    return result;
  } catch (error) {
    console.error(error);
  }
};

const sweepToOmnibus = async (
  vaNamePrefix: string,
  minAmount: number,
  assetId: string,
  omnibusVaId: string,
): Promise<
  Array<{
    fromVaName: string;
    fromVaId: string;
    txId: string;
    grossAmount: string;
  }>
> => {
  let sweepingInfo: any[] = [];

  const vaultsToSweepFrom = await fireblocks.vaults.getPagedVaultAccounts({
    namePrefix: vaNamePrefix,
    assetId,
    minAmountThreshold: minAmount,
  });

  if (vaultsToSweepFrom.data.accounts) {
    await Promise.all(
      vaultsToSweepFrom.data.accounts.map(
        async (vaultAccount: VaultAccount) => {
          if (vaultAccount.assets && vaultAccount.assets.length > 0) {
            const createTxResponse =
              await fireblocks.transactions.createTransaction({
                transactionRequest: {
                  assetId,
                  source: {
                    type: TransferPeerPathType.VaultAccount,
                    id: vaultAccount.id,
                  },
                  destination: {
                    type: TransferPeerPathType.VaultAccount,
                    id: omnibusVaId,
                  },
                  amount: vaultAccount.assets[0].available,
                },
              });

            sweepingInfo.push({
              fromVaName: vaultAccount.name,
              fromVaId: vaultAccount.id,
              txId: createTxResponse.data.id,
              grossAmount: vaultAccount.assets[0].available,
            });
          }
        },
      ),
    );
  }

  console.log(
    "Initiated sweeping transactions:\n" +
      JSON.stringify(sweepingInfo, null, 2),
  );
  return sweepingInfo;
};

sweepToOmnibus("END-USER-#", 0.1, "ETH_TEST5", "0");