[M-1] HOST can withdraw tokens when event is going on, breaking the refund mechanism
Description: host can withdraw tokens when event is going on, cause participants not being able to refund their 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)));
}
...
function refund() external nonReentrant beforeDeadline {
address payable _to = payable(msg.sender);
_refundERC20(_to);
_refundETH(_to);
emit Refunded(msg.sender);
}
if the contract does not have enough tokens to refund, the refund will be reverted.
Impact:
Participants may not be able to refund their tokens.
Proof of Concept:
Participant sends some ERC20 token (in the whitelist) to the contract.
Host withdraws all the tokens.
Participant tries to refund the tokens.
import {IERC20Errors} from "../lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol";
...
function test_hostWithdrawBeforeEventEndBreakParticipantRefund() public {
vm.prank(user1);
cd.deposit(address(wbtc), 5000);
vm.prank(deployer);
cd.withdraw();
vm.prank(user1);
vm.expectRevert(abi.encodeWithSelector(
IERC20Errors.ERC20InsufficientBalance.selector,
address(cd),
0,
5000
));
cd.refund();
}
Recommended Mitigation:
Add a modifier to prevent the host from withdrawing tokens when the event is going on.
+ modifier beforeEventEnd() {
+ require(block.timestamp <= deadline, "Event has ended");
+ _;
+ }
...
- function withdraw() external onlyHost {
+ function withdraw() external onlyHost EventEnded {
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)));
}