Im trying to figure out the best way to automatically update balances in front end upon receiving and sending tokens. Ive tried creating an instance of a token in my react app, then creating an event listener and filter to listen to "Transfer" events going to and from my contract address, then it would run a function that updates the contract token balance and my wallet balance after spending gas on the transfer (my wallets ether balance is displayed in my UI). This way works when a user sends the token to the contract, but it doesn't keep track of how much each user sends. To keep track, I create an instance of the token in my contract, I added a transfer function which calls the transfer function of the token, it adds the balance to the addressToBalance mapping, and then emits an event. I tried listening for this event, but the problem is, I believe it emits the event before the token is actually transferred, is that right? so the event listener is triggered before the the token is transferred. Is there an "industry standard" way of doing this? My guess is listening to transfer events of the token contract is the most reliable, but you you have to be careful with filters an un subscribing, otherwise it gets triggered a thousand times. Any tips are appreciated!
it will be very taxing, on your browser resources, to list all balances of all holders and update them at the same time.
your bet is to show some balances and listen to the transfer event with a filtered topic based on each wallet address you are trying to update. if an event is fired for one wallet, you can call the token and get the new balance of that wallet. you should also do some sorting of events as you can easily have 2 transfers or more in the same block to the same address which would result in multiple useless balanceOf requests.
Im just keeping track of one token balance, but yes, i think youre right Aug 14, 2021 at 17:18
You have 2 options:
1- Use on-chain reads every x seconds, but batch all on-chain read requests using Maker's Multicall contract, or through a JS lib that abstracts Multicall like @pooltogether/etherplex. It's better to batch read calls to stay below your Infura or Alchemy API limits.
2- Leverage the power of The Graph protocol for on-chain data caching and indexing. The UI would basically use the Apollo GraphQL client to fetch data from your deployed subgraph by pooling every x seconds (Apollo supports polling).
thought about the graph, but my dapp is really simple, its a ui for chainlink. I only need to keep track of link tokens, so Im leaning towards just listening for transfer events from the link contract. your first suggestion i dont fully understand, but ill definitely look into it! Aug 14, 2021 at 17:16
@NolanJannotta Good thing about The Graph is that you won't have to worry about events emitted before the blocks they belong to are mined. If you implement the event listener login in the UI, you'll have to wait for event blocks to be mined before you update the UI. This could become resource intensive, and you would experience issues on some devices (i.e., mobile dapp browsers, for example). Or, you could just setup a timed task to read on-chain balances every x seconds. Aug 14, 2021 at 20:06
Got it. Ive been looking for a good time to learn the graph, I bet its a crucial skill for smart contract developers. Maybe nows the time! I think for now I made my dapp work with listening to events emitted from my contract, but I'm not sure how it will behave if more than one user is using the dapp at the same time. for example, would other users using the dapp trigger actions to happen in my UI? I might try adding more filters to my listeners to filter events only from the address logged in. Does using timed task every x seconds effect user experience? does it use a lot of resources? Aug 15, 2021 at 19:05
@NolanJannotta timed tasks could actually be a lot more manageable. It's a common approach for many dapps to do things that way, like Uniswap V2 for example. But you'll need to optimize by using Multicall and probably some React API libs like React Query, in case you're using React for the UI. Aug 15, 2021 at 21:56
you need to add
emit ... after transfer.