# Wrong invocation of Whirpools's updateFeesAndRewards will cause it to always revert

Lockbox withdraw calls Whirlpool updateFeesAndRewards when position liquidity hits zero, which always reverts, permanently locking the last unit of liquidity.

- Payout: Contest reward
- Severity: high
- Program: Olas
- Credited: hash
- Disclosed: 2024-02-06
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-12-autonolas-findings/issues/386
- Library page: https://bugbountylibrary.com/r/c4%3A2023-12-autonolas%3AH-03
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:high tech:solana technique:chained technique:source-review vuln:business-logic

**Target:** Solana liquidity lockbox program / Orca Whirlpool CPI
**Root cause:** withdraw() invokes Whirlpool updateFeesAndRewards after liquidity reaches zero; Whirlpool's _calculate_modify_liquidity rejects liquidity_delta==0 && position.liquidity==0 with LiquidityZero, so the call reverts.
**Steps:**
1. Deposit into lockbox creating a position with liquidity L.
2. Withdraw L-1 liquidity: remainder != 0, no updateFeesAndRewards call, succeeds.
3. Attempt to withdraw the final 1 unit: remainder == 0 triggers updateFeesAndRewards CPI.
4. Whirlpool returns ErrorCode::LiquidityZero because position.liquidity is 0, reverting the tx.
5. Last unit is unwithdrawable; positions chosen sequentially so only first position's liquidity-1 is reachable.
**How found:** Code-reading of withdraw()'s remainder==0 branch, tracing the CPI into Orca Whirlpool source to find the zero-liquidity guard in _calculate_modify_liquidity.
**Exploitation:** Not an attack; a functional bug. Any user withdrawing the full liquidity of the current position hits the revert, permanently stranding the final unit and blocking position closure.
**Insight:** When calling a third-party DEX CPI, check the callee's guards for edge states your code creates (e.g. zero liquidity) — decreaseLiquidity already updates fees, making the extra call both redundant and fatal.
