I will first explain the steps that you need to do to get the list of token holders. This applies to any language so you can recreate this on your own if you don't use Python. Then I will present my opinionated solution in Python that connects to Infura and explain how it works.
My approach gets you the exact same result as Etherescan's token holders page.
To get the list of token holders, you will do:
1. Get all the
Transfer events from your contract.
For that you need your contract address. Go to Etherscan Tokens page and search for your token, mine was this one so my address is
A short lesson in Ethereum: every ERC20 compatible token should emit a
Transmit event (also called a log) whenever this token is sent from one address to another (example).
You can search for all the
Transmit events through the JSON RPC interface of any Ethereum node that you have access to. Since I don't currently run an Ethereum node, I connected to a node from Infura. You search for logs by using the
eth_getlogs RPC function.
When you search for logs, you don't want all the logs, you only want the
Transmit logs. The magic string here is
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef so you filter all the logs by this topic. Why exactly this string is a bit out of scope for this, but you can read more about events and topics here in the Solidity Docs and in this tutorial that shows how this magic string is done.
To speed up searching it's best if you limit your search to blocks that happened when the contract was deployed or later. For me that was block
5857657, which translates to hex
Finally, I can call the RPC method
eth_getLogs on Infura using the parameters contract
2. Parse the events
Ethereum's logs are not straightforward so we need to parse them. If you check one log, there is information about the from address, to address and the token amount, but it's all encoded so you need to know where to look. Check this log entry for example:
The from address is the second topic and the to address is the third topic. The amount of tokens transferred is in
data. Again, you'll have to refer to how Ethereum handles topics and data to understand why this is and how it relates to the
You parse it like this:
* Hex decode the
data to get the amount of tokens transferred. Note that you'll have to move the decimal point by the
decimals of the token, in my case 18.
* To get the from and to addresses just take the last 40 characters of a topic and prepend it with
3. Compute balances
Make a list of all the addresses found in these events and process all the events by adding the token amount to the
to address and subtracting it from the
from address. At last just throw out all the addresses with a zero balance.
My Python solution is here. A few comments:
- I'm using the
requests library to call the JSON RPC on Infura.
- I'm using
Decimal because it's better than
float for financial computation.
- I call it like this:
from ethereum import *
contract = "0x83e2be8d114f9661221384b3a50d24b96a5653f5"
transfers = get_contract_transfers(contract, from_block="0x596179")
balances = get_balances_list(transfers)