Christmas Dinner

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

Ether balance is not sent to host when we withdraw funds from contract

Summary

When the withdraw function is called we do not sent the ether balance to the host as it is stored in a seperate mapping.

Vulnerability Details

When the withdraw function is called we do not send the ether balance to the host, it is left in the contract and we have no way to withdraw it. We can only get the values of the WETH, WBTC and USDC tokens.

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

We have funds left in the contract that won't be withdrawable and will be stuck inside of it, making funding with etherum directly useless.

Tools Used

  • Manual review

  • Foundry testing

POC

function test_withdrawAsHostDoesNotWithdrawEtherDeposited() public {
uint256 wethAmount;
uint256 wbtcAmount;
uint256 usdcAmount;
uint256 ethAmount;
bool sent;
address payable _cd = payable(address(cd));
vm.deal(user1, 10 ether);
vm.deal(user2, 10 ether);
//We start of by funding the contract with WBTC, WETH and Ether by user1
vm.startPrank(user1);
cd.deposit(address(wbtc), 0.5e18);
wbtcAmount += 0.5e18;
cd.deposit(address(weth), 2e18);
wethAmount += 2e18;
(sent, ) = _cd.call{value: 5e18}("");
ethAmount += 5e18;
require(sent, "transfer failed");
assertEq(user1.balance, 5e18);
assertEq(address(cd).balance, 5e18);
vm.stopPrank();
//We funding the contract with WBTC, USDC and Ether by user2
vm.startPrank(user2);
cd.deposit(address(usdc), 2e18);
usdcAmount += 2e18;
cd.deposit(address(wbtc), 1e18);
wbtcAmount += 1e18;
(sent, ) = _cd.call{value: 5e18}("");
ethAmount += 5e18;
require(sent, "transfer failed");
assertEq(user1.balance, 5e18);
assertEq(address(cd).balance, 10e18);
vm.stopPrank();
vm.startPrank(deployer);
cd.withdraw();
vm.stopPrank();
assertEq(wbtc.balanceOf(deployer), wbtcAmount);
assertEq(weth.balanceOf(deployer), wethAmount);
assertEq(usdc.balanceOf(deployer), usdcAmount);
//This is wrong, the balance of the host should be 10 ether
assertEq(deployer.balance, 0);
}

Recommendations

We should add logic to the withdraw function to transfer ethers that were deposited to the contract to the host address.

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