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
Users can revive an expired position with an arbitrary lockDuration while still retaining their initial lock duration
Summary
The contract MLumStaking allows a user to stake their MLUM for voting power. The contract exposes two functions for extending their locking duration:
renewLockPosition(), re-locks a position for exactly _stakingPositions[tokenId].lockDuration, defined by the position itself when it was still active.
extendLockPosition(), extends a lock position by a user's choice of duration. The new duration must at least be as long as the position's initial lock duration.
Both of these functionalities retain the position's initialLockDuration, but has restrictions as to what the new lock duration should be.
By combining partial withdrawing and reviving/extending the duration with addToPosition, we show a method to revive a position with an arbitrary lockDuration while retaining the initialLockDuration.
Vulnerability Detail
First of all, the function addToPosition() can be used to lock additional MLUM into a position. This also has an effect of extending their lock duration by a weighted average of the old amount and the added amount by the formula:
New Lock Time = (Remaining Lock Time * Staked MLUM Amount + MLUM Amount to add * Initial Lock Duration) / (MLUM Staked Amount + MLUM Amount to add)
It is worth noting that an expired position can still be added to, in which case they will be revived.
Secondly, the function withdrawFromPosition allows a user to withdraw MLUM from a position, on the condition that the position is expired. The user is able to partially withdraw from a position.
Combining these two facts, we have a method that allows reviving a position with an arbitrary lockDuration:
Suppose a position of 90 MLUM has been lock for, initially 90 days. This position is expired.
Suppose the owner of this position wishes to re-lock it just for 14 days, to pass the voting eligibility.
A user can partial withdraw 14 MLUM, and then lock that exact 14 MLUM again using addToPosition(). The new lock duration is (0 days * 76 MLUM + 90 days * 14 MLUM)/(90 MLUM) = 14 days.
The user is now eligible to vote, despite having re-locked a unlocked position for 14 days only.
Impact
User is able to re-lock a position with an arbitrary lockDuration, bypassing all functions intended for lock extension, and allows for voting without locking for the full 3 months. Voting has the effect of directing LUM reward emissions, so this equates to a fund loss
sherlock-admin4
changed the title
Icy Basil Seal - Users can revive an expired position with an arbitrary lockDuration while still retaining their initial lock duration
PUSH0 - Users can revive an expired position with an arbitrary lockDuration while still retaining their initial lock duration
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
PUSH0
Medium
Users can revive an expired position with an arbitrary
lockDuration
while still retaining their initial lock durationSummary
The contract MLumStaking allows a user to stake their MLUM for voting power. The contract exposes two functions for extending their locking duration:
renewLockPosition()
, re-locks a position for exactly_stakingPositions[tokenId].lockDuration
, defined by the position itself when it was still active.extendLockPosition()
, extends a lock position by a user's choice of duration. The new duration must at least be as long as the position's initial lock duration.Both of these functionalities retain the position's
initialLockDuration
, but has restrictions as to what the new lock duration should be.By combining partial withdrawing and reviving/extending the duration with
addToPosition
, we show a method to revive a position with an arbitrarylockDuration
while retaining theinitialLockDuration
.Vulnerability Detail
First of all, the function
addToPosition()
can be used to lock additional MLUM into a position. This also has an effect of extending their lock duration by a weighted average of the old amount and the added amount by the formula:It is worth noting that an expired position can still be added to, in which case they will be revived.
Secondly, the function
withdrawFromPosition
allows a user to withdraw MLUM from a position, on the condition that the position is expired. The user is able to partially withdraw from a position.Combining these two facts, we have a method that allows reviving a position with an arbitrary
lockDuration
:addToPosition()
. The new lock duration is(0 days * 76 MLUM + 90 days * 14 MLUM)/(90 MLUM) = 14 days
.Impact
User is able to re-lock a position with an arbitrary
lockDuration
, bypassing all functions intended for lock extension, and allows for voting without locking for the full 3 months. Voting has the effect of directing LUM reward emissions, so this equates to a fund lossCode Snippet
https://github.com/sherlock-audit/2024-06-magicsea/blob/main/magicsea-staking/src/MlumStaking.sol#L496
https://github.com/sherlock-audit/2024-06-magicsea/blob/main/magicsea-staking/src/MlumStaking.sol#L397
Tool used
Manual Review
Recommendation
Disallow adding to expired positions or disallow partial withdrawing.
Duplicate of #138
The text was updated successfully, but these errors were encountered: