ERC20 Transfer but Gas paid by other address

As an exchange, we have one master Ethereum wallet address that is updated every 24 hours. For ERC20, we have hit a road block. We want all ERC20 token of all user to be transferred to Admin wallet after N number of confirmations. However, most of the users may not have ETH balance so the transfer fails.

We are trying to implement a system, were Gas is deducted from our Admin wallet and ERC20 token are transferred from user’s wallet to our Admin wallet. How can we achieve that ?

We have already tried Approve method in Web3J, it results a txHash, but still transfer fails with insufficient Gas error.

Hello, @Kevin_Thakker

It is by design that ERC20 can only be transferred through a user action. The owner of the token must either transfer or approve someone else to transfer.

It the owner is a smartwallet, that support meta-tx, then you have a solution there, but in the general case where the owner is an EOA, you have no simple generic solution.

Some ERC20 include the Permit function. This allows the user to sign a message that someone else can relay to approve (or to transfer) tokens. This would like what you need, but is only available in some rare ERC20. If the token doesn’t include that feature, you can’t do anything about it.

I am wondering what big exchanges like Binance and Bitfinex are doing then. I am sure they won’t be managing millions of individual’s user’s balance.

Centralized Exchanges (Binance, Coinbase, Whitebit, Gate, etc.) use their own wallets. They use a centralized server to manage who owns what.

Binance has a lot of different wallets that stores multiple users amounts in each wallet.

It is not decentralized.

1 Like

That’s sxactly what we are doing. We are using centralized wallet, running our own ETH node.

Yes, and you have a server or backend keeping up with all accounts and their token amounts right?
Centralized Exchanges are using databases to keep track of what account owns what.
When buys and sells happen on their order book, no ERC20 transfer is actually occurring. They just update amounts in their database.

Yes. That’s what we do. But let’s say we have 10,000 users, each of them deposits USDT ERC20 in their wallet. We update their balance accordingly in our DB. But letst say 500 users use their USDT to buy BTC. we again update our DB. So in DB their USDT balance is zero. But their actual wallet still has USDT.

Now, the other 500 users who sold their BTC, will want to withdraw their USDT. Now, if we dontt have one central wallet, we have to withdraw USDT from 500 users who bought BTC with their USDT. That’s 500 transaction.

Getting me ?

They would have to deposit their USDT into your wallet.
For Centralized Exchanges they have deposit addresses.

So for your case, you would need your users to deposit their USDT to you so you can update that amount in your database.

No. Unlike Bitcoin, eth doesn’t have account system. If we take every deposit in our wallet, we never know which deposit belong to which user. Imagine 50 ERC20 token listed and 10,000+ users doca deposit.

Wallet address will have to be unique for every user.

We hold PK of every wallet, so basically user’s wallets are also our own wallet.

But you will because your database needs to track it. When you deposit something to a CEX you are depositing to an address (and memo code depending on the token) they give you. When the deposit comes in, CEX are crediting the account in CEX database.

Imagine 50 ERC20 token listed and 10,000+ users doca deposit.

Yes and every time they deposit, your front end will give them an address (and memo code) to deposit into. On the backend you are keeping track who deposits what, when, where, amount, etc.

We hold PK of every wallet, so basically user’s wallets are also our own wallet.

That is extremely scary. I can only hope that they understand they do not own their wallet and should only use it when trading on your platform.

As a solution I recommend creating a deposit wallet, and not allowing users to know this private key. This is your exchange's wallet. You control their funds. When they want to withdraw, you let them create a withdrawal request to their wallet. You take a little off the top as a fee for the transfer and your service.

It’s not scary that’s how centralized exchange work. Binance doesn’t give PK to wallets, do they ?

Are they your user’s wallets or your wallets?

We hold PK of every wallet, so basically user’s wallets are also our own wallet.

An account is not the same thing as a wallet.
On Binance the user does not have the Private Key to the wallet they use on Binance, thus it is not the user’s wallet.

If you do not allow them access to their wallet, then you should be fine as you own the USDT in their wallet and they have no access to it. Just keep up with it in your database.

I think the solution is a replanning of how you are keeping track of accounts and their values.
If it was me I would do exactly as Binance does. They create a deposit wallet and use that deposit wallet among many different accounts. Every account created doesn’t get a single wallet.

