Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Invalid

Incorrect debt distribution when totalDelegatedCredit is zero in Market::distributeDebtToVaults

Summary

The function distributeDebtToVaults in Market.sol has a potential division-by-zero vulnerability due to an insufficient check on totalVaultSharesX18. The function includes a check to prevent distribution when there is zero delegated credit, but it does not revalidate this condition before division occurs. This could lead to contract failure, incorrect debt distribution, or panic state misclassification under certain market conditions.

Vulnerability

417: function distributeDebtToVaults(
Data storage self,
SD59x18 newUnrealizedDebtUsdX18,
SD59x18 newRealizedDebtUsdX18
)
internal
{
// cache the total vault's shares as SD59x18
SD59x18 totalVaultSharesX18 = ud60x18(self.totalDelegatedCreditUsd).intoSD59x18();
// if there is zero delegated credit and we're trying to distribute debt to vaults, we should revert and the
// market is considered to be in a panic state
@> if (totalVaultSharesX18.isZero()) {
@> revert Errors.NoDelegatedCredit(self.id); // here
}
// update storage values
self.realizedDebtUsdPerVaultShare = newRealizedDebtUsdX18.div(totalVaultSharesX18).intoInt256().toInt128();
self.unrealizedDebtUsdPerVaultShare = newUnrealizedDebtUsdX18.div(totalVaultSharesX18).intoInt256().toInt128();
}
  • This check only validates the value at the beginning of the function.

  • If totalVaultSharesX18 becomes zero after this check (due to changes in state variables or external calls), any subsequent division operation involving totalVaultSharesX18 may cause a division-by-zero error.

  • This could result in unexpected contract behavior, including:

    • Reverts halting contract execution.

    • Incorrect debt distribution.

Impact

  • If exploited or encountered, this could completely break debt distribution logic, potentially leading to incorrect credit allocations or contract failures.

  • The impact depends on whether totalVaultSharesX18 is modified dynamically before division, which varies based on contract interactions.

Tools Used

  • Manual Code Review

Recommendations

  • Add an additional check right before any division to ensure totalVaultSharesX18 has not changed

  • Instead of performing a direct division, ensure totalVaultSharesX18 is non-zero before performing calculations:

if (!totalVaultSharesX18.isZero()) {
SD59x18 debtPerShare = newUnrealizedDebtUsdX18.div(totalVaultSharesX18);
} else {
revert Errors.NoDelegatedCredit(self.id);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
10 months ago
inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!