I want to distribute dividends to all token holders.
They would have to call claimDividend
themselves, because of gas limitations.
How can you stop them from then transferring their tokens to another account and claiming more dividends?
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, called v
, r
and s
, 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 with ecrecover
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 the 0xdeadbeef
account next tries to withdraw funds, their balance will be credited with the dividend, and it marked true
. 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.