Contract Development – How to Distribute Dividends Efficiently

contract-development

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?

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:

  • Send the data of appropriate dividend payment to the chain, based on the state at the payout date, saying how much each account should get. But instead of sending all that data to the chain and putting it in storage, which will cost you gas, arrange the data in a merkle tree or a similar hashed data structure, and just send the root hash to the chain. People claiming will have to send the hashes leading up to the root, which will allow the contract to confirm that their payment is in the tree, and send them the money.
  • Calculate the amounts that need to be paid, but instead of sending anything to the chain, just sign a load of data. For each recipient, sign a message with an Ethereum key saying something like, "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.

Related Topic