Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

## Snow.sol ## [ Unverified Funds Collection in collectFee() ]

Root + Impact

Description

The collectFee() function does not verify whether the ETH and WETH balances it transfers to the collector were actually collected through s_buyFee payments in the buySnow() function.

Issues:

  • No accounting is done in buySnow() to record who paid what or how much was collected

  • The contract does not reference s_buyFee during fee collection

function collectFee() external onlyCollector {
uint256 collection = i_weth.balanceOf(address(this));
@> i_weth.transfer(s_collector, collection);
(bool collected,) = payable(s_collector).call{value: address(this).balance}("");
require(collected, "Fee collection failed!!!");
}

Risk

Likelihood:

Occurs whenever ETH or WETH is sent directly to the contract via transfer.

Common in open/public contracts where many users interact with the address or spoof interactions.

Impact:

Low accounting integrity: Cannot verify that collected funds came from legitimate purchases.

Lack of auditability: Makes it hard to reconcile how much was paid and by whom.

Proof of Concept

Bob sends 100 WETH directly to the contract
​
Collector calls collectFee()
​
Contract state gives no way to trace where it came from or who paid what

Recommended Mitigation

Track Fees per User, and update buySnow and collectFee functions:

mapping(address => uint256) public wethPaid;
mapping(address => uint256) public ethPaid;
​
function buySnow(uint256 amount) external payable canFarmSnow {
uint256 totalCost = s_buyFee * amount;
if (msg.value == totalCost {
ethPaid[msg.sender] += msg.value;
_mint(msg.sender, amount);
} else {
i_weth.safeTransferFrom(msg.sender, address(this), totalCost);
wethPaid[msg.sender] += totalCost;
_mint(msg.sender, amount)
}
s_earnTimer = block.timestamp;
emit SnowBought(msg.sender, amount);
}
function collectFee() external onlyCollector {
uint256 wethToCollect = i_weth.balanceOf(address(this));
if (wethToCollect > 0) {
i_weth.transfer(s_collector, wethToCollect);
}
uint256 ethToCollect = address(this).balance;
if (ethToCollect > 0) {
(bool collected,) = payable(s_collector).call{value: address(this).ethToCollect}("");
require(collected, "ETH collection failed!!!");
}
emit FeeCollected(msg.sender);
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!