Fast Khaki Raccoon
High
When adding or removing shares for tokens if one of them is paused it would cause all rewards, even the ones accumulated before the pause to be "bricked" for all users who claim during the pause.
Example would be _removeShares
function _removeShares(address _wallet, uint256 _amount) internal {
require(shares[_wallet] > 0 && _amount <= shares[_wallet], "RE");
_distributeReward(_wallet);
totalShares -= _amount;
shares[_wallet] -= _amount;
if (shares[_wallet] == 0) {
totalStakers--;
}
_resetExcluded(_wallet);
}
for we first call _distributeReward
and distribute for all not paused tokens
for (uint256 _i; _i < _allRewardsTokens.length; _i++) {
address _token = _allRewardsTokens[_i];
if (REWARDS_WHITELISTER.paused(_token)) {
continue;
}
uint256 _amount = getUnpaid(_token, _wallet);
rewards[_token][_wallet].realized += _amount;
rewards[_token][_wallet].excluded = _cumulativeRewards(_token, shares[_wallet], true);
if (_amount > 0) {
rewardsDistributed[_token] += _amount;
IERC20(_token).safeTransfer(_wallet, _amount);
emit DistributeReward(_wallet, _token, _amount);
}
}
but then trigger _resetExcluded and reset
rewards[_token][_wallet].excluded` for all tokens.
The diff in handling between _resetExcluded
and _distributeReward
when it comes to paused rewards
function _resetExcluded(address _wallet) internal {
for (uint256 _i; _i < _allRewardsTokens.length; _i++) {
address _token = _allRewardsTokens[_i];
rewards[_token][_wallet].excluded = _cumulativeRewards(_token, shares[_wallet], true);
}
}
for (uint256 _i; _i < _allRewardsTokens.length; _i++) {
address _token = _allRewardsTokens[_i];
if (REWARDS_WHITELISTER.paused(_token)) {
continue;
}
uint256 _amount = getUnpaid(_token, _wallet);
rewards[_token][_wallet].realized += _amount;
rewards[_token][_wallet].excluded = _cumulativeRewards(_token, shares[_wallet], true);
if (_amount > 0) {
rewardsDistributed[_token] += _amount;
IERC20(_token).safeTransfer(_wallet, _amount);
emit DistributeReward(_wallet, _token, _amount);
}
}
No response
No response
- Token A and B both accumulate 1 reward per share
- Alice has 100 shares and claims rewards for both tokens and her
rewards[token][Alice].excluded
are synced with the current rewards - B is then temporarily paused for some reason
- Bob claims rewards, however since B is paused he claims only for A
- Bob's
rewards[token][Alice].excluded
are both synced since_resetExcluded
does not have any way to handle paused tokens
function _resetExcluded(address _wallet) internal {
for (uint256 _i; _i < _allRewardsTokens.length; _i++) {
address _token = _allRewardsTokens[_i];
rewards[_token][_wallet].excluded = _cumulativeRewards(_token, shares[_wallet], true);
}
}
Users will lose on rewards. Tokens will be bricked.
No response
Include the same mechanic inside _resetExcluded
.