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: 52/126
Findings: 2
Award: $0.02
🌟 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
setLockDuration
function to reduce the lock time (almost to few seconds).Here is some high-quality graphics to better understand the current function logic in the time field
What happens is that when checking the validity of the new duration, the check is relative to the current timestamp. But duration is assigned according to initial lock time. Which allow you to reduce the lock time by amount of: >= unlock time
- block.timestamp
.
In practice we can reduce lock time by 2-5+ times (because of gas cost and continuity of time).
But teoretically it can be reduced to 1 second
After 1 * d seconds we call:
setLockDuration(9 * d seconds)
,
then setLockDuration(8 * d seconds)
,
... ,
then setLockDuration(1 * d seconds)
and we can unlock the tokens
Each time the total lock time reduced by the amount of time that has already passed, so the abstract formula looks like
new lock time
= old lock time
- (X times * time passed
)
block.timestamp
in check:if ( uint32(block.timestamp) + uint32(_duration) < lockedTokens[msg.sender][tokenContract].unlockTime ) {
lastLockTime
in assignment:lockedTokens[msg.sender][tokenContract].unlockTime = lastLockTime + uint32(_duration);
PoC uses setup that inherit from src/test/MunchablesTest.sol
:
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.25; import "src/test/MunchablesTest.sol"; import "forge-std/console2.sol"; import {LockManager} from "src/managers/LockManager.sol"; contract LockManagerAudit is MunchablesTest { address immutable USER_1 = makeAddr("USER_1"); address immutable PLAYER_1 = makeAddr("PLAYER_1"); function setUp() public override { deployContracts(); }
function test_unlock_before_end_of_lock() public { uint32 lockDuration = 86400; // default for test vm.startPrank(PLAYER_1); amp.register(MunchablesCommonLib.Realm(3), USER_1); lm.setLockDuration(lockDuration); vm.deal(PLAYER_1, 11 ether); lm.lock{value: 1.5 ether}(address(0), 1.5 ether); lm.getLocked(PLAYER_1); skip(lockDuration / 2); vm.expectRevert(0xbd0ab71d); // ERROR: "TokenStillLockedError()" lm.unlock(address(0), 1.5 ether); lm.setLockDuration(lockDuration / 2); lm.unlock(address(0), 1.5 ether); }
Manual code review
In setLockDuration
check that user does not reduce initial lock period or, if it is allowed, check that user do not reduce lock time to be less than minimum contract wide lock time.
Invalid Validation
#0 - c4-judge
2024-06-04T12:40:47Z
alex-ppg marked the issue as duplicate of #89
#1 - c4-judge
2024-06-05T12:54:02Z
alex-ppg marked the issue as satisfactory
#2 - c4-judge
2024-06-05T12:54:34Z
alex-ppg changed the severity to 3 (High Risk)
🌟 Selected for report: robertodf99
Also found by: 0xAadi, 0xAkira, 0xdice91, 0xhacksmithh, 0xleadwizard, AgileJune, Bauchibred, Bbash, Beosin, Bigsam, Dots, EPSec, EaglesSecurity, Eeyore, Evo, John_Femi, Mahmud, MrPotatoMagic, RotiTelur, Rushkov_Boyan, Sabit, Sentryx, Stormreckson, Topmark, Tychai0s, Utsav, Walter, ZanyBonzy, ZdravkoHr, adam-idarrha, araj, aslanbek, avoloder, bigtone, brevis, brgltd, carrotsmuggler, crypticdefense, dd0x7e8, dhank, djanerch, falconhoof, iamandreiski, joaovwfreire, leegh, merlinboii, mitko1111, pamprikrumplikas, pfapostol, prapandey031, swizz, trachev, twcctop, typicalHuman, unique, xyz
0.0148 USDC - $0.01
https://github.com/code-423n4/2024-05-munchables/blob/57dff486c3cd905f21b330c2157fe23da2a4807d/src/managers/LockManager.sol#L194-L195 https://github.com/code-423n4/2024-05-munchables/blob/57dff486c3cd905f21b330c2157fe23da2a4807d/src/managers/LockManager.sol#L225-L228
For the Price feed, it is allowed approveUSDPrice
to be called after disapproveUSDPrice
was called, but not vice versa.
This inconsistency is most likely incorrect:
Personally, I think the later option is more appropriate because a situation may arise where the price feed erroneously approves the wrong price (or the price undergoes a brief fluctuation before returning to normal, or someone manipulates the price, etc.).
function approveUSDPrice( uint256 _price ) external onlyOneOfRoles( [ Role.PriceFeed_1, Role.PriceFeed_2, Role.PriceFeed_3, Role.PriceFeed_4, Role.PriceFeed_5 ] ) { if (usdUpdateProposal.proposer == address(0)) revert NoProposalError(); if (usdUpdateProposal.proposer == msg.sender) revert ProposerCannotApproveError(); if (usdUpdateProposal.approvals[msg.sender] == _usdProposalId) revert ProposalAlreadyApprovedError();
function disapproveUSDPrice( uint256 _price ) external onlyOneOfRoles( [ Role.PriceFeed_1, Role.PriceFeed_2, Role.PriceFeed_3, Role.PriceFeed_4, Role.PriceFeed_5 ] ) { if (usdUpdateProposal.proposer == address(0)) revert NoProposalError(); if (usdUpdateProposal.approvals[msg.sender] == _usdProposalId) revert ProposalAlreadyApprovedError(); if (usdUpdateProposal.disapprovals[msg.sender] == _usdProposalId) revert ProposalAlreadyDisapprovedError();
Manual Review
I think it's preferable to allow the price feed to change its mind in any direction.
Access Control
#0 - 0xinsanity
2024-05-30T23:02:47Z
Duplicate of #83
#1 - c4-judge
2024-06-03T10:18:20Z
alex-ppg marked the issue as not a duplicate
#2 - c4-judge
2024-06-03T10:20:17Z
alex-ppg marked the issue as duplicate of #105
#3 - c4-judge
2024-06-03T11:48:09Z
alex-ppg marked the issue as duplicate of #104
#4 - c4-judge
2024-06-05T12:42:51Z
alex-ppg marked the issue as satisfactory