# changeRanges silently fails when price is out of tick range, sending all liquidity to treasury instead of creating new position

changeRanges silently skips new position creation when pool price is out of tick range, sending all LP tokens to treasury and leaving stale position mapping.

- Payout: Contest reward
- Severity: medium
- Program: Olas
- Credited: anchabadze
- Disclosed: 2026-05-18
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2026-01-olas#m-06
- Library page: https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AM-06
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** LiquidityManagerCore.sol changeRanges (Uniswap V3 LP manager)
**Root cause:** The guard `if (amounts[0] > 0 && amounts[1] > 0)` has no else branch, so when out-of-range collect() returns one token amount as zero, new position creation is skipped while _manageUtilityAmounts still sweeps all tokens to treasury and the mapping is left stale.
**Steps:**
1. Set up OLAS/WETH LP position with tick range [-10000, +10000].
2. Move pool price so current tick is outside range (e.g. -15000).
3. Call `changeRanges()` to reposition.
4. decreaseLiquidity() removes all liquidity; collect() returns amounts like `[1000000 OLAS, 0 WETH]`.
5. Condition `amounts[0] > 0 && amounts[1] > 0` is false; no new position minted, no revert.
6. `_manageUtilityAmounts(tokens, MAX_BPS, false)` transfers all tokens to treasury.
7. `mapPoolAddressPositionIds[pool]` still points to old empty position.
**How found:** Code review of changeRanges: noticed the two-token guard lacks an else branch and that Uniswap V3 collect() returns zero for one token when price is out of range, tracing the silent-failure path into _manageUtilityAmounts.
**Escalation:** Subsequent convertToV3/increaseLiquidity calls deposit into the stale out-of-range position, compounding fee loss; collectFees/decreaseLiquidity revert with ZeroValue.
**Insight:** In LP-manager wrappers, check what Uniswap collect() returns when price is out of tick range (one side zero) and audit every branch that assumes both amounts are non-zero; missing else branches around position creation leave stale mappings and misrouted funds.
