# TokenisableRange's incorrect accounting of non-reinvested fees in "deposit" exposes the fees to a flash-loan attack

TokenisableRange skipped fee downscaling when any liquidity was added, letting a flash-loan depositor mint LP tokens and withdraw most accrued fees.

- Payout: Contest reward
- Severity: high
- Program: Good Entry
- Credited: 3docSec
- Disclosed: 2023-10-02
- Write-up quality: 8/10
- Original: https://github.com/code-423n4/2023-08-goodentry-findings/issues/85
- Library page: https://bugbountylibrary.com/r/c4%3A2023-08-goodentry%3AH-04
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:accounting-error vuln:business-logic vuln:flash-loan

**Target:** TokenisableRange.sol deposit/withdraw fee accounting (Uniswap V3 LP wrapper)
**Root cause:** The 1% reinvestment check compares fee0/fee1 amounts to pool amounts rather than total value, and the LP-token downscaling for accrued fees is skipped whenever newFee0==0 && newFee1==0, i.e. when any liquidity is added to the position.
**Steps:**
1. Fork mainnet at block 17811921; init TokenisableRange USDC/WETH range 500e10-1000e10 out of range so pool holds 0 WETH.
2. Deposit 100k USDC; simulate accrued fees fee0=1000e6 USDC, fee1=2e18 WETH (mock collect, transfer tokens to contract).
3. Call `tr.claimFee()`; fees remain non-reinvested because 1% check is on amounts not value.
4. Attacker approves 10,000,000e6 USDC and 1000 wei WETH; calls `tr.deposit(10_000_000e6, 1000)` — tiny WETH makes newFee1==0 so fee downscaling is skipped.
5. Call `tr.withdraw(deposited, 0, 0)`; attacker recovers ~1.58 WETH profit (most of fees) with ~1 wei USDC loss.
**How found:** Code review of TokenisableRange deposit/withdraw: noticed the 1% reinvestment check compares raw fee amounts to pool amounts (ignoring price), and that the fee downscaling branch is gated on newFee0==0 && newFee1==0, so adding any liquidity bypasses it.
**Exploitation:** Attacker flash-loans a large amount of the range's asset, deposits it together with a few wei of the other token to short-circuit the fee downscaling, receives LP tokens priced without the accrued fees, then withdraws to capture a disproportionate share of fee0/fee1 held by the contract.
**Escalation:** Profit scales with the value of accrued fees relative to pool; larger price swings between fee accrual and deposit increase the stealable fraction beyond the intended 1% cap.
**Insight:** When a contract guards against fee theft by downscaling minted shares, check the exact condition that enables the downscale — a branch keyed on 'no new liquidity added' is trivially bypassed by adding dust of the other token; also verify value-based caps use oracle prices, not raw token amounts.
