You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Mar 3, 2024. It is now read-only.
sherlock-admin opened this issue
Aug 30, 2023
· 0 comments
Labels
DuplicateA valid issue that is a duplicate of an issue with `Has Duplicates` labelMediumA valid Medium severity issueRewardA payout will be made for this issue
Users are unable to withdraw from LMPVault if the accumulated TOKE rewards are below the MIN_STAKE_AMOUNT threshold
Summary
Staking TOKE rewards in the GPToke staking contract potentially reverts if the token rewards for a given user are below the MIN_STAKE_AMOUNT threshold. This prevents affected users from withdrawing funds from the LMPVault vault.
Vulnerability Detail
Whenever LMPVault shares are transferred (e.g., burned when withdrawing), the LMPVault.beforeTokenTransfer function is called, which internally withdraws and unstakes from the associated rewarder contract in line 844:
834: function _beforeTokenTransfer(addressfrom, addressto, uint256amount) internalvirtualoverride whenNotPaused {
835: // Nothing to do really do here836: if (from == to) {
837: return;
838: }
839:
840: // If this isn't a mint of new tokens, then they are being transferred841: // from someone who is "staked" in the rewarder. Make sure they stop earning842: // When they transfer those funds843: if (from !=address(0)) {
844: rewarder.withdraw(from, amount, true);
845: }
846:
847: // Make sure the destination wallet total share balance doesn't go above the848: // current perWalletLimit849: if (balanceOf(to) + amount > perWalletLimit) {
850: revertOverWalletLimit(to);
851: }
852: }
However, the GPToke.stake function, specifically, the _stake function enforces a minimum stake amount of MIN_STAKE_AMOUNT and reverts if the amount is below this threshold in line 103:
098: function _stake(uint256amount, uint256duration, addressto) internal whenNotPaused {
099: //100: // validation checks101: //102: if (to ==address(0)) revertZeroAddress();
103: if (amount < MIN_STAKE_AMOUNT) revertStakingAmountInsufficient();
104: if (amount > MAX_STAKE_AMOUNT) revertStakingAmountExceeded();
... // [...]126: }
Affected users are the ones that have a small position in the LMPVault vault and thus have little accumulated rewards, or users wanting to withdraw from the LMPVault vault before having sufficient accumulated TOKE reward. In either case, the withdrawal attempt will revert, leaving the user unable to withdraw funds. The user would have to wait until the accumulated rewards are sufficient to meet the MIN_STAKE_AMOUNT threshold to be able to finally withdraw.
Impact
Users with either little or no TOKE rewards accumulated so far are unable to withdraw from the LMPVault vault.
354: function _getReward(addressaccount) internal {
355: Errors.verifyNotZero(account, "account");
356:
357: uint256 reward =earned(account);
358: (IGPToke gpToke, addresstokeAddress) = (systemRegistry.gpToke(), address(systemRegistry.toke()));
359:
360: // slither-disable-next-line incorrect-equality361: if (reward ==0) return;
362:
363: rewards[account] =0;
364: emitRewardPaid(account, reward);
365:
366: // if NOT toke, or staking is turned off (by duration = 0), just send reward back367: if (rewardToken != tokeAddress || tokeLockDuration ==0) {
368: IERC20(rewardToken).safeTransfer(account, reward);
369: } else {
370: // authorize gpToke to get our reward Toke371: // slither-disable-next-line unused-return372: IERC20(address(tokeAddress)).approve(address(gpToke), reward);
373:
374: // stake Toke375: gpToke.stake(reward, tokeLockDuration, account);
376: }
377: }
Tool used
Manual Review
Recommendation
Consider checking in the AbstractRewarder._getReward function if the accumulated amount of TOKE rewards is sufficient to meet the MIN_STAKE_AMOUNT threshold before attempting to stake the rewards in the GPToke contract. If the amount is lower, the rewards should be transferred to the user's address instead of staking them in the GPToke contract.
sherlock-admin2
changed the title
Nice Maroon Frog - Users are unable to withdraw from LMPVault if the accumulated TOKE rewards are below the MIN_STAKE_AMOUNT threshold
berndartmueller - Users are unable to withdraw from LMPVault if the accumulated TOKE rewards are below the MIN_STAKE_AMOUNT threshold
Oct 3, 2023
Sign up for freeto subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Labels
DuplicateA valid issue that is a duplicate of an issue with `Has Duplicates` labelMediumA valid Medium severity issueRewardA payout will be made for this issue
berndartmueller
high
Users are unable to withdraw from
LMPVault
if the accumulatedTOKE
rewards are below theMIN_STAKE_AMOUNT
thresholdSummary
Staking
TOKE
rewards in theGPToke
staking contract potentially reverts if the token rewards for a given user are below theMIN_STAKE_AMOUNT
threshold. This prevents affected users from withdrawing funds from theLMPVault
vault.Vulnerability Detail
Whenever
LMPVault
shares are transferred (e.g., burned when withdrawing), theLMPVault.beforeTokenTransfer
function is called, which internally withdraws and unstakes from the associated rewarder contract in line 844:The
MainRewarder.withdraw
function calls theAbstractRewarder._getReward
function and attempts to claim the accumulated rewards for the user. In the case of theLMPVault
, therewardToken
is most probably theTOKE
token, thus the accumulatedTOKE
rewards will be intended to be staked in theGPToke
contract by calling theGPToke.stake
function in line 375.However, the
GPToke.stake
function, specifically, the_stake
function enforces a minimum stake amount ofMIN_STAKE_AMOUNT
and reverts if the amount is below this threshold in line 103:src/staking/GPToke.sol#L103
Affected users are the ones that have a small position in the
LMPVault
vault and thus have little accumulated rewards, or users wanting to withdraw from theLMPVault
vault before having sufficient accumulatedTOKE
reward. In either case, the withdrawal attempt will revert, leaving the user unable to withdraw funds. The user would have to wait until the accumulated rewards are sufficient to meet theMIN_STAKE_AMOUNT
threshold to be able to finally withdraw.Impact
Users with either little or no
TOKE
rewards accumulated so far are unable to withdraw from theLMPVault
vault.Code Snippet
src/rewarders/AbstractRewarder.sol#L375
Tool used
Manual Review
Recommendation
Consider checking in the
AbstractRewarder._getReward
function if the accumulated amount ofTOKE
rewards is sufficient to meet theMIN_STAKE_AMOUNT
threshold before attempting to stake the rewards in theGPToke
contract. If the amount is lower, the rewards should be transferred to the user's address instead of staking them in theGPToke
contract.Duplicate of #565
The text was updated successfully, but these errors were encountered: