# Issue when handling native ETH trade and WETH trade in DODO RouterProxy#externalSwap

DODO RouterProxy externalSwap measures received amount via WETH balance, so external swaps settling in native ETH report zero received and revert, breaking ETH-out trades.

- Payout: Contest reward
- Severity: medium
- Program: Dodo
- Credited: ctf_sec
- Disclosed: 2022-11-05
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2022-11-dodo-judging/issues/20
- Library page: https://bugbountylibrary.com/r/sherlock%3A2022-11-dodo%3AM-3
- Tags: domain:web3 impact:dos kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** DODORouteProxy.externalSwap external swap router
**Root cause:** externalSwap tracks toToken balance via WETH balance when toToken is ETH, but external routers like Paraswap wrap then unwrap WETH and return native ETH, leaving WETH balance unchanged; no ETH wrap/approve or msg.value==fromTokenAmount check.
**Steps:**
1. Call `externalSwap(fromToken=ETH_ADDRESS, toToken=ETH_ADDRESS, approveTarget, swapTarget=Paraswap, fromTokenAmount, minReturnAmount, feeData, callDataConcat, deadLine)` with msg.value=fromTokenAmount
2. Router forwards ETH via `swapTarget.call{value: fromTokenAmount}(callDataConcat)` to Paraswap swapOnUniswapV2Fork
3. Paraswap deposits ETH to WETH, swaps, then `IWETH(weth).withdraw(tokensBought)` and `safeTransferETH(msg.sender, tokensBought)` back to RouterProxy
4. RouterProxy computes `receiveAmount = WETH.balanceOf(this) - toTokenOriginBalance` which is 0 since WETH was unwrapped
5. Trade reverts / reports zero received despite ETH delivered
**How found:** Read externalSwap source, noticed payable modifier and ETH_ADDRESS branch but balance accounting uses WETH; traced Paraswap swapOnUniswapV2Fork implementation on Etherscan to confirm it unwraps WETH to ETH before returning.
**Insight:** When a router measures output via a wrapped-token balance, check whether the downstream DEX aggregator unwraps to native ETH before returning — balance deltas on the wrapped token will be zero even though value arrived.
