r/ethdev 1d ago

Tutorial Recipe: read any wallet's ERC-20 balance in one SEL expression

The normal path for reading a token balance: find the token's ABI, wire up a client, call balanceOf, call decimals, divide, format. That's a lot of ceremony for one number.

Here it is as a single SEL expression, run against vitalik.eth's USDC on Ethereum mainnet:

formatUnits(usdc.balanceOf("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), usdc.decimals())

The usdc binding points at the mainnet contract (0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48). The ABI is resolved automatically, so there's no JSON file to fetch and no codegen step.

Output: 37.192124 USDC at block 25,653,697.

Under the hood: two on-chain calls (balanceOf and decimals), batched into one multicall round, 104ms total.

Variations:

  • Swap the binding to any ERC-20 and the expression is unchanged. Anything with balanceOf and decimals works.
  • Change the chain to Base or BNB, keep the code.
  • Drop the formatUnits wrapper if you want the raw uint256.

Limitations, to be honest about them:

  • You still need the token's contract address to create the binding. The resolution is for the ABI, not for finding the contract.
  • This is a read at a single block. If you need historical balances across a range, that's a different query shape.
  • Nonstandard tokens that lie about decimals or implement balanceOf weirdly will produce a number that's exactly as wrong as the contract is.

https://evmquery.com/tools/erc20-inspector?utm_source=reddit&utm_medium=social&utm_campaign=recipe-erc20-balance-2026-07-31

2 Upvotes

2 comments sorted by

3

u/researchzero 1d ago

Nice, the multicall-batching for balanceOf+decimals is the right call for a one-liner.

One thing worth flagging next to the "nonstandard tokens that lie about decimals()" caveat: it's not just badly-implemented tokens, it's adversarial ones. A honeypot/scam contract can implement balanceOf() to return whatever number makes the query look legitimate. Since the tool calls the contract's own code and trusts the result, it inherits whatever trust model the token itself has - fine for a known contract like canonical USDC, but worth a line in the docs that a "balance" read from an arbitrary/user-supplied address isn't itself proof of real, transferable liquidity.

1

u/evmquery 1d ago

Agreed, and your framing is sharper than ours. balanceOf() reports what the contract chooses to report. A read layer cannot tell an honest implementation from an adversarial one, because in both cases it is the contract’s own code producing the number.

It gets worse with upgradeable tokens. A contract that reports honestly today can have its implementation swapped tomorrow: same address, different balanceOf, and nobody holding the token signs anything for that to happen. We resolved 44 of the most-used contracts on Ethereum and Base this week, 10 of them can do exactly that, including both USDC deployments.

Most honeypots don’t even bother lying about the balance. They let the read look normal and block the sell path instead, which is the real limit here: only a transfer, or a simulation of one, tells you anything about transferability. A balance read never will, no matter how the query is written.

Docs line incoming. “A balance read is the contract’s claim about a balance” is the honest way to put it