# Unused ETH is not refunded when a limit price is set

Maverick Router keeps unspent ETH when a limit price partially fills a swap; anyone can steal it via public refundETH.

- Payout: Audit contest
- Severity: medium
- Program: Maverick
- Found by: Jeiwan
- Disclosed: 2023-05-03
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2022-12-stealth-project#m-05
- Library page: http://bugbountylibrary.com/r/c4%3A2022-12-stealth-project%3AM-05
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic

**Target:** Router.sol swap entrypoint (exactInputSingle) with native ETH and sqrtPriceLimitD18
**Root cause:** Router.pay deposits the full msg.value into WETH and forwards it, but when a limit price causes a partial fill the leftover input is never returned to the user and stays in the Router balance.
**Steps:**
1. Call `router.exactInputSingle` with `tokenIn: weth9.address`, `amountIn: floatToFixed(1)`, `sqrtPriceLimitD18: "1077931889220708752"`, sending `{ value: floatToFixed(1) }`.
2. Swap stops at the limit price; only part of the ETH is consumed and tokens are delivered.
3. Observe router ETH balance increased by ~0.4937 ETH while user spent the full 1 ETH.
4. Attacker calls `router.refundETH()` and receives the leftover ETH.
**How found:** Noticed Router.pay deposits full msg.value while Pool stops swapping at sqrtPriceLimitD18, so partial fills leave input unspent; wrote a Hardhat PoC asserting router balance grows and refundETH drains it.
**Exploitation:** Any account (MEV bot) monitors the Router and calls the public refundETH() to sweep ETH left behind by partially filled limit-price swaps.
**Insight:** When a router wraps native value up-front, check whether partial fills (limit price, slippage cap, partial matching) return the unspent input; leftover balances in a shared router are free money for anyone calling a public refund/sweep function.

