Tatum
Search…
How to pay fees for token transfers from another address
A gas pump for your native assets, ERC-20, ERC-721 and ERC-1155 tokens.
If you’ve built or want to build a custodial exchange like Binance or Kraken, a custodial wallet service, or a custodial NFT marketplace, there’s one major headache that you’re bound to encounter: how do you pay the gas fees for sending tokens from your users’ accounts? Astoundingly, there really hasn’t been any simple way to do this until now. As an exchange owner, every time you want to send tokens from one of your user’s accounts, you have to calculate the gas fees, send that amount to their account (a transaction that also incurs gas fees), and send the tokens from their account.
Two transactions, both of which incur gas fees, plus can result in minuscule differences of crypto “dust” remaining in their accounts. If you have thousands or millions of addresses, this method creates an enormous amount of work and fees for you as a custodial provider.
In short, a big headache. So we decided to fix that.

Gas pump smart contract

Our new gas pump uses a master address that generates user sub-accounts - smart contracts.
Smart contract implementation is available here.
You simply top up the master address with a balance of crypto from which you’ll pay all of your gas fees, and every time you send tokens from a user address, the gas fees are deducted from the master balance. As with everything else in Tatum, it’s super easy to implement.
Custodial wallet.postman_collection.json
9KB
Binary
Postman collection

Generate new gas pump contract

The first step is to create a gas pump smart contract that will accept all the assets you want. We have multiple options and combinations, which can be used. Once you choose a setup, it can't be changed in the future. Supported features are:
    Accept native assets (ETH, CELO, MATIC, BSC, ONE) and ERC-20 tokens
    Accept native assets (ETH, CELO, MATIC, BSC, ONE) and ERC-721 tokens
    Accept native assets (ETH, CELO, MATIC, BSC, ONE) and ERC-1155 tokens
    Accept native assets (ETH, CELO, MATIC, BSC, ONE), ERC-20, and ERC-721 tokens
    Accept native assets (ETH, CELO, MATIC, BSC, ONE), ERC-20, and ERC-1155 tokens
    Accept native assets (ETH, CELO, MATIC, BSC, ONE), ERC-721, and ERC-1155 tokens
    Accept native assets (ETH, CELO, MATIC, BSC, ONE), ERC-20, ERC-721, and ERC-1155 tokens
All of these combinations can be enabled in a batch mode - it will be possible to transfer an unlimited amount of different tokens in 1 blockchain transaction atomically. Otherwise, you need to transfer the assets one by one. The more features you enable, the more gas you will pay for initial address creation.
Enough of the talk, let's generate one on the Polygon Mumbai testnet. We will enable all features by default.
Request
Response
1
curl --location --request POST 'https://api-eu1.tatum.io/v3/blockchain/sc/custodial' \
2
--header 'Content-Type: application/json' \
3
--header 'x-api-key: YOUR_API_KEY' \
4
--data-raw '{
5
"enableFungibleTokens": true,
6
"enableNonFungibleTokens": true,
7
"enableSemiFungibleTokens": true,
8
"enableBatchTransactions": true,
9
"chain": "MATIC",
10
"fromPrivateKey": "0x37b091fc4ce46a56da643f021254612551dbe0944679a6e09cb5724d3085c9ab"
11
}'
Copied!
1
{
2
"txId": "0x2979a3d30f812b0d9ebcc66d01b620d3779380c38e8770a82fa4ea4f2dfa8f69"
3
}
Copied!
As a result, we obtain transaction hash. From this hash, we can find the address of the contract - our custodial address.
Request
Response
1
curl --location --request GET 'https://api-eu1.tatum.io/v3/blockchain/sc/address/MATIC/0x2979a3d30f812b0d9ebcc66d01b620d3779380c38e8770a82fa4ea4f2dfa8f69' \
2
--header 'Content-Type: application/json' \
3
--header 'x-api-key: YOUR_API_KEY'
Copied!
1
{
2
"contractAddress": "0x4eC40a4A0dA042d46cC4529f918080957003b531"
3
}
Copied!
You can assign this address to your user. It is capable of accepting MATIC and any ERC-* tokens out of the box. You can take a look at our address on Mumbai Polygon explorer.

