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: 37/126
Findings: 2
Award: $0.02
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Circolors
Also found by: 0rpse, 0x175, 0xAadi, 0xHash, 0xMax1mus, 0xMosh, 0xblack_bird, 0xdice91, 0xfox, 0xhacksmithh, 0xloscar01, 0xrex, 4rdiii, Audinarey, AvantGard, Bigsam, DPS, Dots, Drynooo, Dudex_2004, Evo, Kaysoft, King_, Limbooo, MrPotatoMagic, PENGUN, Sabit, SovaSlava, SpicyMeatball, TheFabled, Utsav, Varun_05, Walter, adam-idarrha, araj, aslanbek, ayden, bctester, biakia, bigtone, brgltd, carrotsmuggler, cats, crypticdefense, dd0x7e8, dhank, fandonov, fyamf, grearlake, iamandreiski, ilchovski, jasonxiale, joaovwfreire, lanrebayode77, m4ttm, merlinboii, niser93, nnez, octeezy, oxchsyston, pamprikrumplikas, rouhsamad, tedox, trachev, turvy_fuzz, twcctop, yotov721, zhaojohnson
0.0056 USDC - $0.01
https://github.com/code-423n4/2024-05-munchables/blob/main/src/managers/LockManager.sol#L382
Anyone can increse/grief users unlock time repeatedly by locking dust amounts .
lockOnBehalf
functionality is for locoking on behalf of other users . Calling this function with a valid user as recipient will result in a increase in user's unlocktime
equal to his lockduration . And there are no minimum threshold for the locking amount(_quantity
) .
function lockOnBehalf( address _tokenContract, uint256 _quantity, address _onBehalfOf ) //.. { address tokenOwner = msg.sender; address lockRecipient = msg.sender; if (_onBehalfOf != address(0)) { lockRecipient = _onBehalfOf; } _lock(_tokenContract, _quantity, tokenOwner, lockRecipient); }
function _lock( address _tokenContract, uint256 _quantity, address _tokenOwner, address _lockRecipient ) private { //.. lockedToken.quantity += _quantity; lockedToken.lastLockTime = uint32(block.timestamp); @> lockedToken.unlockTime =//@audit-issue uint32(block.timestamp) + uint32(_lockDuration);
This can be used against user by locking dust amount of tokens on behalf of the victim . As there are no threshold regarding minimum locking amount ,locking dust amount of token will prolong user's unlocktime . And user will fail to unlock his funds as intended .And repeatedly doing this users fund can be locked for very long time . Because of the low gas cost on Blast Chain , this exploit can be pulled of in very low cost .
Manual review
Two mitigation is possible :
Context
#0 - c4-judge
2024-06-05T12:58:21Z
alex-ppg marked the issue as satisfactory
🌟 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.0105 USDC - $0.01
https://github.com/code-423n4/2024-05-munchables/blob/main/src/managers/LockManager.sol#L257
funds can be unlocked before unlock time !
setLockDuration
function is for updating the lock duration of a user's locked fund . However one issue arises when a user set a token lock duration less then his previous lock duration . The reason behind this is token unlock time is being updated as lastLockTime + _duration
.
function setLockDuration(uint256 _duration) external notPaused { //.. for (uint256 i; i < configuredTokensLength; i++) { address tokenContract = configuredTokenContracts[i]; if (lockedTokens[msg.sender][tokenContract].quantity > 0) { // check they are not setting lock time before current unlocktime if ( uint32(block.timestamp) + uint32(_duration) < lockedTokens[msg.sender][tokenContract].unlockTime ) { revert LockDurationReducedError(); } uint32 lastLockTime = lockedTokens[msg.sender][tokenContract] .lastLockTime; lockedTokens[msg.sender][tokenContract].unlockTime = @> lastLockTime + uint32(_duration); } }
Consider this scenario :
lock
. Now , his lastLockTime = block.timestamp
& unlockTime = 60 days later .lastLockTime + _duration
which is 30 days prior to actual unlockTime of 60 days !Manual review
Setting a new duration should not impact the previous locks . Remove this logic :
lockedTokens[msg.sender][tokenContract].unlockTime = lastLockTime + uint32(_duration);
Context
#0 - c4-judge
2024-06-05T12:52:03Z
alex-ppg marked the issue as partial-75