# Rebalancing can be indefinitely blocked due to ever-increasing `totalWithdrawalRequests`, causing locking of funds in vaults

XChainController never resets totalWithdrawalRequests between rebalances, so it accumulates until it exceeds vault totalUnderlying, underflowing and permanently blocking rebalancing and withdrawals.

- Payout: Contest reward
- Severity: medium
- Program: Derby
- Credited: Jeiwan
- Disclosed: 2022-10-17
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-01-derby-judging/issues/311
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-01-derby%3AM-14
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:sherlock sev:medium tech:solidity technique:source-review vuln:accounting-error vuln:dos

**Target:** XChainController / MainVault rebalancing accounting (Solidity)
**Root cause:** XChainController.resetVaultUnderlying resets totalUnderlying, totalSupply and underlyingReceived but not totalWithdrawalRequests, so the value accumulates across rebalance periods instead of tracking only the current period.
**Steps:**
1. Depositor calls requestWithdrawal on MainVault; MainVault.totalWithdrawalRequests increases and is pushed to XChainController via pushTotalUnderlyingToController, which adds to vaults[n].totalWithdrawalRequests.
2. Rebalance completes; MainVault resets its own totalWithdrawalRequests to 0 and moves amount into reservedFunds, but XChainController's copy is never zeroed.
3. Next rebalance: Game pushes allocations, XChainController calls resetVaultUnderlying which zeroes totalUnderlying but leaves totalWithdrawalRequests intact.
4. Repeat over periods until accumulated totalWithdrawalRequests > getTotalUnderlyingVault(n).
5. pushVaultAmounts executes `getTotalUnderlyingVault(n) - totalWithdrawalRequests`, underflows and reverts, blocking rebalancing indefinitely.
6. Guardian recovery functions also fail to reset the variable, so rebalancing cannot be forced through; pending withdrawals stay locked.
**How found:** Code reading of the rebalancing lifecycle: noticed MainVault resets its totalWithdrawalRequests after rebalance while XChainController's counterpart is only ever incremented, then traced resetVaultUnderlying to confirm it omits the field, and reasoned the subtraction in pushVaultAmounts would eventually underflow.
**Exploitation:** Not an attacker-triggered exploit; the flaw is triggered by normal repeated withdrawal requests over time. Any depositor requesting withdrawals contributes to the accumulation, eventually bricking the rebalance pipeline and locking all vault funds since withdrawals only execute after a successful rebalance.
**Insight:** When a mirrored accounting variable exists on both a vault and a controller, diff their reset paths: a field zeroed on one side but only incremented on the other is a latent underflow/DoS. Check whether guardian/admin recovery functions can reset the stale field.
