9

I need to allow users to deposit and extract ERC20 tokens in my service, and I'm wondering what's the best way of implementing that. My idea is to generate an account for each user, and when a user deposits, have that deposit forwarded to a main account with consolidated balances. When a user needs to withdraw, the amount is sent from the main account.

  1. Is this the best approach to store ERC20 tokens?

  2. How can I detect user deposits without calling the token contract (i.e. without spending gas)? I don't mind scanning the blockchain to see if there are deposits, however I'm not sure how I can detect them.

Thanks

1
  • Trying to do the same now and so far the best solution I found is creating a new account and immediately calling approve(mainWalletAccount, MAX_INT) ... then I can call transferFrom anytime to empty the deposit address into the mainWallet. The biggest problem is that calling approve requires gas so I have to send ETH to each deposit account. Have you figured a way around this? Commented Nov 6, 2017 at 23:04

2 Answers 2

4

My idea is ... when a user deposits, have that deposit forwarded to a main account with consolidated balances.

With this model, you're setting yourself up as an exchange; your users don't have the private key to the 'hot wallet' where all the tokens are stored, you do. And you'd then better have very thorough security to keep those funds safe that you're holding for them.

How can I detect user deposits without ... spending gas?

Using the web3.js utility, calling the web3.eth.call() command calls a method on a smart contract without using gas. Only methods that don't update the state of the blockchain can be used this way (others need to be called with web3.eth.sendTransaction() and use gas; related question).

So, you can manually query the smart contract to tell the current balance of a given address for that token.

To detect movements of tokens live, as they're happening, ERC20 tokens all emit a Transfer event when tokens are moved. Using web3.js's filtering options, you can query for just those events and get a callback when they happen


So, as to "is this the right way to do it", that depends on what you're actually doing with those tokens on your site. If your users are paying you in a certain token in exchange for some service that you offer on your site (they're losing ownership of the tokens, and the site is gaining them), with some additional option for them to be "paid" in tokens and withdraw them out, then the best way to handle that is for your site to present the incoming user with a (new) receiving address that your site has the private key for. Instruct the user to use the approve() method on the token contract to allow the receiving address to move some of their funds for them. When they indicate that's done, call the allowance() function to verify that's true. Then your website can call the transfer() function (will cost you a little gas) to move the user's tokens to itself.

However, if you're wanting to use a given token just as proof of membership on your site (the token is acting as shares in a company; the users are retaining ownership of them, and you're just tracking who's a known member), then your site just needs to gather address information from the incoming users (ask them to sign a message from their account), and use the balanceOf() function to check how much of a given token they have.

3
  • Thanks for replying. The user will definitely lose their tokens after transferring them to my service (that would be a "deposit"). The actual transfer should be out of scope, meaning the user will be provided with an account and they should make sure their tokens end up there somehow. The main aspect of question 1 is whether the forwarding I propose makes sense or there's a better alternative (one that doesn't use any gas when the user deposits).
    – Paul
    Commented Jun 27, 2017 at 19:51
  • If a user's not using gas when they "do something", then whatever that something is, it cannot modify the state of the blockchain (stateless actions are the only type that can be zero gas). Since you say you want them to actually lose ownership of the tokens and you to gain ownership, that's modifying state, so gas will have to be spent by the user. Your contract for monitoring when a transaction has happened can do that without gas (monitoring for Transfer events). Commented Jun 28, 2017 at 19:08
  • And beware allowing the "they make sure their tokens end up there somehow". If the current owner of the tokens is a multi-sig address, the transaction to move the funds from their ownership to your ownership may be hard to detect. Best way is to have a separate receiving address for each new user. Wait for the funds to get there (by whatever means the user wants), and then if you want to consolidate them later, sweep them after it's confirmed. Commented Jun 28, 2017 at 19:13
5

It may require some user training, but here's a possible way using transferFrom():

  1. Have the user call approve() on the token contract, giving your contract the right to withdraw X tokens from their balance.
  2. Have the user call your contract, which calls transferFrom() on the token contract to get X said tokens. You can then immediately do whatever logic in your contract to keep track of user balances. (A mapping, for a simple example.)

Note that this scheme fails if a user haplessly uses the normal transfer method, since your contract wouldn't be called. It's possible you could find a way to keep accidental transfers like this separate, and send them back manually.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.