Get ETH & ERC20 token balances for multiple addresses in a single call

William O'Beirne
4 min readNov 6, 2018

TL;DR a slick contract and NPM package for efficient and fast balance checks. Scroll to the bottom to try it out and find the package.

A common task that has plagued wallet providers and block explorers since ERC20 tokens came out is fetching all of the value associated with a single address. With tokens included, you need to both call eth_getBalance , as well as balanceOf for each token. But what if I told you we could bundle those into a single call, and not just for a single address, but as many addresses as we want? And you can do so without having to run custom software, since it works on any Ethereum node? Let me explain.

Credits for this method go to DeltaBalances for the idea & Henry Nguyen for the final implementation

At ETHSanFrancisco this year, myself and a team of 3 others put together a chrome extension that keeps track of your addresses called Safu. One of the key features of the extension was it needed to to check all of the balances of all of your addresses, and fast.

Most applications’ approach for doing this so far has usually been to fire off dozens or hundreds of requests to a node, and fill in the balances as they come back. The more speed conscious developers may have even utilized JSON RPC’s batch spec, seeing as all of the main Ethereum clients support it. But that still wasn’t good enough for Safu, since we wanted to be showing all balances for multiple addresses at once, and we wanted it fast.

An underused trick to do this much faster, and much more efficiently is by using a smart contract. Most people only think of using smart contracts for their ability to store data, and handling the permissions around who can store and remove what. But you can actually make read-only contracts that perform useful functions for you that are completely stateless. So that’s exactly what we’ve got, a smart contract that fetches all of the desired balances for us. This is considerably faster, as we don’t have to waste time with HTTP round trips and clogging up a node’s available connections & threads. It’s all done internally in the EVM in one go. Here’s a comparison of the network requests between the old multi-request way, and the new contract way:

On the left, MyCrypto’s balance checker. On the right, our single contract request.

The code for this contract is deceptively simple. You simply have an array that, as you loop over every address and desired token, you append balances to it. The main function of it is embedded below, but you can find the full source code here.

You can find the full contract code here.

Demo & NPM Package

You can see a demo of it in action here. It’s using the contract above, wrapped in a handy web3.js & ethers.js compatible library that handles some of the input and output trickiness.

You can find the NPM package that powers the demo here, complete with code samples. The library also defaults to using a contract that’s already been deployed on mainnet, so there’s no need for you to deploy the contract yourself to get started using this today. It’s as simple as installing the package, and using one of two functions:

Check the readme in the package for more information.

…But There’s Always a Catch

There is an unexpected issue with using smart contracts as functions though, and that’s the block gas limit. Despite the fact that we’re making a read-only call that doesn’t require a transaction, the block gas limit is still taken into account, and calls that would exceed the limit of a single block get rejected.

The current block gas limit is around 8 million, and this function uses approximately 500,000 gas per 100 balances. So you should limit yourself to around 1,000 total balance calls (addresses * tokens) per contract method call to be safe. Even if you split balance checks into a few calls using this contract method, you’ll still be getting incredible time savings over splitting thousands of calls.

Special thanks to Aaron (Github), Henry (Github), and Daniel (Github, Twitter) for helping put together the Safu extension. Thanks to DeltaBalances for the original single-address balance contract implementation.

Sometimes my Twitter and Github accounts have stuff worth looking at too.

--

--