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 Jan 12, 2025. It is now read-only.
DuplicateA valid issue that is a duplicate of an issue with `Has Duplicates` labelMediumA Medium severity issue.RewardA payout will be made for this issue
The lockMultiplier can be decreased unexpectedly by renewLockPosition.
Summary
After MlumStaking.sol#createPosition(), the lockMultiplier is not decreased when addToPosition(), renewLockPosition() and extendLockPosition() are called individually unless multiplier settings are not changed.
And in addToPosition(), the lockMultiplier is not decreased but lockDuration can be decreased.
And in renewLockPosition(), lockMultiplier is calculated from lockDuration.
So if a user calls through addToPosition() => renewLockPosition(), lockMultiplier can be decreased unexpectedly so amountWithMultiplier is decreased and less rewards are distributed to the user.
Vulnerability Detail
MlumStaking.sol#createPosition() function is as follows.
function createPosition(uint256amount, uint256lockDuration) externaloverride nonReentrant {
// no new lock can be set if the pool has been unlockedif (isUnlocked()) {
require(lockDuration ==0, "locks disabled");
}
_updatePool();
// handle tokens with transfer tax
amount =_transferSupportingFeeOnTransfer(stakedToken, msg.sender, amount);
require(amount !=0, "zero amount"); // createPosition: amount cannot be null// mint NFT position tokenuint256 currentTokenId =_mintNextTokenId(msg.sender);
// calculate bonuses370uint256 lockMultiplier =getMultiplierByLockDuration(lockDuration);
371uint256 amountWithMultiplier = amount * (lockMultiplier +1e4) /1e4;
// create position
_stakingPositions[currentTokenId] =StakingPosition({
initialLockDuration: lockDuration,
amount: amount,
rewardDebt: amountWithMultiplier * (_accRewardsPerShare) / (PRECISION_FACTOR),
lockDuration: lockDuration,
startLockTime: _currentBlockTimestamp(),
380 lockMultiplier: lockMultiplier,
381 amountWithMultiplier: amountWithMultiplier,
totalMultiplier: lockMultiplier
});
// update total lp supply
_stakedSupply = _stakedSupply + amount;
_stakedSupplyWithMultiplier = _stakedSupplyWithMultiplier + amountWithMultiplier;
emitCreatePosition(currentTokenId, amount, lockDuration);
}
Here, lockMultiplier is calculated from lockDuration.
And MlumStaking.sol#addToPosition() function is as follows.
As we can see on L410, avgDuration < position.initialLockDuration so lockDuration is decreased.
But on L417, lockMultiplier is calculated from position.initialLockDuration so it is not decreased.
And MlumStaking.sol#renewLockPosition(), _lockPosition() functions are as follows.
function renewLockPosition(uint256tokenId) external nonReentrant {
_requireOnlyApprovedOrOwnerOf(tokenId);
_updatePool();
@>_lockPosition(tokenId, _stakingPositions[tokenId].lockDuration, false);
}
function _lockPosition(uint256tokenId, uint256lockDuration, boolresetInitial) internal {
require(!isUnlocked(), "locks disabled");
StakingPosition storage position = _stakingPositions[tokenId];
// for renew only, check if new lockDuration is at least = to the remaining active durationuint256 endTime = position.startLockTime + position.lockDuration;
uint256 currentBlockTimestamp =_currentBlockTimestamp();
if (endTime > currentBlockTimestamp) {
require(lockDuration >= (endTime - currentBlockTimestamp) && lockDuration >0, "invalid");
}
// for extend lock postion we reset the initial lock duration// we have to check that the lock duration is greater then the currentif (resetInitial) {
require(lockDuration > position.initialLockDuration, "invalid");
position.initialLockDuration = lockDuration;
}
_harvestPosition(tokenId, msg.sender);
// update position and total lp supply
position.lockDuration = lockDuration;
714 position.lockMultiplier =getMultiplierByLockDuration(lockDuration);
position.startLockTime = currentBlockTimestamp;
_updateBoostMultiplierInfoAndRewardDebt(position);
emitLockPosition(tokenId, lockDuration);
}
As you can see on L714, the lockMultiplier is calculated from lockDuration.
If a user calls renewLockPosition() => _lockPosition() after addToPosition() by some reason, the lockMultiplier is decreased.
This results in distribution of less rewards to the user.
Impact
If a user calls renewLockPosition() after addToPosition(), the lockMultiplier is decreased so the amountWithMultiplier is decreased and the user receives less rewards than normal unexpectedly.
MlumStaking.sol#_lockPosition() function has to be modified as follows.
function _lockPosition(uint256tokenId, uint256lockDuration, boolresetInitial) internal {
require(!isUnlocked(), "locks disabled");
StakingPosition storage position = _stakingPositions[tokenId];
// for renew only, check if new lockDuration is at least = to the remaining active durationuint256 endTime = position.startLockTime + position.lockDuration;
uint256 currentBlockTimestamp =_currentBlockTimestamp();
if (endTime > currentBlockTimestamp) {
require(lockDuration >= (endTime - currentBlockTimestamp) && lockDuration >0, "invalid");
}
// for extend lock postion we reset the initial lock duration// we have to check that the lock duration is greater then the currentif (resetInitial) {
require(lockDuration > position.initialLockDuration, "invalid");
position.initialLockDuration = lockDuration;
}
_harvestPosition(tokenId, msg.sender);
// update position and total lp supply
position.lockDuration = lockDuration;
- position.lockMultiplier =getMultiplierByLockDuration(lockDuration);
+ position.lockMultiplier =getMultiplierByLockDuration(position.initialLockDuration);
position.startLockTime = currentBlockTimestamp;
_updateBoostMultiplierInfoAndRewardDebt(position);
emitLockPosition(tokenId, lockDuration);
}
0xSmartContract
added
Medium
A Medium severity issue.
Duplicate
A valid issue that is a duplicate of an issue with `Has Duplicates` label
and removed
Excluded
Excluded by the judge without consulting the protocol or the senior
labels
Jul 28, 2024
sherlock-admin4
changed the title
Petite Rouge Huskie - The lockMultiplier can be decreased unexpectedly by renewLockPosition.
dany.armstrong90 - The lockMultiplier can be decreased unexpectedly by renewLockPosition.
Jul 29, 2024
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 Medium severity issue.RewardA payout will be made for this issue
dany.armstrong90
Medium
The
lockMultiplier
can be decreased unexpectedly byrenewLockPosition
.Summary
After
MlumStaking.sol#createPosition()
, thelockMultiplier
is not decreased whenaddToPosition()
,renewLockPosition()
andextendLockPosition()
are called individually unless multiplier settings are not changed.And in
addToPosition()
, thelockMultiplier
is not decreased butlockDuration
can be decreased.And in
renewLockPosition()
,lockMultiplier
is calculated fromlockDuration
.So if a user calls through
addToPosition() => renewLockPosition()
,lockMultiplier
can be decreased unexpectedly soamountWithMultiplier
is decreased and less rewards are distributed to the user.Vulnerability Detail
MlumStaking.sol#createPosition()
function is as follows.Here,
lockMultiplier
is calculated fromlockDuration
.And
MlumStaking.sol#addToPosition()
function is as follows.As we can see on L410,
avgDuration < position.initialLockDuration
solockDuration
is decreased.But on L417,
lockMultiplier
is calculated fromposition.initialLockDuration
so it is not decreased.And
MlumStaking.sol#renewLockPosition(), _lockPosition()
functions are as follows.As you can see on L714, the
lockMultiplier
is calculated fromlockDuration
.If a user calls
renewLockPosition() => _lockPosition()
afteraddToPosition()
by some reason, thelockMultiplier
is decreased.This results in distribution of less rewards to the user.
Impact
If a user calls
renewLockPosition()
afteraddToPosition()
, thelockMultiplier
is decreased so theamountWithMultiplier
is decreased and the user receives less rewards than normal unexpectedly.Code Snippet
https://github.com/sherlock-audit/2024-06-magicsea/blob/main/magicsea-staking/src/MlumStaking.sol#L714
Tool used
Manual Review
Recommendation
MlumStaking.sol#_lockPosition()
function has to be modified as follows.Duplicate of #138
The text was updated successfully, but these errors were encountered: