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.
Transferring tokens is basically to change the entries in a variable in the token contract. This means that there is nothing actually moved.
Assume a user with address A, a token contract B and another contract (yours) with address C.
If A decides to sent x tokens to your contract C what happens is that a transaction is sent to B. B has a mapping with the balances of all the users, and subtract x tokens from the balance of A and adds x tokens to the balance of C. This means that C never get to know that a transfer of x tokens was sent to it.
This is why you can't forbid tokens to be sent to your contract because transferring tokens to your contract do not involve your contract at all.
However, there is an option. ERC20 standard implements a function approveAndCall
which allows users (for instance A) to approve your contract (C) to move x amount of tokens from their balance in (B). This function will actually call your contract and you will see the address of the token. If the call is from your token contract you can just transfer from the x tokens to you contract using transferFrom
and execute your code. If the call is from another contract you just revert.
For the rest, if someone does normal transactions to your contract, you do not need to worry, your contract will will never know.
Hope this helps.
Best Answer
All token transfers are performed by calling methods on your contract - so your contract can track balances and accounts in any way it wishes. If you're using the default arrangement of using a Solidity
mapping
, you will also need to keep a separate list of known account IDs in an array, so you can iterate over them.