Debt cannot be repaid without redeeming vault share
Debt cannot be repaid without redeeming the vault share. As such, users have to redeem a certain amount of vault shares/strategy tokens at the current market price to work around this issue, which deprives users of potential gains from their vault shares if they maintain ownership until the end.\\n```\\nFile: VaultAccountAction.sol\\n    function exitVault(\\n        address account,\\n        address vault,\\n        address receiver,\\n        uint256 vaultSharesToRedeem,\\n        uint256 lendAmount,\\n        uint32 minLendRate,\\n        bytes calldata exitVaultData\\n    ) external payable override nonReentrant returns (uint256 underlyingToReceiver) {\\n..SNIP..\\n        // If insufficient strategy tokens are redeemed (or if it is set to zero), then\\n        // redeem with debt repayment will recover the repayment from the account's wallet\\n        // directly.\\n        underlyingToReceiver = underlyingToReceiver.add(vaultConfig.redeemWithDebtRepayment(\\n            vaultAccount, receiver, vaultSharesToRedeem, exitVaultData\\n        ));\\n```\\n\\nThere is a valid scenario where users want to repay debt without redeeming their vault shares/strategy tokens (mentioned in the comments above "or if it is set to zero" at Line 251-263). In this case, the users will call `exitVault` with `vaultSharesToRedeem` parameter set to zero. The entire debt to be repaid will then be recovered directly from the account's wallet.\\nFollowing is the function trace of the VaultAccountAction.exitVault:\\n```\\nVaultAccountAction.exitVault\\n└─VaultConfiguration.redeemWithDebtRepayment\\n  └─VaultConfiguration._redeem\\n    └─IStrategyVault.redeemFromNotional\\n      └─MetaStable2TokenAuraVault._redeemFromNotional\\n        └─MetaStable2TokenAuraHelper.redeem\\n          └─Balancer2TokenPoolUtils._redeem\\n            └─StrategyUtils._redeemStrategyTokens\\n```\\n\\n```\\nFile: StrategyUtils.sol\\n    function _redeemStrategyTokens(\\n        StrategyContext memory strategyContext,\\n        uint256 strategyTokens\\n    ) internal returns (uint256 poolClaim) {\\n        poolClaim = _convertStrategyTokensToPoolClaim(strategyContext, strategyTokens);\\n\\n        if (poolClaim == 0) {\\n            revert Errors.ZeroPoolClaim();\\n        }\\n```\\n\\nThe problem is that if the vault shares/strategy tokens to be redeemed are zero, the `poolClaim` will be zero and cause a revert within the `StrategyUtils._redeemStrategyTokens` function call. Thus, users who want to repay debt without redeeming their vault shares/strategy tokens will be unable to do so.
Within the `VaultConfiguration.redeemWithDebtRepayment` function, skip the vault share redemption if `vaultShares` is zero. In this case, the `amountTransferred` will be zero, and the subsequent code will attempt to recover the entire `underlyingExternalToRepay` amount directly from account's wallet.\\n```\\nfunction redeemWithDebtRepayment(\\n VaultConfig memory vaultConfig,\\n VaultAccount memory vaultAccount,\\n address receiver,\\n uint256 vaultShares,\\n bytes calldata data\\n) internal returns (uint256 underlyingToReceiver) {\\n uint256 amountTransferred;\\n uint256 underlyingExternalToRepay;\\n {\\n..SNIP..\\n// Add the line below\\n  if (vaultShares > 0) {\\n   // Repayment checks operate entirely on the underlyingExternalToRepay, the amount of\\n   // prime cash raised is irrelevant here since tempCashBalance is cleared to zero as\\n   // long as sufficient underlying has been returned to the protocol.\\n   (amountTransferred, underlyingToReceiver, /* primeCashRaised */) = _redeem(\\n    vaultConfig,\\n    underlyingToken,\\n    vaultAccount.account,\\n    receiver,\\n    vaultShares,\\n    vaultAccount.maturity,\\n    underlyingExternalToRepay,\\n    data\\n   ); \\n// Add the line below\\n  }\\n..Recover any unpaid debt amount from the account directly..\\n..SNIP..\\n```\\n\\nAlternatively, update the `StrategyUtils._redeemStrategyTokens` function to handle zero vault share appropriately. However, note that the revert at Line 154 is added as part of mitigation to the "minting zero-share" bug in the past audit. Therefore, any changes to this part of the code must ensure that the "minting zero-share" bug is not being re-introduced. Removing the code at 153-155 might result in the user's vault share being "burned" but no assets in return under certain conditions.\\n```\\nFile: StrategyUtils.sol\\n    function _redeemStrategyTokens(\\n        StrategyContext memory strategyContext,\\n        uint256 strategyTokens\\n    ) internal returns (uint256 poolClaim) {\\n        poolClaim = _convertStrategyTokensToPoolClaim(strategyContext, strategyTokens);\\n\\n        if (poolClaim == 0) {\\n            revert Errors.ZeroPoolClaim();\\n        }\\n```\\n
Users cannot repay debt without redeeming their vault shares/strategy tokens. To do so, they have to redeem a certain amount of vault shares/strategy tokens at the current market price to work around this issue so that `poolClaim > 0`, which deprives users of potential gains from their vault shares if they maintain ownership until the end.
```\\nFile: VaultAccountAction.sol\\n    function exitVault(\\n        address account,\\n        address vault,\\n        address receiver,\\n        uint256 vaultSharesToRedeem,\\n        uint256 lendAmount,\\n        uint32 minLendRate,\\n        bytes calldata exitVaultData\\n    ) external payable override nonReentrant returns (uint256 underlyingToReceiver) {\\n..SNIP..\\n        // If insufficient strategy tokens are redeemed (or if it is set to zero), then\\n        // redeem with debt repayment will recover the repayment from the account's wallet\\n        // directly.\\n        underlyingToReceiver = underlyingToReceiver.add(vaultConfig.redeemWithDebtRepayment(\\n            vaultAccount, receiver, vaultSharesToRedeem, exitVaultData\\n        ));\\n```\\n