Lost withdrawals due to ManagedLeveragedVault::openDen() using all asset() balance
Summary
ManagedLeveragedVault::openDen() picks up all asset() and converts to collateral. However, some of these assets may be reserved for withdrawals, in which case the tracking would be completely off.
Vulnerability Detail
ManagedLeveragedVault::executeWithdrawalEpoch() converts collateral vault shares to assets and leaves them in the contract.
function executeWithdrawalEpoch(
ExecuteWithdrawalParams calldata params
) external onlyOwner nonReentrant claimCollateralSurplus(params.upperHint, params.lowerHint) {
BoycoVaultStorage storage b$ = _getBoycoVaultStorage();
_checkEpoch(params.epoch);
CollDebt memory cd = _getCollVaultSharesAndDebtToUnwind(params.epoch);
b$.borrowerOperations.adjustDen({
denManager: b$.denManager,
account: address(this),
_maxFeePercentage: params.maxFeePercentage,
_collDeposit: 0,
_collWithdrawal: cd.collVaultSharesToWithdraw,
_debtChange: cd.debtToUnwind,
_isDebtIncrease: false,
_upperHint: params.upperHint,
_lowerHint: params.lowerHint
});
/// @dev Have assets sitting on the contract for `withdrawFromEpoch` to claim
uint256 assets = _rebalance(
RebalanceParams({
sentCurrency: address(b$.collVault),
sentAmount: cd.collVaultSharesToWithdraw,
receivedCurrency: asset(),
ext: params.unwrapParams
})
);
...
}ManagedLeveragedVault::openDen() picks up all asset() available, including the ones reserved for withdrawal.
function openDen(
uint256 _maxFeePercentage,
uint256 _minCollVaultShares,
address _upperHint,
address _lowerHint
) external onlyOwner {
BoycoVaultStorage storage b$ = _getBoycoVaultStorage();
IDenManager denManager = IDenManager(b$.denManager);
uint256 status = denManager.getDenStatus(address(this));
if (DenStatus(status) != DenStatus.active) revert AlreadyOpened();
uint256 collVaultShares;
uint256 assetsAmount = IERC20(asset()).balanceOf(address(this));
if (assetsAmount != 0) {
IERC20(asset()).approve(address(b$.collVault), assetsAmount);
collVaultShares = b$.collVault.deposit(assetsAmount, address(this));
if (collVaultShares < _minCollVaultShares) revert VaultSlippage(_minCollVaultShares, collVaultShares);
}
...
}Impact
DoSed withdrawals, loss of funds as the shares/assets ratio will be off because the shares were already burned.
Code Snippet
Tool Used
Manual Review
Recommendation
Include the reserved assets for withdrawal in the calculation.