Getting a list of ERC20 token holders in solidity

7.3k views Asked by At

Is it possible to get a list of token holders for a given ERC20 token from within another solidity contract?

Since "balances" are stored in a mapping in most ERC20 contracts, I do not think it is possible, since you can't get a list of keys for a mapping in solidity.

Is there anything I missed? Or is this just impossible?

Thanks!

3

There are 3 answers

0
Divyasshree On

You could try using an on-chain indexer that has token holder data.

Bitquery, for example, has an API for token holders that provides information on holders, their holdings, top holders, and other details.

Here's an example. This query gives you top holders for USDT You can run it here.

query MyQuery {
  EVM(dataset: archive, network: eth) {
    TokenHolders(
      date: "2023-10-29"
      tokenSmartContract: "0xdAC17F958D2ee523a2206206994597C13D831ec7"
      orderBy: {descending: Balance_Amount}
      limit: {count: 10}
    ) {
      Balance {
        Amount
      }
      Holder {
        Address
      }
      Currency {
        Name
      }
    }
  }
}

enter image description here

2
Shane Fontaine On

It is not possible to get a list of ERC20 token holders directly from a contract.

You are correct in that you cannot do this because you cannot get a list of keys for a mapping in Solidity, therefore it is impossible without external intervention.

With that said, there are many people who need this functionality and perform tasks to achieve this. The biggest example I can think of is airdropping tokens to various accounts based on their holdings of another token. The way that most people do this is to read all of the token holders from the blockchain and store it in a local database. From there, they will implement a gas-efficient function that takes in the addresses as a parameter and performs actions on them that way.

It is not possible to accomplish what you desire using only the blockchain, but using a combination of on-chain/off-chain logic can achieve your goals.

0
LEON On

It maybe possible. If you make a function that can pick sender and receiver when transfer function is called, it's possible.

mapping(address => bool) _holderList;

function transferFrom(address from, address to, uint256 amount) {
    checkHolderList(from);
    checkHolderList(to);
    _transfer(from, to, amount);
}

function checkHolderList(address _address) {
    require(balanceOf(_address) > 0, "this address can't be holder");
    require(_holderList[address] != true, "this address is already in holder list");
    _holderList[_address] = true;
}