Rebalancing can be indefinitely blocked due to ever-increasing `totalWithdrawalRequests`, causing locking of funds in vaults
Rebalancing can get stuck indefinitely at the `pushVaultAmounts` step due to an error in the accounting of `totalWithdrawalRequests`. As a result, funds will be locked in vaults since requested withdrawals are only executed after a next successful rebalance.\\nFunds deposited to underlying protocols can only be withdrawn from vaults after a next successful rebalance:\\na depositor has to make a withdrawal request first, which is tracked in the current rebalance period;\\nrequested funds can be withdrawn in the next rebalance period.\\nThus, it's critical that rebalancing doesn't get stuck during one of its stages.\\nDuring rebalancing, vaults report their balances to `XChainController` via the pushTotalUnderlyingToController function: the functions sends the current unlocked (i.e. excluding reserved funds) underlying token balance of the vault and the total amount of withdrawn requests in the current period. The latter amount is stored in the `totalWithdrawalRequests` storage variable:\\nthe variable is increased when a new withdrawal request is made;\\nand it's set to 0 after the vault has been rebalanced-it's value is added to the reserved funds.\\nThe logic of `totalWithdrawalRequests` is that it tracks only the requested withdrawal amounts in the current period-this amount becomes reserved during rebalancing and is added to `reservedFunds` after the vault has been rebalanced.\\nWhen `XChainController` receives underlying balances and withdrawal requests from vaults, it tracks them internally. The amounts then used to calculate how much tokens a vault needs to send or receive after a rebalancing: the total withdrawal amount is subtracted from vault's underlying balance so that it's excluded from the amounts that will be sent to the protocols and so that it could then be added to the reserved funds of the vault.\\nHowever, `totalWithdrawalRequests` in `XChainController` is not reset between rebalancings: when a new rebalancing starts, `XChainController` receives allocations from the Game and calls `resetVaultUnderlying`, which resets the underlying balances receive from vaults in the previous rebalancing. `resetVaultUnderlying` doesn't set `totalWithdrawalRequests` to 0:\\n```\\nfunction resetVaultUnderlying(uint256 _vaultNumber) internal {\\n  vaults[_vaultNumber].totalUnderlying = 0;\\n  vaultStage[_vaultNumber].underlyingReceived = 0;\\n  vaults[_vaultNumber].totalSupply = 0;\\n}\\n```\\n\\nThis cause the value of `totalWithdrawalRequests` to accumulate over time. At some point, the total historical amount of all withdrawal requests (which `totalWithdrawalRequests` actually tracks) will be greater than the underlying balance of a vault, and this line will revert due to an underflow in the subtraction:\\n```\\nuint256 totalUnderlying = getTotalUnderlyingVault(_vaultNumber) - totalWithdrawalRequests;\\n```\\n
In `XChainController.resetVaultUnderlying`, consider setting `vaults[_vaultNumber].totalWithdrawalRequests` to 0. `totalWithdrawalRequests`, like its `MainVault.totalWithdrawalRequests` counterpart, tracks withdrawal requests only in the current period and should be reset to 0 between rebalancings.
Due to accumulation of withdrawal request amounts in the `totalWithdrawalRequests` variable, `XChainController.pushVaultAmounts` can be blocked indefinitely after the value of `totalWithdrawalRequests` has grown bigger than the value of `totalUnderlying` of a vault. Since withdrawals from vaults are delayed and enable in a next rebalancing period, depositors may not be able to withdraw their funds from vaults, due to a block rebalancing.\\nWhile `XChainController` implements a bunch of functions restricted to the guardian that allow the guardian to push a rebalancing through, neither of these functions resets the value of `totalWithdrawalRequests`. If `totalWithdrawalRequests` becomes bigger than `totalUnderlying`, the guardian won't be able to fix the state of `XChainController` and push the rebalancing through.
```\\nfunction resetVaultUnderlying(uint256 _vaultNumber) internal {\\n  vaults[_vaultNumber].totalUnderlying = 0;\\n  vaultStage[_vaultNumber].underlyingReceived = 0;\\n  vaults[_vaultNumber].totalSupply = 0;\\n}\\n```\\n