I guess I failed to explain you. Yes, we are centralized exchange just like Binance. So every user will have a unique Ethereum address for all his ETH and ERC20 transactions. We generate this address offline using ECKeypair and store address an PK safely.

Let’s say you register on our exchange, click deposit, and then transfer 100USDT from Binance to our exchange. you use this 100USDT to buy Bitcoin. We updated our local DB with USDT=0 and BTC=0.0001

I am the one you bought BTC from, as exchange my DB balance will be 100USDT and BTC=0. I click on Withdraw and enter 100USDT withdrawal amount. After fees, my withdrawal will be let’s say 99USDT.

On the back-end, exchange doesn’t have any USDT balance in it’s main wallet. It is still in your wallet on the blockchain (NOT DB). Repeat this scenario for thousands of users doing multiple withdrawal.

For ethereum, we have a logic implemented that transfers ETH from user’s wallet to our master wallet after X confirmation. So ETH withdrawals are processed from our master Wallet only. But that’s not possible with ERC20. Because if we want to transfer ERC20 from your wallet after X confirmation to our exchange master wallet, your wallet should have some ETH to cover the gas fees, which you don’t have.

When I say your wallet, it is basically exchange wallet created unique for each user.

Am I making sense ?

This is not how centralized exchanges like Binance work, as far as I know. They only have master wallets, and user's funds are in those master wallets.

I assume that in your exchange it's a design goal for the user's funds to be in a separate wallet. This is interesting, but will definitely present a challenge. You use approve, and you may be able to pay for the transaction using Flashbots?

If you create two different account on Binance and then generate a new address for ERC20, you’ll notice both addresses are unique. So I am sure, not every user gets the same wallet address on Binance or on any other exchange. It’s just that they move their funds to master wallet once a deposit is confirmed. Or they have their own smart contract that manages parent and child addresses. But every user having same wallet address is not possible.

Yes definitely. The address for deposit has to be different for every user, but from there I assume it's moved.

Yes. Now you understand. While moving from user’s wallet to exchange wallet, gas has to be paid by sender which is user. Now user doesn’t have ETH to pay gas fees. This is where we are stucked.

Ah, okay. I understand now.

I don’t know how exchanges actually do it.

I would try using a “factory” contract that uses create2 to be able to sweep funds from deterministic addresses, by temporarily creating a contract that moves the funds to the master wallet and then selfdestructs. You can calculate the address by generating a salt, have the user deposit funds to that address, and then sweep from it using your “factory” contract. You can even batch multiple of these sweeps in the same transaction.

Not sure if i am going to get a reply 2 years later. :grinning:
Anyway I understand exactly what you were asking because I am attempting to do the same.

Essentially the back story/context :

  1. User creates an account via the app; the app in turn dynamically generates a wallet via API. The user has no control over the account (wallet) except through the app. Basically the user has no access to the PK or the mnemonic.
  2. User can deposit ERC20 tokens into the account address assigned to him. We update the balance in the db when ERC20 tokens are deposited into the account (wallet) and the user can see the balance on the UI - which is retrieved from the db.
  3. Meanwhile we need to transfer the deposited ERC20 tokens to an "admin" wallet from the users deposit account (wallet). But the user wallet has no Eth to fund the transfer transaction.

So one solution is that

  1. We dynamically estimate the gas required to effect the transfer transaction; buffer it by say 10% and then transfer the required eth to the user account (wallet) from say the admin wallet.
  2. Then we transfer the ERC20 tokens from the user account (wallet) to the admin wallet.

This is a lossy and messy affair; if gas prices are volatile we may end up

  • underpaying (which means we will have to retry the transfer transaction with the same nonce (leads to underpriced replacement errors) or Cancel the transaction and try again.
  • or overpaying which means we will leave dust lying in the user account (wallet)

Either way its an inefficient solution. Further the app would like to cater to a variety of ERC20 tokens which may or may not have permit functionality. Cant let that determine the choice of token.

Hence the question - is there any way another wallet can pay for the transactions of a wallet assuming that the PK of both wallets are available.

Hoping to get an innovative reply :grinning:!
Thanks