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?
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.