Platform: Code4rena
Start Date: 01/08/2023
Pot Size: $91,500 USDC
Total HM: 14
Participants: 80
Period: 6 days
Judge: gzeon
Total Solo HM: 6
Id: 269
League: ETH
Rank: 19/80
Findings: 1
Award: $625.44
🌟 Selected for report: 0
🚀 Solo Findings: 0
625.436 USDC - $625.44
In "V3Proxy" contract, the swapTokensForExactETH
function does not fully refund the unspent tokens back to the user when performing a token-to-ETH swap.
Users may lose some of their tokens unnecessarily when executing a token-to-ETH swap using the swapTokensForExactETH
function. If the actual amount of tokens needed for the swap is less than the provided amountInMax
, the excess tokens are not refunded to the user, resulting in an unavoidable loss.
To demonstrate the issue, the following steps can be taken:
swapTokensForExactETH
function with a larger amountInMax
than required for the swap.swapTokensForExactETH
function, check if the actual amount of tokens needed for the swap (amounts[0]
) is less than the provided amountInMax
.amounts[0]
and amountInMax
, refund the unspent tokens back to the user using the safeTransfer
function of the ERC20 token contract.function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) payable external returns (uint[] memory amounts) { require(path.length == 2, "Direct swap only"); require(path[1] == ROUTER.WETH9(), "Invalid path"); ERC20 ogInAsset = ERC20(path[0]); ogInAsset.safeTransferFrom(msg.sender, address(this), amountInMax); ogInAsset.safeApprove(address(ROUTER), amountInMax); amounts = new uint[](2); amounts[0] = ROUTER.exactOutputSingle(ISwapRouter.ExactOutputSingleParams(path[0], path[1], feeTier, address(this), deadline, amountOut, amountInMax, 0)); amounts[1] = amountOut; + if (amounts[0] < amountInMax) { + uint256 refundAmount = amountInMax - amounts[0]; + ogInAsset.safeTransfer(msg.sender, refundAmount); // Refund the unspent tokens back to the user + } ogInAsset.safeApprove(address(ROUTER), 0); IWETH9 weth = IWETH9(ROUTER.WETH9()); acceptPayable = true; weth.withdraw(amountOut); acceptPayable = false; payable(msg.sender).call{value: amountOut}(""); emit Swap(msg.sender, path[0], path[1], amounts[0], amounts[1]); }
Uniswap
#0 - c4-pre-sort
2023-08-09T08:23:06Z
141345 marked the issue as duplicate of #64
#1 - c4-judge
2023-08-20T17:31:48Z
gzeon-c4 changed the severity to 3 (High Risk)
#2 - c4-judge
2023-08-20T17:31:51Z
gzeon-c4 marked the issue as satisfactory