I'll split your question into several steps, as there is no simple way to fetch the data from the blockchain in the format you want, so you have to "walk a thorny path".
1. Get the list of Token Addresses owned by an Externally-Owned-Account
1.1 Query for Transfer
events
A token, or better to say - a contract, which implements the ERC20
interface, emits an event Transfer(address from, address to, uint256 amount)
Event every time the token transfer occurs. You can query the blockchain for the past events, where the to
is your target account. The event emitters are the contracts, possibly the ERC20
tokens, but also those could be the ERC721
tokens, as they have the same event signature in the interface.
Also notice, an event emitter could be any contract, even not related to tokens, as any contract can emit any event.
Some blockchain nodes could limit the block ranges per request to get the events from, so you have to implement the pagination, as you want to get events from block 0
to latest
1.2 Find out the ERC20
Tokens
You have here several options
a. You can create the list of known tokens from various 3rd party sources (CoinmarketCap, 1inch, Shushiswap, Uniswap) and then filter those Transfer
emitters narrowed to those from the known list.
b. Another option, is to fetch ERC20
interface Information directly from the blockchain. Call each Transfer
emitter by getting the decimals
, name
, symbol
, balanceOf
. If you don't get the exception for the calls, then the contract is highly likely the ERC20
token.
c. Or you can get the contracts ABI (if the contract is validated) from Etherscan, and check if everything from ERC20
interface exists in the ABI.
I have implemented all these steps in the 0xweb
cli tool, which uses the dequanto
library. You can check the implementation in CTokens.ts#L88
After these steps, you'll get the list of all tokens owned by the account, and their amounts (balanceOf
).
2. Get the token prices
Another challenging task, in case you don't use any 3rd party service and stick to onchain data.
a. Query the oracle price feeds like chain.link. But not all tokens are presented there.
b. Get the price directly from DEX, like uniswap, sushiswap, pancakeswap etc. But surprise - no easy way to get the price also here. You can find a stable pair (Some USD stable coin/Your Token), if the pair exists just grab the reserves and the ratio is the price. For less popular tokens there could be only the ETH/YourToken
pair, and the price for ETH
you can get these steps a)
or b)
.
I've written a more in-depth article: https://dev.kit.eco/ethereum-get-token-price-at-a-specific-block-onchain on how to get the price at any time in the past. And if you don't have the archive node, you just get the price for the latest
block.
If you want me to explain some parts in detail, don't hesitate to ask in the comments, I'll update the answer then.