# Lack of segregation between users' assets and collected fees resulting in loss of funds for the users

LimitOrderRegistry.withdrawNative sweeps all WETH/ETH including users' unclaimed swapped tokens, so owner withdrawal irreversibly steals user funds.

- Payout: Contest reward
- Severity: high
- Program: Gfx
- Credited: Dug
- Disclosed: 2023-06-23
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-06-gfx-judging/issues/48
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-06-gfx%3AH-1
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:source-review vuln:access-control vuln:accounting-error

**Target:** LimitOrderRegistry.sol (Uniswap V3 limit orders)
**Root cause:** Collected fees and users' pending swapped WETH/ETH share the same contract balance; withdrawNative transfers the entire WETH and native balance to the owner instead of only accrued fees.
**Steps:**
1. Owner configures LimitOrderRegistry for a DAI/ETH Uniswap V3 pool.
2. Bob submits a buy limit order DAI->ETH at 1000 DAI/ETH depositing 1,000,000 DAI.
3. Order becomes ITM and performUpkeep fulfills it, sending 1000 WETH into LimitOrderRegistry awaiting Bob's claim.
4. Before Bob calls `claimOrder(batchId, user)`, owner/bot calls `withdrawNative()` which does `WRAPPED_NATIVE.safeTransfer(owner, wrappedNativeBalance)` and `owner.safeTransferETH(nativeBalance)`.
5. Bob's `claimOrder` reverts due to insufficient WETH; funds are unrecoverable.
**How found:** Code review of claimOrder fee handling and withdrawNative: noticed fee collection and user payouts both use the same WETH/native balance with no accounting separation, so a full-balance sweep by owner captures user assets.
**Exploitation:** Owner automation (or any routine fee-withdrawal bot) calls withdrawNative, draining the full WETH/ETH balance including unclaimed user proceeds; no recovery path exists since contract has no function to return swept funds.
**Insight:** When a contract both custodies user payouts and accrues protocol fees in the same token, check whether the fee-withdrawal function reads raw `balanceOf`/`address(this).balance` instead of tracked fee state — that pattern sweeps pending user funds.
