Links

How to withdraw assets from virtual accounts with gas pump wallets

This guide describes how to withdraw assets from virtual accounts connected to gas pump wallets (gas pump addresses).
When using gas pump addresses for withdrawals, gas fees for the transactions are automatically deducted from a dedicated address instead of each individual gas pump addresses. This eliminates the need to send crypto to each gas pump address to pay for gas fees.
For the complete information about the Gas Pump feature and how it works, see Pay Gas Fees with Tatum Gas Pump.
To withdraw assets from virtual accounts connected to gas pump addresses, complete the following steps:

Precalculate (generate) gas pump addresses

​Precalculate a gas pump address for every user. Each gas pump address supports the native currency of the blockchain it's deployed on, as well as fungible tokens, NFTs, and Multi Tokens (ERC-20, ERC-721, and ERC-1155 or equivalent).
In the request, specify the ID of the blockchain address that will own the precalculated gas pump addresses (the owner parameter). The owner will also be paying gas fees for operations made on the gas pump addresses. You have to make sure that the owner always has enough funds to cover these gas fees.
The following sample request precalculates 100 gas pump addresses on Ethereum:
cURL
JavaScript
1
curl -i -X POST \
2
https://api.tatum.io/v3/gas-pump \
3
-H 'Content-Type: application/json' \
4
-H 'x-api-key: YOUR_API_KEY_HERE' \
5
-d '{
6
"chain": "ETH",
7
"owner": "0x2b5a0bE5940B63dE1eDdCCCa7bd977357e2488eD",
8
"from": 0,
9
"to": 99
10
}'
1
import { Currency, TatumApi} from "@tatumio/api-client"
2
const api = TatumApi('YOUR_API_KEY_HERE')
3
​
4
export async function ethBlockchainExample(){
5
const blockchainAddresses = await api.blockchain.gasPump.precalculateGasPumpAddresses({
6
chain: Currency.ETH,
7
owner: '0x2b5a0bE5940B63dE1eDdCCCa7bd977357e2488eD',
8
from: 0,
9
to: 99,
10
});
11
}
12
​
13
ethBlockchainExample()
You can find the complete information about this API, its parameters, and code samples in various languages in the API Reference.
The response returns an array of the precalculated gas pump addresses:
1
[
2
"0x8cb76aed9c5e336ef961265c6079c14e9cd3d2ea",
3
"0x5c6079c14e9cd3d2ea8cb76aed9c5e336ef96126",
4
...
5
]

Activate the gas pump addresses

The precalculated addresses can receive funds. However, they cannot be used to send funds to other addresses. This is because the addresses are not activated. To make the addresses be able to send funds, activate them.
The following sample request activates the 100 gas pump addresses that you precalculated on Ethereum in the previous step:
cURL
JavaScript
1
curl -i -X POST \
2
https://api.tatum.io/v3/gas-pump/activate \
3
-H 'Content-Type: application/json' \
4
-H 'x-api-key: YOUR_API_KEY_HERE' \
5
-d '{
6
"chain": "ETH",
7
"owner": "0x2b5a0bE5940B63dE1eDdCCCa7bd977357e2488eD",
8
"from": 0,
9
"to": 99,
10
"fromPrivateKey": "0x05e150c73f1920ec14caa1e0b6aa09940899678051a78542840c2668ce5080c2"
11
}'
1
import { Currency, TatumApi } from "@tatumio/api-client"
2
const api = TatumApi('YOUR_API_KEY_HERE')
3
​
4
export async function ethBlockchainExample(){
5
const blockchainHash = await api.blockchain.gasPump.activateGasPumpAddresses({
6
from: 0,
7
to: 99,
8
chain: Currency.ETH,
9
owner: '0x2b5a0bE5940B63dE1eDdCCCa7bd977357e2488eD',
10
fromPrivateKey: '0x05e150c73f1920ec14caa1e0b6aa09940899678051a78542840c2668ce5080c2'
11
});
12
const addresses = await api.blockchain.gasPump.activatedNotActivatedGasPumpAddresses(Currency.ETH, blockchainHash.txId)
13
}
14
ethBlockchainExample()
You can find the complete information about this API, its parameters, and code samples in various languages in the API Reference.
The response returns the ID of the activation transaction:
1
{
2
"txId": "c83f8818db43d9ba4accfe454aa44fc33123d47a4f89d47b314d6748eb0e9bc9"
3
}
Activating the gas pump addresses may take some time. We recommend that you get the results of the activation transaction using this API and, if any addresses did not get activated, try activating them again.

