Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

```SantaList::collectPresent()``` ```NICE``` and ```EXTRA_NICE"``` users can collect the Present multipletime

Summary

NICE and EXTRA_NICE" users can collect the Present multiple time calling SantaList::collectPresent(). SantaList::collectPresent() function uses the balanceOf the user for checking if the Present was already redeemed. However if the user collect the Present and then transfer it to another address, he/she can collect the Present again. This can do multiple time.

Vulnerability Details

function collectPresent() external {
if (block.timestamp < CHRISTMAS_2023_BLOCK_TIME) {
revert SantasList__NotChristmasYet();
}
@> if (balanceOf(msg.sender) > 0) {
@> revert SantasList__AlreadyCollected();
}
if (s_theListCheckedOnce[msg.sender] == Status.NICE && s_theListCheckedTwice[msg.sender] == Status.NICE) {
_mintAndIncrement();
return;
} else if (
s_theListCheckedOnce[msg.sender] == Status.EXTRA_NICE
&& s_theListCheckedTwice[msg.sender] == Status.EXTRA_NICE
) {
_mintAndIncrement();
i_santaToken.mint(msg.sender);
return;
}
revert SantasList__NotNice();
}

Impact

function testCanCollectPresentIfAlreadyCollected() public {
//User is NICE
vm.startPrank(santa);
santasList.checkList(user, SantasList.Status.NICE);
santasList.checkTwice(user, SantasList.Status.NICE);
vm.stopPrank();
vm.warp(santasList.CHRISTMAS_2023_BLOCK_TIME() + 1);
//User collects the first present
vm.startPrank(user);
santasList.collectPresent();
assertEq(santasList.balanceOf(user), 1);
//User transfers the Present to another address (userPresentBox)
santasList.safeTransferFrom(user, userPresentBox, 0);
//User collects the second present
santasList.collectPresent();
assertEq(santasList.balanceOf(user), 1);
}

Tools Used

Manual review

Recommendations

Considering to store the status of the Present collection (collected/uncollected) using a mapping.

+ mapping(address => bool) private s_presentCollected;
function collectPresent() external {
if (block.timestamp < CHRISTMAS_2023_BLOCK_TIME) {
revert SantasList__NotChristmasYet();
}
- if (balanceOf(msg.sender) > 0)
+ if (s_presentCollected[msg.sender]) {
revert SantasList__AlreadyCollected();
}
if (s_theListCheckedOnce[msg.sender] == Status.NICE && s_theListCheckedTwice[msg.sender] == Status.NICE) {
+ s_presentCollected[msg.sender] = true;
_mintAndIncrement();
return;
} else if (
s_theListCheckedOnce[msg.sender] == Status.EXTRA_NICE
&& s_theListCheckedTwice[msg.sender] == Status.EXTRA_NICE
) {
+ s_presentCollected[msg.sender] = true;
_mintAndIncrement();
i_santaToken.mint(msg.sender);
return;
}
revert SantasList__NotNice();
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

Weak Already Collected Check

Relying on balanceOf > 0 in collectPresent() allows the msg.sender to send their present to another address and then collect again.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!