Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: high
Valid

Incorrect Credit Capacity Check in VaultRouterBranch::redeem Prevents Redeems

Summary

VaultRouterBranch::redeem aims to check if the credit capacity delta exceeds locked credit capacity before the transition. However, it does the opposite, causing an unintended permanent revert condition. No user can redeem assets from the vault, making it impossible to withdraw funds.


Vulnerability Details

Incorrect Conditional Check Causes Permanent Revert:

if (
ctx.creditCapacityBeforeRedeemUsdX18.sub(vault.getTotalCreditCapacityUsd()).lte(
ctx.lockedCreditCapacityBeforeRedeemUsdX18.intoSD59x18()
)
) {
revert Errors.NotEnoughUnlockedCreditCapacity();
}
  • If creditCapacityBefore - creditCapacityAfter is less than or equal to lockedCreditCapacityBefore, it reverts.

  • This condition always holds (since withdrawing reduces credit capacity), leading to permanent failure, unless a user redeems a lot of tokens, in that case the vault will become insolvent and violate credit locked capacity


Impact

  • Since all redeems will revert, users cannot withdraw assets


Recommendation

Change the condition check to do opposite of what it is currently doing:

function redeem(uint128 vaultId, uint128 withdrawalRequestId, uint256 minAssets) external {
/// Rest of the code
// invariant: received assets must be > 0 even when minAssets = 0
if (assets == 0) revert Errors.RedeemMustReceiveAssets();
// if the credit capacity delta is greater than the locked credit capacity before the state transition, revert
if (
- ctx.creditCapacityBeforeRedeemUsdX18.sub(vault.getTotalCreditCapacityUsd()).lte(
+ ctx.creditCapacityBeforeRedeemUsdX18.sub(vault.getTotalCreditCapacityUsd()).gte(
ctx.lockedCreditCapacityBeforeRedeemUsdX18.intoSD59x18()
)
) {
revert Errors.NotEnoughUnlockedCreditCapacity();
}
// set withdrawal request to fulfilled
withdrawalRequest.fulfilled = true;
// emit an event
emit LogRedeem(vaultId, msg.sender, ctx.sharesMinusRedeemFeesX18.intoUint256());
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

The check in VaultRouterBranch::redeem should be comparing remaining capacity against required locked capacity not delta against locked capacity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!