# withdraw can fail unexpectedly

Lockbox::withdraw omits whirlpool::collect_rewards, so owed rewards make close_position revert, permanently blocking user withdrawals.

- Payout: Contest reward
- Severity: medium
- Program: Olas Lockbox
- Credited: Amaechi Okolobi
- Disclosed: 2024-03-11
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_olas_lockbox_jan2024.pdf#3.2.1
- Library page: https://bugbountylibrary.com/r/cantina%3Aolas_lockbox_jan2024%3A3.2.1
- Tags: domain:web3 impact:dos kind:contest platform:cantina sev:medium tech:solana technique:chained technique:source-review vuln:business-logic vuln:dos

**Target:** Solana Anchor program (lib.rs) integrating Orca whirlpool CPI
**Root cause:** withdraw calls update_fees_and_rewards then close_position without first calling collect_rewards, leaving reward_infos.amount_owed nonzero; close_position's is_position_empty check then reverts with ClosePositionNotEmpty.
**Steps:**
1. User has a Lockbox position in an Orca whirlpool with active reward incentives.
2. Call `Lockbox::withdraw`; it invokes `whirlpool::cpi::update_fees_and_rewards`, which applies reward growth via `update_rewards`/`position.update`.
3. No `whirlpool::collect_rewards` is called, so `position.reward_infos[i].amount_owed` remains > 0.
4. `whirlpool::cpi::close_position` runs `is_position_empty`, which returns false because rewards_not_owed is false.
5. close_position returns `ErrorCode::ClosePositionNotEmpty`, reverting the whole withdraw.
**How found:** Code-reading of the withdraw flow against Orca whirlpool's close_position precondition: noticed update_fees_and_rewards can accrue rewards but no collect_rewards precedes close_position, then traced is_position_empty to confirm the revert.
**Exploitation:** Not an attacker-driven exploit; a user's own withdraw reverts whenever the whirlpool has reward incentives enabled, locking funds until rewards are collected out-of-band.
**Insight:** When wrapping a third-party CPI close/exit, check every precondition of the callee's emptiness/state guard (fees AND rewards owed) and ensure your flow zeroes all of them before calling close.
