15

How hard is it to implement rewards into ERC20 Tokens? By this I mean a ERC20 Token that receives a reward in the form of Ether from a rewardAccount that is distributed evenly between all tokens.

After some basic searching I found this question:

How to send some ether to all token holders? https://ethereum.stackexchange.com/a/5811/3660

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.

The DAO had its own withdraw() method to allow DTHs to withdraw reward tokens:

Code from DAO.sol on Sock.it's DAO Github page

/// @notice Withdraw `_account`'s portion of the reward from `rewardAccount`
/// to `_account`'s balance
/// @return Whether the call was successful
 
 function withdrawRewardFor(address _account) internal returns (bool _success);

function getMyReward() noEther returns (bool _success) {
  return withdrawRewardFor(msg.sender);
}

Here is the withDrawRewardFor() Method/function code which mentions the rewardAccount http://pastebin.com/BuTZBWRU

So it seems that the two parts to get working correctly to have a ERC20 Token with Rewards is the rewardAccount (in the DAO, this was a ManagedAccount, which you can find on Slock.its DAO github page, ManagedAccount.sol) and the withdrawRewardFor() method.

Is this the best way to do it? Security issues? Anyone doing something similar?

2 Answers 2

4

This is non-trivial, although possible.

Architecture with a separate account isn't the problem per se. (The DAO had it to separate income from current holdings, as I understand it.) The main issue is that you can't simply iterate through every token holder, or you'll hit the block gas limit after enough token holders. (The question you linked to is about this.)

The pattern more commonly used, withdrawals, is where the user specifically asks for money, and at that time the contract pays them. While this makes sense in most situations, such as an auction contract where the users have individual balances, what does it mean if rewards accumulate to tokens? Is the reward calculated when the user withdraws, based on the time since last withdrawal? Then an attacker withdraws, sends tokens to another address, and repeats.

I am not sure exactly how the DAO avoided this, as I did not understand the math involved. Which leads to the following point.

Security-wise, there's all sorts of small mistakes that can lead to disaster. Notably, The DAO heist itself was due one such small mistake in this category... in withdrawRewardFor() as it happened.

The DAO had expert programmers and a paid security audit, and they still missed this. I would be incredibly cautious about this entire area. I'm not saying it's impossible, just risky.

2
  • Having the rewards accumulate is a good way to describe one way the rewards could work. Only the token holder can withdraw from the rewardAccount if they decide to. If they don't withdraw and then trade the token away, the next owner of the token would be able to withdraw what's in the tokens reward balance. Sep 23, 2016 at 2:16
  • 2
    An ERC20 token is tracked by an integer token balance for each account. How will the contract distinguish between tokens that have already been rewarded from the rest? There's ways, I'm sure, but they will prove complicated. You may be best reading the DAO's source and understanding it yourself, as this is, again, a risky area. Sep 23, 2016 at 18:58
0

I assume that for getting the reward users need to have tokens in their account (they should be holding the token). Then you could have the reward function to check the balance in the token contract. If the balance for a particular address is > 0 then it can withdraw.

You will need to create a mapping to register that a person (address) had or not withdraw the reward.

Use a mapping variable where you will record if a particular address already took its reward. If the person holds tokens and has not withdrawn the reward, then decrease the withdraw account (or the register that counts the available amount for withdraws) and only then, make the transfer from the reward account to the user account.

The issue I see in your approach is that the same address can withdraw several times as you do not check: 1. If the person requesting the reward holds token and 2. If the person already withdraw.

I hope this helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.