I created contract A which generates and sends my tokens. I would like to send some ether to each token holder from another contract B. So how to find all token holders from contract B?
3 Answers
There's some trickiness when sending ether to lots of recipients.
If you use address.send(), the send can fail if the recipient is a contract that consumes some gas, because send() only forwards a fixed amount of gas. So (a) you don't want to throw if send returns false, because it would block everybody, and (b) that recipient will never get the ether, no matter how much gas he includes.
The other way is to use address.call.value, which does forward all gas. But you don't want to use that in this situation because a contract that consumes all the gas will halt everything even if you don't throw upon failure. So if you insist on looping the sends, you have to use address.send() and ignore failures.
To make sure everyone can get their ether, have each recipient call a withdraw() method in your contract. Within that method, do whatever update you need to record the withdrawal, then say "if (!address.call.value(x)()) throw;". If the recipient doesn't include enough gas, everything gets rolled back and he can try again.
If you do this, you no longer have to worry about finding all token holders. This also prevents the problem of having so many people in the loop that you exceed the gas limit of the entire block.
But if you really want to loop and address.send, then you're going to need a data structure like this:
mapping(address => uint) public holders; //people's balances
mapping(uint => address) public indexes;
uint public topindex;
Every time you add a token holder, you increment topindex, put the new index and holder address in indexes, and the address and balance in holders. This is necessary because there's no native way to iterate through a mapping, which is because of the way the mapping is stored in the blockchain.
Anything marked "public" is accessible from other contracts.
Contract A would also have to call Contract B informing it every time a transfer has taken place.
having said that - you have a bigger problem which is, how does Contract B handle the ether that it receives, and when should it pay out. What happens to those people who did not originally have tokens, but acquired them later? Would they also receive Ether retrospectively?
-
2Also don't forget, contracts require gas. If you have a lot of token holders, you will not be able to send a transaction to all of them in one go because it will not fit into a block. This could potentially lock your contract up! Commented Jun 7, 2016 at 15:09
Getting all token holders of ERC-20 token contract is not currently feasible in EVM / smart contract due to heaviness this operation of all but trivial amount of token holders.
Build a list of token holders offchain
Upload this list to your token distribution smart contract or use any of other standard token distribution tools