Christmas Dinner

First Flight #31
Beginner FriendlyFoundrySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

Participant mapping is not updated in the receive() after deposit

Summary

The participant mapping is not updated when user deposits native ETH to the contract to sign up as participant.

Vulnerability Details

When a user sends ETH to the contract via the receive() function, their etherBalance is updated, and a NewSignup event is emitted. However, the participant mapping is not updated, which tracks whether a user is considered a participant. If the same user later deposits tokens using the deposit() function or native ETH using the receive(), the NewSignup event is emitted again because the participant mapping still shows false.

POC

Add the following test to the ChristmasDinnerTest contract:

  • Although user1 becomes participant after depositing ETH, the NewSignup event is also emited after the user deposits some token (WETH, WBTC or USDC).

event NewSignup(address indexed, uint256 indexed, bool indexed);
function test_signUpIsEmittedTwiceWhenUserDepositsETH() public {
vm.deal(user1, 1 ether);
vm.startPrank(user1);
vm.expectEmit(address(cd));
emit NewSignup(user1, 1 ether, true);
(bool success, ) = address(cd).call{value: 1 ether}("");
require(success, "transfer failed");
vm.expectEmit(address(cd));
emit NewSignup(user1, 1 ether, true);
cd.deposit(address(weth), 1 ether);
}

Impact

  1. The NewSignup event is emitted twice for the same user - once for ETH deposit via receive() and again for tokens via deposit() or ETH with receive(). This is misleading and can confuse users or data analytics tools that rely on event logs.

  2. The user is effectively treated as a participant for ETH but not for tokens unless they explicitly deposit tokens. This inconsistency could cause issues in other parts of the contract.

Tools Used

  • Manual review

  • Foundry

Recommendations

Add a check and update the participant mapping in the receive() function when the user sends ETH.

Also, when the user is already a participant emit GenerousAdditionalContribution event.

This way, the user is correctly marked as a participant regardless of the deposit method.

receive() external payable {
etherBalance[msg.sender] += msg.value;
if (participant[msg.sender]) {
emit GenerousAdditionalContribution(msg.sender, msg.value);
} else {
participant[msg.sender] = true;
emit NewSignup(msg.sender, msg.value, true);
}
}
Updates

Lead Judging Commences

0xtimefliez Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

receive does not update participation status

Support

FAQs

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