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.
Best Answer
The solution here will depend on whether there is a trusted actor (you?) who can look at the blockchain and work out how much everyone should receive, or whether the contract needs to be able to confirm the right dividend payment itself based on its own history.
In the former case, you have two options:
"Account 0xdeadbeef gets 1234 coins"
. Stick all the messages on your website. This signature will consist of 3 pieces of data, calledv
,r
ands
, plus the hash of the signed message. Send the chain the address that you're doing the signing with. Each user can send those pieces of the data to the contract, at which point it will check the signature withecrecover
to make sure the message was signed with the official signing address and credit them with the money that the message said they should receive.If you don't have a trusted actor, and the contract needs to be able to confirm who should get paid itself, then it's a bit harder. You have a couple of ways to do this:
Your contract keeps a history of each account as it goes, so that it can tell how much money it had at each date or block. Again, this is costly to do in storage, but you can make it somewhat cheaper with a hashed data structure: Each account starts with a hash of zero, then when they make a transaction, a record is created for the change, and hashed, together with the previous hash, and the resulting change is saved back over the last one. The user can then send data to replay this chain, and prove how much money they had at the dividend payment date. This allows you to apply dividends whenever you like, including based on dividend dates in the past. But you have to design it carefully to avoid situations where money becomes unclaimable because of gas costs. See this code for an example; It's not exactly a dividend payment, but it's a similar process.
Your contract knows the dividend date in advance, so it applies the dividend when you subsequently move funds, and records the fact that it has done it so that it won't do so again. So the contract knows that there is a dividend payable from future date X, and that it should be say 1% of holdings. As of the dividend date X, consider accounts are marked something like
Dividend X paid: "0xdeadbeef => false"
. Then when the0xdeadbeef
account next tries to withdraw funds, their balance will be credited with the dividend, and it markedtrue
. You also need to do something when receiving funds - for example, apply the dividend on the previous balance of the receiver, then mark the receiver record paid as well. The disadvantage with this is that it applies a gas cost on normal sends and receives, even once the dividend has been paid, and that cost grows if you have more dividends. You might want to put a deadline on how soon you have to collect the dividend before the contract considers it unclaimed and stops crediting it.