Fallback + Receive redundancy
Description
-
Donators should be able to donate by sending ETH directly to the contract (calling the receive() function).
If no function matches the called function selector/signature on that contract, e.g. mistyped function name, the fallback() handles the call.
-
Issue: Redundant code, and Donation event is emitted even with msg.value of 0
receive() external payable {
@> emit SepEthDonated(msg.sender, msg.value);
}
fallback() external payable {
@> emit SepEthDonated(msg.sender, msg.value);
}
Risk
Likelihood:
-
Low: User calls RaiseboxFaucet with msg.value > 0 but with a misspelled function call
-
Low: Attacker sends empty value transaction and spams with donation events, calls RaiseboxFaucet with msg.value = 0
Impact:
-
1) User donates attached ETH to contract unwillingly.
-
2) Contract emits donation events, even if no ETH was sent.
Proof of Concept
Add the following test cases to your testfile:
function test_fallback_AcceptsEthWithMsgData() public {
vm.deal(user, 1 ether);
vm.prank(user);
(bool success, ) = address(raiseBoxFaucet).call{value: 0.1 ether}("0x1234");
assertTrue(success);
assertEq(address(raiseBoxFaucet).balance, 0.1 ether);
}
function test_fallback_EmitsDonationEventWithoutEthSent() public {
vm.prank(user);
vm.expectEmit(true, false, false, true);
emit SepEthDonated(user, 0);
(bool success, ) = address(raiseBoxFaucet).call("0x1234");
assertTrue(success);
}
Recommended Mitigation
Add _handleDonation() for less redundancy or make fallback() not unpayble.
Check if msg.valueis greater than zero before emitting donation event.
+ error RaiseBoxFaucet__NoDonation();
// -----------------------------------------------------------------------
// DONATION HANDLERS
// -----------------------------------------------------------------------
+ function _handleDonation() internal {
+ if(msg.value == 0){
+ RaiseBoxFaucet__NoDonation());
+ }
+ emit SepEthDonated(msg.sender, msg.value);
+ }
/// @notice Accept ETH donations via `receive`
receive() external payable {
- emit SepEthDonated(msg.sender, msg.value);
+ _handleDonation();
}
/// @notice Accept ETH donations via `fallback`
fallback() external payable {
- emit SepEthDonated(msg.sender, msg.value);
+ _handleDonation();
}