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 {
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)));
}
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);
vm.startPrank(user1);
(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();
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);
}