Platform: Code4rena
Start Date: 22/05/2024
Pot Size: $20,000 USDC
Total HM: 6
Participants: 126
Period: 5 days
Judge: 0xsomeone
Total Solo HM: 1
Id: 379
League: ETH
Rank: 86/126
Findings: 1
Award: $0.01
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: SpicyMeatball
Also found by: 0rpse, 0xMosh, 0xblack_bird, 0xdice91, 0xhacksmithh, 0xleadwizard, 0xmystery, Audinarey, AvantGard, Bigsam, Dots, EPSec, Eeyore, Janio, Limbooo, LinKenji, Mahmud, MrPotatoMagic, Myd, Oxsadeeq, Sabit, SovaSlava, Stefanov, Tychai0s, Utsav, Varun_05, Walter, adam-idarrha, ahmedaghadi, araj, aslanbek, ayden, bigtone, c0pp3rscr3w3r, carrotsmuggler, crypticdefense, dhank, fyamf, gajiknownnothing, gavfu, itsabinashb, jasonxiale, joaovwfreire, ke1caM, leegh, merlinboii, mitko1111, n4nika, pfapostol, prapandey031, rouhsamad, sandy, snakeeaterr, stakog, steadyman, swizz, tedox, th3l1ghtd3m0n, trachev, turvy_fuzz, xyz, yashgoel72, zhaojohnson
0.014 USDC - $0.01
The way lock duration is set by calling LockManager::setLockDuration()
it is possible to set a lock duration which is less than minimum lock duration.
Suppose minimum lock duration is 60 seconds. A lock was created at timestamp X which is the lastLockTime of the lock. So unlockTime will be (X + 60 seconds).
lastLockTime(X) unlockTime(X+60) |-------------------------------------------------------------| <------------- duration = minDuration = 60 secs ------------->
Now, at the time of (x+40 secs) player called the setLockDuration()
with 30 secs as argument. As (X + 40 + 30) = (x + 70) is greater than the unlockTime i.e (X+60) so the call will not revert by LockDurationReducedError
.
Finally unlockTime = lastLockTime + duration = X + 30.
As of the new unlockTime the lock is already unlocked.
So we can see that actually (X + 30) is far less than minimum duration, still the player managed to unlock 20 seconds before [because he called the setLockDuration()
at (X + 40).
The problem is in the process of checking the condition for whether the duration is reduced or not i.e LockDurationReducedError
. The if
condition looks like:
if ( uint32(block.timestamp) + uint32(_duration) < lockedTokens[msg.sender][tokenContract].unlockTime ) { revert LockDurationReducedError(); }
You can see that uint32(_duration)
is added with block.timestamp but it should not, it should be added with lastLockTime
.
The new duration looks like:
X + 40 secs lastLockTime(X) setLockDuration() unlockTime(X+60) |--------------------------------------|-----------------------| <------------- duration = minDuration = 60 secs -------------> X X+30 |-----------------------------| <----- new duration = 30 ----->
Manual review
Change the if
block from present to this:
if ( lockedTokens[msg.sender][tokenContract].lastLockTime + uint32(_duration) < lockedTokens[msg.sender][tokenContract].unlockTime ) { revert LockDurationReducedError(); }
Math
#0 - c4-judge
2024-06-04T12:40:56Z
alex-ppg marked the issue as duplicate of #89
#1 - c4-judge
2024-06-05T12:53:42Z
alex-ppg marked the issue as satisfactory
#2 - c4-judge
2024-06-05T12:54:34Z
alex-ppg changed the severity to 3 (High Risk)