# Heap is incorrectly stores the removed operator ID which can lead to division by zero in deposit/withdrawal flow

Heap _remove leaves stale operator ID in storage slot; resetting an operator's cap to 0 causes divWad by zero, bricking deposits/withdrawals.

- Payout: Contest reward
- Severity: high
- Program: Rio Network Core Protocol
- Credited: almurhasan
- Disclosed: 2024-02-14
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2024-02-rio-network-core-protocol-judging/issues/193
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-02-rio-network-core-protocol%3AH-8
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:dos

**Target:** OperatorUtilizationHeap / RioLRTOperatorRegistry (Solidity)
**Root cause:** _remove does `self.operators[i] = self.operators[self.count--]`, leaving the old last slot populated in storage; getOperatorUtilizationHeapForStrategy then reads that stale operator whose cap is now 0 and computes allocation.divWad(cap).
**Steps:**
1. Deploy 3 operators with caps 1000e18 each; deposit 1002e18 cbETH and rebalance so all operators have allocations.
2. Owner calls `setOperatorStrategyShareCaps(2, [{strategy: CBETH_STRATEGY, cap: 0}])` to remove operator 2.
3. Deposit 10e18 more cbETH, skip rebalanceDelay, call `rebalance(CBETH_ADDRESS)`.
4. Rebalance reverts with `DivWadFailed()` because heap slot still holds removed operator ID with cap 0.
**How found:** Code review of heap removeByID/_remove and getOperatorUtilizationHeapForStrategy; noticed _remove does not clear the vacated last slot, then traced how the stale ID with cap 0 reaches divWad.
**Exploitation:** No attacker; the intended admin workflow (zeroing an operator's cap) leaves a stale heap entry, so every subsequent rebalance/deposit/withdrawal reverts, locking funds until manual deactivation.
**Insight:** When auditing array-backed heaps/maps persisted to storage, check that removal clears the vacated slot, not just decrements count; stale entries resurface on reload and can hit division-by-zero or wrong-operator paths.
