Finding description and impact
The contract may hold an increasing balance of unusable ETH over time, reducing efficiency and potentially leading to disputes over unrefunded funds.
Proof of Concept
if (msg.value > (amountXIn + fee + 1)) { (bool success, ) = payable(msg.sender).call{value: msg.value - amountXIn - fee - 1}(""); require(success, "ETH transfer failed"); }
The conditional check msg.value > (amountXIn + fee + 1) requires the excess ETH to exceed (amountXIn + fee + 1)
before issuing a refund. If the msg.value
provided is exactly equal to (amountXIn + fee + 1)
, no refund occurs—even though the extra 1 wei
remains in the contract.
In scenarios where users provide slightly more ETH than required and the condition fails, the small amounts left behind accumulate in the contract. Over many transactions, this can result in a growing unclaimed ETH balance.
Example
Suppose:
msg.value = 1.000001 ETH
amountXIn = 1 ETH
fee = 0.000001 ETH
Here, msg.value - amountXIn - fee = 1 wei
. Since the condition checks for msg.value > (amountXIn + fee + 1)
, the 1 wei
refund won't execute, and it remains stuck in the contract.
Recommended mitigation steps
Try this:
uint256 refundAmount = msg.value - amountXIn - fee; if (refundAmount > 0) { (bool success, ) = payable(msg.sender).call{value: refundAmount}(""); require(success, "ETH transfer failed"); }