Unable to withdraw extra rewards
Suppose Bob only has 9999 Wei TOKE tokens as main rewards and 100e18 DAI as extra rewards in this account.\\nWhen attempting to get the rewards, the code will always get the main rewards, followed by the extra rewards, as shown below.\\n```\\nFile: MainRewarder.sol\\n    function _processRewards(address account, bool claimExtras) internal {\\n        _getReward(account);\\n\\n        //also get rewards from linked rewards\\n        if (claimExtras) {\\n            for (uint256 i = 0; i < extraRewards.length; ++i) {\\n                IExtraRewarder(extraRewards[i]).getReward(account);\\n            }\\n        }\\n    }\\n```\\n\\nIf the main reward is TOKE, they will be staked to the `GPToke` at Line 376 below.\\n```\\nFile: AbstractRewarder.sol\\n    function _getReward(address account) internal {\\n        Errors.verifyNotZero(account, "account");\\n\\n        uint256 reward = earned(account);\\n        (IGPToke gpToke, address tokeAddress) = (systemRegistry.gpToke(), address(systemRegistry.toke()));\\n\\n        // slither-disable-next-line incorrect-equality\\n        if (reward == 0) return;\\n\\n        rewards[account] = 0;\\n        emit RewardPaid(account, reward);\\n\\n        // if NOT toke, or staking is turned off (by duration = 0), just send reward back\\n        if (rewardToken != tokeAddress || tokeLockDuration == 0) {\\n            IERC20(rewardToken).safeTransfer(account, reward);\\n        } else {\\n            // authorize gpToke to get our reward Toke\\n            // slither-disable-next-line unused-return\\n            IERC20(address(tokeAddress)).approve(address(gpToke), reward);\\n\\n            // stake Toke\\n            gpToke.stake(reward, tokeLockDuration, account);\\n        }\\n    }\\n```\\n\\nHowever, if the staked amount is less than the minimum stake amount (MIN_STAKE_AMOUNT), the function will revert.\\n```\\nFile: GPToke.sol\\n    uint256 public constant MIN_STAKE_AMOUNT = 10_000;\\n..SNIP..\\n    function _stake(uint256 amount, uint256 duration, address to) internal whenNotPaused {\\n        //\\n        // validation checks\\n        //\\n        if (to == address(0)) revert ZeroAddress();\\n        if (amount < MIN_STAKE_AMOUNT) revert StakingAmountInsufficient();\\n        if (amount > MAX_STAKE_AMOUNT) revert StakingAmountExceeded();\\n```\\n\\nIn this case, Bob will not be able to redeem his 100 DAI reward when processing the reward. The code will always attempt to stake 9999 Wei Toke and revert because it fails to meet the minimum stake amount.
To remediate the issue, consider collecting TOKE and staking it to the `GPToke` contract only if it meets the minimum stake amount.\\n```\\nfunction _getReward(address account) internal {\\n    Errors.verifyNotZero(account, "account");\\n\\n    uint256 reward = earned(account);\\n    (IGPToke gpToke, address tokeAddress) = (systemRegistry.gpToke(), address(systemRegistry.toke()));\\n\\n    // slither// Remove the line below\\ndisable// Remove the line below\\nnext// Remove the line below\\nline incorrect// Remove the line below\\nequality\\n    if (reward == 0) return;\\n\\n// Remove the line below\\n    rewards[account] = 0;\\n// Remove the line below\\n    emit RewardPaid(account, reward);\\n\\n    // if NOT toke, or staking is turned off (by duration = 0), just send reward back\\n    if (rewardToken != tokeAddress || tokeLockDuration == 0) {\\n// Add the line below\\n  rewards[account] = 0;\\n// Add the line below\\n  emit RewardPaid(account, reward);\\n        IERC20(rewardToken).safeTransfer(account, reward);\\n    } else {\\n// Add the line below\\n     if (reward >= MIN_STAKE_AMOUNT) {\\n// Add the line below\\n   rewards[account] = 0;\\n// Add the line below\\n   emit RewardPaid(account, reward);\\n// Add the line below\\n\\n            // authorize gpToke to get our reward Toke\\n            // slither// Remove the line below\\ndisable// Remove the line below\\nnext// Remove the line below\\nline unused// Remove the line below\\nreturn\\n            IERC20(address(tokeAddress)).approve(address(gpToke), reward);\\n\\n            // stake Toke\\n            gpToke.stake(reward, tokeLockDuration, account);\\n// Add the line below\\n  }\\n    }\\n}\\n```\\n
There is no guarantee that the users' TOKE rewards will always be larger than `MIN_STAKE_AMOUNT` as it depends on various factors such as the following:\\nThe number of vault shares they hold. If they hold little shares, their TOKE reward will be insignificant\\nIf their holding in the vault is small compared to the others and the entire vault, the TOKE reward they received will be insignificant\\nThe timing they join the vault. If they join after the reward is distributed, they will not be entitled to it.\\nAs such, the affected users will not be able to withdraw their extra rewards, and they will be stuck in the contract.
```\\nFile: MainRewarder.sol\\n    function _processRewards(address account, bool claimExtras) internal {\\n        _getReward(account);\\n\\n        //also get rewards from linked rewards\\n        if (claimExtras) {\\n            for (uint256 i = 0; i < extraRewards.length; ++i) {\\n                IExtraRewarder(extraRewards[i]).getReward(account);\\n            }\\n        }\\n    }\\n```\\n