Christmas Dinner

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

The host is not able to withdraw ETH from the contract

Summary

There is no functionality available to allow the host to withdraw ETH from the contract.

Vulnerability Details & Impact

To facilitate the event, the host withdraws all tokens from the contract to the host wallet. However, there is no functionality to withdraw eth to the host wallet. If the host or participant does not withdraw funds, all ETH remaining in the contract will be forfeited after the deadline.

Tools Used

Manual review and see foundry test below:

//SPDX-License-Identifier: MIT
pragma solidity 0.8.27;
import {Test, console2} from "forge-std/Test.sol";
import {ChristmasDinner} from "../src/ChristmasDinner.sol";
import {ERC20Mock} from "../lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol";
contract XmasDinnerTest is Test {
ChristmasDinner cd;
ERC20Mock wbtc;
ERC20Mock weth;
ERC20Mock usdc;
uint256 constant DEADLINE = 7;
address deployer = makeAddr("deployer");
address user1;
function setUp() public {
wbtc = new ERC20Mock();
weth = new ERC20Mock();
usdc = new ERC20Mock();
vm.startPrank(deployer);
cd = new ChristmasDinner(address(wbtc), address(weth), address(usdc));
vm.warp(1);
cd.setDeadline(DEADLINE);
vm.stopPrank();
user1 = makeAddr("user1");
usdc.mint(user1, 2e18);
deal(user1, 2 ether);
vm.prank(user1);
usdc.approve(address(cd), 2e18);
}
function testWithDraw() public {
//Initial assertions
assert(usdc.balanceOf(user1) == 2e18);
assert(usdc.balanceOf(address(cd)) == 0);
assert(address(cd).balance == 0);
assert(user1.balance == 2 ether);
assert(deployer.balance == 0);
//user1 deposits USDC and ETH to the contract
vm.startPrank(user1);
cd.deposit(address(usdc), 1e18);
(bool success,) = address(cd).call{value: 1 ether}("");
require(success);
vm.stopPrank();
assert(usdc.balanceOf(user1) == 1e18);
assert(usdc.balanceOf(address(cd)) == 1e18);
assert(address(cd).balance == 1 ether);
assert(user1.balance == 1 ether);
assert(deployer.balance == 0);
//Host withdraws money
vm.prank(deployer);
cd.withdraw();
assert(usdc.balanceOf(deployer) == 1e18);
assert(usdc.balanceOf(address(cd)) == 0);
assert(address(cd).balance == 1 ether); //still 1 ether in the contract
assert(deployer.balance == 0); // 0 ether
}
}

Recommendations

Add the following lines to the ChristmasDinner::withdraw() function:

function withdraw() external onlyHost {
//@m no eth transfer
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,"ETH transfer failed!");
}
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!