Christmas Dinner

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

Missing Mechanism for Host to Withdraw Ether Contributions.

Description

Users can sign up for the Christmas dinner by paying with either a whitelisted ERC20 token or Ether. However, the contract lacks a withdrawal mechanism for the host to access the Ether, causing the funds to be locked in the contract indefinitely.

Here is the vulnerable code:

function withdraw() external onlyHost { // @audit not withdraw mechanism for the ether balance, causing the ether to be locked in the contract forever.
address _host = getHost();
i_WETH.safeTransfer(_host, i_WETH.balanceOf(address(this)));
i_WBTC.safeTransfer(_host, i_WBTC.balanceOf(address(this)));
i_USDC.safeTransfer(_host, i_USDC.balanceOf(address(this)));
// @audit missing ether withdrawal mechanism.
}

Impact

the ether contributions would be locked in the contract forever.

Proof of concept

Add the below foundry test to the test file to approve this findings:

function test_HostCantWithdrawEther() public {
uint256 wethAmount;
uint256 wbtcAmount;
uint256 usdcAmount;
address payable _cd = payable(address(cd));
vm.deal(user1, 10e18); // Fund user1 with 10 ethers
vm.startPrank(user1);
// user1 sign-up via ether payment
(bool sent,) = _cd.call{value: 1e18}("");
require(sent, "transfer failed");
cd.deposit(address(weth), 2e18);
wethAmount += 2e18;
vm.stopPrank();
vm.startPrank(user2);
cd.deposit(address(usdc), 2e18);
usdcAmount += 2e18;
cd.deposit(address(wbtc), 1e18);
wbtcAmount += 1e18;
vm.stopPrank();
vm.startPrank(deployer);
cd.withdraw();
vm.stopPrank();
// ether contract balance after host place a withdrawal.
console.log("The contract Ether balance after host withdraw the funds", address(cd).balance);
assertEq(address(cd).balance, 1e18);
assertEq(weth.balanceOf(deployer), wethAmount);
assertEq(usdc.balanceOf(deployer), usdcAmount);
}

Expected Output:

[PASS] test_HostCantWithdrawEther() (gas: 311135)
Logs:
The contract Ether balance after host withdraw the funds 1000000000000000000
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 25.05ms (20.94ms CPU time)

Recommended Mitigation

To mitigate this issue, consider add ether withdrawal mechanism to the withdraw function.

function withdraw() external onlyHost { // @audit not withdraw mechanism for the ether balance, causing the ether to be locked in the contract forever.
address _host = getHost();
i_WETH.safeTransfer(_host, i_WETH.balanceOf(address(this)));
i_WBTC.safeTransfer(_host, i_WBTC.balanceOf(address(this)));
i_USDC.safeTransfer(_host, i_USDC.balanceOf(address(this)));
+ (bool success, ) = _host.call{value: address(this).balance}("");
+ require(success);
}
Updates

Lead Judging Commences

0xtimefliez Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

withdraw function lacks functionality to send ether

Support

FAQs

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

Give us feedback!