refundETH() missing
swapNative does not call Uniswap V3 SwapRouter's refundETH(), so any unspent ETH (from price-limited or partial swaps) is left in the router and can be withdrawn by anyone, causing user loss.
Description
Potential loss of user funds due to unhandled refunds of unspent ETH in the Uniswap V3 ISwapRouter after executing the swapNative() function.
Location: WEDXswap::swapNative()
SwapRouter allows swapping of ETH for ERC20 tokens. The difference between selling ETH and an ERC20 token is that the contract can compute and request from the user the exact amount of ERC20 tokens to sell, but, when selling ETH, the user has to send the entire amount when making the call (i.e. before the actual amount was computed in the contract).
As swaps made via SwapRouter can be partial, there are scenarios when ETH can be spent partially. However, the contract doesn't refund unspent ETH in such scenarios:
- When
sqrtPriceLimitX96is set (SwapRouter.sol#L80, SwapRouter.sol#L164), the swap will be interrupted when the limit price is reached, and some ETH can be left unspent. - A swap can be interrupted earlier when there's not enough liquidity in a pool.
- Positive slippage can result in more efficient swaps, causing exact output swaps to leave some ETH unspent (even when it was pre-computed precisely by the caller).
Impact
The SwapRouter can retain leftover ETH after a swap. This ETH can be withdrawn by anyone using the SwapRouter.refundETH() function, leading to potential loss for the SwapRouter user.
Recommendation
Ensure the refundETH() function of Uniswap V3's router is called to return any unspent ETH. This prevents funds from being inadvertently left in the swap router, safeguarding user assets.

