Native ETH may be sent by mistake in some cases
Description
This contract has an open and unpermissioned receive handler:
receive() external payable {}
In normal operation, this is used to receive native ETH from calls to WETH.withdraw
. However, any user may accidentally send native ETH to this contract, causing it to become stuck.
Another way users may accidentally lose native ETH is through the swapETHForToken
function. This is a payable function, but if isWETH
is set to true, it uses WETH instead, never reading the msg.value
:
function swapETHForToken(
uint256 _amountIn,
uint256 _amountOutMin,
address _address,
bool _isWETH
) public payable tokenExists(_address) {
// [...]
if (_isWETH) {
_safeTransferTokenFrom(address(weth), msg.sender, address(this), _amountIn);
weth.withdraw(_amountIn);
} else {
if (msg.value < _amountIn) revert NotEnoughETH();
}
This means that a user may mistakenly send native ETH alongside a call to swapETHForToken
that actually pays the contract in WETH. This native ETH will become stuck in the contract.
Additionally, in the same code, the NotEnoughETH
check ensures that msg.value >= _amountIn
instead of being equal. If a user sends in more native ETH than _amountIn
, the excess becomes stuck in the contract.
Impact
It is standard to revert upon unexpected or incorrect transfers of native ETH, instead of just accepting the funds, in order to ensure that users do not mistakenly send value that they do not intend to freely donate. However, through the three ways outlined above, native ETH can become stuck in the contract.
Recommendations
We recommend restricting the receive
function to only WETH, adding a check for msg.value == 0
in the _isWETH
branch of swapETHForToken
, and modifying the check to msg.value == _amountIn
in the other branch.
Remediation
This issue has been acknowledged by PondFun, and a fix was implemented in commit 45ea64e3↗. The issue has been fixed by adding a WETH address check and additional msg.value
checks as recommended.