### Description
The `buySnow` function checks if user-submitted capital matches fees exactly via `msg.value == s_buyFee * amount`.
If a user sends even 1 wei above the exact required amount, the validation condition triggers the `else` logic block. In this fallback branch, the contract pulls the entire fee value in `WETH` directly from the user's wallet anyway. However, the original excess `ETH` sent within `msg.value` remains completely trapped inside the contract state because no refund mechanisms exist.
The user pays twice for a single transaction—once in trapped `ETH` and once in pulled `WETH`—while receiving only one batch of tokens.
### Risk
Medium. Users lose their entire `ETH` payment permanently due to simple rounding or overpayment mistakes. The asset loss occurs silently without triggering a transaction revert or recovery path, allowing the contract controller to draw an unintended windfall profit at the user's expense.
### Likelihood
Medium. Web3 frontends or manual transaction execution tools often over-estimate or round gas/value pairs slightly, making accidental overpayment a common real-world occurrence.
### Proof of Concept
Add this test instance to your suite to witness the silent asset drain:
```solidity
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "../src/Snow.sol";
import "../src/WETH.sol";
contract SnowDoublePaymentTest is Test {
Snow public snow;
WETH public weth;
address public user = address(0x3);
address public collector = address(0x4);
function test_BuySnowDoublePayment() public {
vm.prank(user);
weth.approve(address(snow), type(uint256).max);
uint256 initialWeth = weth.balanceOf(user);
vm.prank(user);
snow.buySnow{value: 10 ether + 1}(10);
assertEq(snow.balanceOf(user), 10);
assertEq(weth.balanceOf(user), initialWeth - 10 ether);
assertEq(address(snow).balance, 10 ether + 1);
vm.prank(collector);
snow.collectFee();
assertEq(address(collector).balance, 10 ether + 1);
}
}
```
Run verification via command line:
```bash
forge test --match-test test_BuySnowDoublePayment -vvv
```
### Tools Used
Manual Review, Foundry Unit Testing.
### Recommended Mitigation
Remove the exact-match requirement condition. Accept loose `msg.value` submissions and calculate and return excess balances directly to the sender.
Modify the fee gate inside `Snow.sol` as shown below:
```solidity
uint256 requiredFee = s_buyFee * amount;
if (msg.value >= requiredFee) {
uint256 excess = msg.value - requiredFee;
if (excess > 0) {
(bool success, ) = msg.sender.call{value: excess}("");
require(success, "Refund failed");
}
_mint(msg.sender, amount);
} else {
}
```