Create virtual accounts

With the gas pump addresses prepared, create virtual accounts.
Let's imagine that you have decided to support ETH and USDC for every user. That means that you need to create two virtual accounts: one for ETH and one for USDC. Because you will later assign the gas pump addresses to these accounts manually, you need to create the virtual accounts without the extended public key (xpub). That means that you are going to use the CreateAccount schema of the API request body.
The following sample requests create one virtual account for ETH and one virtual account for USDC:
cURL
JavaScript
ETH virtual account
1
curl -i -X POST \
2
https://api.tatum.io/v3/ledger/account \
3
-H 'Content-Type: application/json' \
4
-H 'x-api-key: YOUR_API_KEY_HERE' \
5
-d '{
6
"currency": "ETH"
7
}'
ETH virtual account
1
import { Account, Currency, CreateAccount, createAccount } from "@tatumio/tatum";
2
import { config } from "dotenv";
3
​
4
config();
5
​
6
const createNewAccount = async () => {
7
const createAccountData: CreateAccount = {
8
currency: Currency.ETH
9
};
10
const accoun: Account = await createAccount(createAccountData);
11
console.log(accoun);
12
};
13
​
14
createNewAccount();
cURL
JavaScript
USDC virtual account
1
curl -i -X POST \
2
https://api.tatum.io/v3/ledger/account \
3
-H 'Content-Type: application/json' \
4
-H 'x-api-key: YOUR_API_KEY_HERE' \
5
-d '{
6
"currency": "USDC_ETH"
7
}'
USDC virtual account
1
import { Account, Currency, CreateAccount, createAccount } from "@tatumio/tatum";
2
import { config } from "dotenv";
3
​
4
config();
5
​
6
const createNewAccount = async () => {
7
const createAccountData: CreateAccount = {
8
currency: Currency.USDC_ETH
9
};
10
const accoun: Account = await createAccount(createAccountData);
11
console.log(accoun);
12
};
13
​
14
createNewAccount();
You can find the complete information about this API, its parameters, and code samples in various languages in the API Reference.
The responses return the details about the two virtual accounts that you have just created:
ETH virtual account
1
{
2
"id": "5fb7bdf6e96d9ab593e191a5",
3
"currency": "ETH",
4
"balance": {
5
"accountBalance": "0",
6
"availableBalance": "0"
7
},
8
"active": true,
9
"frozen": false
10
}
USDC virtual account
1
{
2
"id": "5fb7bdf6e96d9ab593e191a6",
3
"currency": "USDC_ETH",
4
"balance": {
5
"accountBalance": "0",
6
"availableBalance": "0"
7
},
8
"active": true,
9
"frozen": false
10
}

Assign the gas pump addresses to the virtual accounts

Once the virtual accounts have been created, assign the gas pump addresses to them.
When a blockchain address is assigned to a virtual account, any incoming transaction to the address is automatically synchronized with the virtual account according to the address currency.
The following sample request assigns one of the precalculated and activated gas pump addresses to the ETH virtual account:
cURL
JavaScript
1
curl -i -X POST \
2
'https://api.tatum.io/v3/offchain/account/5fb7bdf6e96d9ab593e191a5/address/0x8cb76aed9c5e336ef961265c6079c14e9cd3d2ea' \
3
-H 'x-api-key: YOUR_API_KEY_HERE'
1
import {assignDepositAddress} from '@tatumio/tatum';
2
​
3
const assign = assignDepositAddress ("5fb7bdf6e96d9ab593e191a5","0x8cb76aed9c5e336ef961265c6079c14e9cd3d2ea");
You can find the complete information about this API, its parameters, and code samples in various languages in the API Reference.
The response confirms the gas pump address has been assigned to the virtual account. Any incoming blockchain transaction to this address will be automatically detected, and the virtual account balance will be updated.
1
{
2
"address": "0x8cb76aed9c5e336ef961265c6079c14e9cd3d2ea",
3
"currency": "ETH"
4
}

Create a withdrawal request to the virtual account

