Christmas Dinner

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

H-03: `ChristmasDinner::withdraw()` does not withdraw the Ether and Ether will be stuck in the contract forever after deadline has passed

Summary

ChristmasDinner::withdraw() does not withdraw the Ether and the Ether will be stuck in the contract forever after deadline has passed. As ChristmasDinner::refund() will revert as deadline has passed

Vulnerability Details

ChristmasDinner::withdraw() only withdraws the ERC20 tokens and not including Ether. Hence, the ether will be stucked in the contract after deadline.

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

  1. User1 deposit the ERC20 tokens and Ether to ChristmasDinner contract

  2. Deployer withdraws and only the ERC20 tokens are withdrawn. Leaving the Ether inside the contract

  3. Fast forward past deadline, the Ether will be stucked as ChristmasDinner::withdraw() does not withdraw Ether and ChristmasDinner::refund() will revert when users call

function testWithdrawDoesNotIncludeEther() public {
// Note: WBTC, WETH, USDC are already minted and approved in _makeParticipants()
uint256 amount = 2e18;
vm.deal(user1, 5 ether);
// User 1 deposits
vm.startPrank(user1);
cd.deposit(address(wbtc), amount);
cd.deposit(address(weth), amount);
cd.deposit(address(usdc), amount);
(bool success1, ) = address(cd).call{value: 5 ether}("");
require(success1, "Deposit ether failed for user 1");
vm.stopPrank();
console.log("Before withdraw()");
console.log("CD WBTC: ", wbtc.balanceOf(address(cd)));
console.log("CD WETH: ", weth.balanceOf(address(cd)));
console.log("CD USDC: ", usdc.balanceOf(address(cd)));
console.log("CD ETH: ", address(cd).balance);
// Start prank deployer to withdraw
vm.startPrank(deployer);
cd.withdraw();
console.log("\nAfter withdraw()");
console.log("CD WBTC: ", wbtc.balanceOf(address(cd)));
console.log("CD WETH: ", weth.balanceOf(address(cd)));
console.log("CD USDC: ", usdc.balanceOf(address(cd)));
console.log("CD ETH: ", address(cd).balance);
assertEq(wbtc.balanceOf(address(cd)), 0, "WBTC not empty.");
assertEq(weth.balanceOf(address(cd)), 0, "WETH not empty.");
assertEq(usdc.balanceOf(address(cd)), 0, "USDC not empty.");
assertEq(address(cd).balance, 5 ether, "Ether is empty");
vm.stopPrank();
// Fastforward 10days (past the deadline)
vm.warp(10 days);
vm.startPrank(user1);
vm.expectRevert(ChristmasDinner.BeyondDeadline.selector);
cd.refund();
vm.stopPrank();
}

Results

[PASS] testWithdrawDoesNotIncludeEther() (gas: 304700)
Logs:
Before withdraw()
CD WBTC: 2000000000000000000
CD WETH: 2000000000000000000
CD USDC: 2000000000000000000
CD ETH: 5000000000000000000
After withdraw()
CD WBTC: 0
CD WETH: 0
CD USDC: 0
CD ETH: 5000000000000000000
Traces:
....
....
....
├─ [0] VM::warp(864000 [8.64e5])
│ └─ ← [Return]
├─ [0] VM::startPrank(user1: [0x29E3b139f4393aDda86303fcdAa35F60Bb7092bF])
│ └─ ← [Return]
├─ [0] VM::expectRevert(BeyondDeadline())
│ └─ ← [Return]
├─ [2514] ChristmasDinner::refund()
-> │ └─ ← [Revert] BeyondDeadline()
├─ [0] VM::stopPrank()
│ └─ ← [Return]
└─ ← [Stop]
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.85s (246.21ms CPU time)

Tools Used

Foundry

Recommendations

Include withdrawing Ether from the contract

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)));
+ uint256 balance = address(this).balance;
+ (bool success, ) = address(_host).call{value: 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!