Transfer asset from a custodial address

Your user deposited some ERC-20 or ERC-721 tokens into his account. Now it's time to move assets to another address. You don't have to send any MATIC there to pay for gas, just say which assets should be sent, how much of them, and where. Let's send an ERC-721 token with a tokenId of 100 from the address.
Request
Response
1
curl --location --request POST 'https://api-eu1.tatum.io/v3/blockchain/sc/custodial/transfer' \
2
--header 'Content-Type: application/json' \
3
--header 'x-api-key: YOUR_API_KEY' \
4
--data-raw '{
5
"chain": "MATIC",
6
"contractType": 1,
7
"tokenId": "100",
8
"tokenAddress": "0x6d8eae641416B8b79e0fB3a92b17448CfFf02b11",
9
"custodialAddress": "0xA09Eee86868ECE1A44B57b1EEBEe4f40Df2Ed43D",
10
"recipient": "0x8cb76aEd9C5e336ef961265c6079C14e9cD3D2eA",
11
"fromPrivateKey": "0x37b091fc4ce46a56da643f021254612551dbe0944679a6e09cb5724d3085c9ab"
12
}'
Copied!
1
{
2
"txId": "0xa1bdc0008b6cce138cec38336a3cbbf1117cc56bcfe0004e14d6789a9d099b72"
3
}
Copied!
As a result, we obtain a transaction hash. As you can see, we have to enter the address of the token we want to transfer, and for an ERC-721, a tokenId as well. The contractType attribute is important, as it tells the wallet which kind of token it is transferring.
Since the transfer endpoint is universal and neither ERC-20 tokens nor native assets have tokenIds, this field can be omitted with transfers of such tokens. Similarly, for amount, ERC-721 tokens are always one-of-a-kind, so the amount is omitted. Native assets don't have contract addresses, so this field is omitted when they are transferred

Transfer assets from a custodial address in a batch call

Simple transfers are great, but batch transfers are much more powerful. In this operation, you can basically transfer all of the assets from an address in 1 transaction. You can define different recipients for different assets, you can split the balance of the ERC-20 token into 2 different recipients and many more.
We are transferring all types of assets we have in the custodial address in 1 call:
    contractType 0 - ERC-20 token
    contractType 1 - ERC-721 token
    contractType 2 - ERC-1155 token
    contractType 3 - native asset - MATIC
Request
Response
1
curl --location --request POST 'https://api-eu1.tatum.io/v3/blockchain/sc/custodial/transfer/batch' \
2
--header 'Content-Type: application/json' \
3
--header 'x-api-key: YOUR_API_KEY' \
4
--data-raw '{
5
"chain": "MATIC",
6
"contractType": [0,1,2,3],
7
"tokenId": ["0","100","1","0"],
8
"amount": ["0.001","0","1","0.009"],
9
"tokenAddress": [
10
"0x2d7882bedcbfddce29ba99965dd3cdf7fcb10a1e",
11
"0x6d8eae641416B8b79e0fB3a92b17448CfFf02b11",
12
"0x664F97470654e8f00E42433CFFC0d08a5f4f7BC7",
13
"0"
14
],
15
"custodialAddress": "0x4eC40a4A0dA042d46cC4529f918080957003b531",
16
"recipient": [
17
"0x8cb76aEd9C5e336ef961265c6079C14e9cD3D2eA",
18
"0x8cb76aEd9C5e336ef961265c6079C14e9cD3D2eA",
19
"0x8cb76aEd9C5e336ef961265c6079C14e9cD3D2eA",
20
"0x8cb76aEd9C5e336ef961265c6079C14e9cD3D2eA"
21
],
22
"fromPrivateKey": "0x37b091fc4ce46a56da643f021254612551dbe0944679a6e09cb5724d3085c9ab"
23
}'
Copied!
1
{
2
"txId": "0xc1e1b725d68a5e35d36121307d2365678ad9179411c1f59a2deac8a7080afffa"
3
}
Copied!
As a result, we again obtain transaction hash.
When the asset you want to transfer does not have tokenAddress or amount or tokenId, use 0 instead. We will take care of the rest for you.
To find out more about the API calls we have just used, visit our API Reference.
Last modified 22d ago