Once you have accumulated assets on a virtual account, withdraw them from the account. To do so, perform a withdrawal operation from that account.
In the request, specify the ID of the virtual account to withdraw the assets from (the senderAccountId parameter) and the blockchain address to send the assets to (the address parameter). Creating a withdrawal request to the virtual account will debit the withdrawn balance from the virtual account. This operation is done within the virtual account and is not written to the underlying blockchain.
The assets will not be sent yet. You are just specifying the future recipient of the assets but not actually sending the assets yet.
The following sample request withdraws 1 USDC from the USDC virtual account that you created earlier:
cURL
JavaScript
1
curl -i -X POST \
2
https://api.tatum.io/v3/offchain/withdrawal \
3
-H 'Content-Type: application/json' \
4
-H 'x-api-key: YOUR_API_KEY_HERE' \
5
-d '{
6
"senderAccountId": "5fb7bdf6e96d9ab593e191a6",
7
"address": "0x42952e30fB119e0683607Ef6D5A7E8A97dBB7314",
8
"amount": "1",
9
"fee": "0.0005"
10
}'
1
import { offchainStoreWithdrawal } from '@tatumio/tatum';
2
​
3
const body = {
4
senderAccountId: "5fb7bdf6e96d9ab593e191a6",
5
address: "0x42952e30fB119e0683607Ef6D5A7E8A97dBB7314",
6
amount: "1",
7
fee: "0.0005"
8
}
9
const wallet = offchainStoreWithdrawal (body);
You can find the complete information about this API, its parameters, and code samples in various languages in the API Reference.
The response returns the virtual account transaction reference and the ID of the withdrawal:
1
{
2
"reference": "5e6be8e9e6aa436299950c41",
3
"id": "5e68c66581f2ee32bc354087"
4
}
The account balance has been debited with 1 USDC, and the transaction is visible in the list of the transactions for the virtual account. You still have not done anything on the blockchain.

Transfer the assets from the gas pump address

Once the withdrawal request is successfully stored on the virtual account, move the assets from the gas pump address.
Because you are using gas pump addresses, you do not have to send any funds there to pay for gas. The funds required to pay for the transaction will automatically be deducted from the owner address that you specified when precalculating the gas pump addresses.
The following sample request transfers 1 USDC from the gas pump address associated with the USDC virtual account where you created a withdrawal request:
cURL
JavaScript
1
curl -i -X POST \
2
https://api.tatum.io/v3/blockchain/sc/custodial/transfer \
3
-H 'Content-Type: application/json' \
4
-H 'x-api-key: YOUR_API_KEY_HERE' \
5
-d '{
6
"chain": "ETH",
7
"custodialAddress": "0x5c6079c14e9cd3d2ea8cb76aed9c5e336ef96126",
8
"recipient": "0x42952e30fB119e0683607Ef6D5A7E8A97dBB7314",
9
"contractType": 0,
10
"tokenAddress": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174",
11
"amount": "1",
12
"fromPrivateKey": "0x37b091fc4ce46a56da643f021254612551dbe0944679a6e09cb5724d3085c9ab"
13
}'
1
import { Currency, prepareTransferFromCustodialWallet } from '@tatumio/tatum';
2
​
3
const body = {
4
chain: Currency.ETH,
5
custodialAddress: "0x5c6079c14e9cd3d2ea8cb76aed9c5e336ef96126",
6
recipient: "0x42952e30fB119e0683607Ef6D5A7E8A97dBB7314",
7
contractType: 0,
8
tokenAddress: "0x2791bca1f2de4661ed88a30c99a7a9449aa84174",
9
amount: "1",
10
fromPrivateKey: "0x37b091fc4ce46a56da643f021254612551dbe0944679a6e09cb5724d3085c9ab"
11
}
12
const transfer = prepareTransferFromCustodialWallet(false, body);
  • custodialAddress is the gas pump address associated with the USDC virtual account.
  • recipient is the blockchain address to send the assets to (it is the same address that you specified in the address parameter when creating a withdrawal request earlier).
  • contractType is the type of the asset that you transferring; 0 means fungible tokens (ERC-20 or equivalent).
  • tokenAddress is the address of the asset that you are transferring; this sample request uses 0x2791bca1f2de4661ed88a30c99a7a9449aa84174.
  • amount is the amount of the asset that you are transferring (1 USDC).
  • fromPrivateKey is the private key of the owner address.
You can find the complete information about this API, its parameters, and code samples in various languages in the API Reference.
The response returns the transaction ID (hash):
1
{
2
"txId": "0xa1bdc0008b6cce138cec38336a3cbbf1117cc56bcfe0004e14d6789a9d099b72"
3
}

Mark the withdrawal on the virtual account as completed

Once the transfer transaction is successful, mark the withdrawal as completed. If the transaction is not marked as completed, there will be inconsistencies within the virtual account state.
If the transaction fails, cancel the original withdrawal request. The funds will be credited to the originating virtual account.