Closed sherlock-admin2 closed 3 months ago
Low severity, there is more than ample time (52 weeks, 1 year) for a user to ensure maxLock is disabled for the specific token and/or invoke another action to continue max_lock. Additionally, the admin can disable max_lock_enabled
to help users avoid this revert.
Escalate
I think that the argument : there is more than ample time (52 weeks, 1 year) for a user to ensure maxLock is disabled for the specific token and/or invoke another action to continue max_lock. Additionally, the admin can disable max_lock_enabled to help users avoid this revert
is insufficient.
Sure, there is ample time for the user to interact but this is a very special expectation from the user, which is not documented. The consequences are also not documented, so we cannot assume that the user will know how the code dictates their responsibility. And the consequences are large, as they will completely lose control of their position forever.
This is also not similar to the general defi awareness of claiming your rewards before burning your position. This is more serious and different than that, as it involves losing the principal. The user shall be able to recover their principal amount in any case.
This expectation that every user shall know he needs to recurringly interact with the nft every once in a while is flawed and doesn't fall in the domain of usual "user error" and imo is unintended behavior as the withdrawl etc. should not be blocked, especially not an error for those users who do not know the code logic.
the admin can disable max_lock_enabled to help users avoid this revert
: true, but that is not a solution coz the team can't keep enabling and disabling the max_lock for every tokenID that gets stuck over the course of protocol lifecycle. The admin is not a trusted entity to allow/disallow "unblocking of stuck positions", at least that is not documented.
Also note that this could affect multiple users' principal funds.
Escalate
I think that the argument :
there is more than ample time (52 weeks, 1 year) for a user to ensure maxLock is disabled for the specific token and/or invoke another action to continue max_lock. Additionally, the admin can disable max_lock_enabled to help users avoid this revert
is insufficient.
Sure, there is ample time for the user to interact but this is a very special expectation from the user, which is not documented. The consequences are also not documented, so we cannot assume that the user will know how the code dictates their responsibility. And the consequences are large, as they will completely lose control of their position forever.
This is also not similar to the general defi awareness of claiming your rewards before burning your position. This is more serious and different than that, as it involves losing the principal. The user shall be able to recover their principal amount in any case.
This expectation that every user shall know he needs to recurringly interact with the nft every once in a while is flawed and doesn't fall in the domain of usual "user error" and imo is unintended behavior as the withdrawl etc. should not be blocked, especially not an error for those users who do not know the code logic.
the admin can disable max_lock_enabled to help users avoid this revert
: true, but that is not a solution coz the team can't keep enabling and disabling the max_lock for every tokenID that gets stuck over the course of protocol lifecycle. The admin is not a trusted entity to allow/disallow "unblocking of stuck positions", at least that is not documented.Also note that this could affect multiple users' principal funds.
You've created a valid escalation!
To remove the escalation from consideration: Delete your comment.
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
I still maintain this issue as low severity and hence invalid because
isApprovedOrOwner()
will automatically max lock user NFT for another 52 weeks, e.g. if at the point where 10 weeks has passed, it will extend another 52 weeks for the user to actmax_lock_bulk()
functionalities, invoking the extension mentioned in point 3Funds are temporarily stuck and can be recovered by the administrator or owner.
I agree with the @nevillehuang arguments. This is more about the way the protocol works than a bug. The user has one year to take action. Even more, as Nevi has pointed out.
Also, the admin can use the maxLockToggle()
function at any time and solve the problem:
function maxLockToggle() external {
require(msg.sender == team);
max_lock_enabled = !max_lock_enabled;
}
Then there will be no revert at all in max_lock()
because it will not enter the if statement:
if(maxLockIdToIndex[_tokenId] !=0 && max_lock_enabled) {
Planning to reject the escalation and leave the issue as is.
Result: Invalid Has duplicates
Chinmay
High
If a max locked nft expires, it will be stuck forever
Summary
The
votingEscrow
contract has amax_lock
feature by which an veNFT owner can turn max lock on for their nfts which will re-lock the nft for the max duration on any interaction ( increasing amount, increasing unlock time etc.), and this can also be done by anyone since max_lock is a public function.The problem is that if a max locked NFT's lock expires, then the NFT will be stuck forever.
Vulnerability Detail
Any interaction with the NFT calls isApprovedOrOwner() for auth check. The max_lock() function is embedded into isApprovedorOwner() to facilitate re-locking on any modifications of the NFT position as well as whenever it uses vote/poke/claim in voter contract.
This is the max lock logic :
The relevant part here is this :
require(_locked.end > block.timestamp, 'Lock expired');
This means that if the max_lock() function is reached after the lock expires, it will always revert.Now since the
isApprovedOrOwner() => max_lock
is looped in for all max locked nfts in all functions, this logic will always revert after the lock had expired.Now the lock can expire naturally if the user did not interact with it for some time, and after that the lp tokens associated with the lock will be stuck forever in the votingescrow contract.
This can happen for many users and tokenIDs.
Impact
Users locked tokens will be permanently stuck in the contract.
High severity because this can happen under normal operations and easily brick funds of a lot of users.
Code Snippet
https://github.com/sherlock-audit/2024-06-velocimeter/blob/63818925987a5115a80eff4bd12578146a844cfd/v4-contracts/contracts/VotingEscrow.sol#L918
Tool used
Manual Review
Recommendation
Remove the lock expired check from max_lock logic or refactor the max locking logic by calling it separately at required places and removing it from isApprovedOrOwner() flow.