Part 2

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

market's credit capacity is incorrectly calculated

Summary

Currently, market's credit capacity is delegatedCreditUsd + marketTotalDebtUsd . However, it should be calculated as delegatedCreditUsd - marketTotalDebtUsd.

Vulnerability Details

Market's credit capacity is calculated as follows:

function getCreditCapacityUsd(
UD60x18 delegatedCreditUsdX18,
SD59x18 totalDebtUsdX18
)
internal
pure
returns (SD59x18 creditCapacityUsdX18)
{
creditCapacityUsdX18 = delegatedCreditUsdX18.intoSD59x18().add(totalDebtUsdX18); // @audit debt should be subtracted
}

According to current implementation, market's credit capacity is calculated as follows:

(1)

However since delegated credit is credit from vaults. totalDebtUsd should be deducted, not added.

Further Argument why totalDebtUsdshould be deducted

One can argue that since totalDebtUsdX18 is a signed integer, it represents not just debt but more like market's PnL.

In other words, totalDebtUsdX18is a negative vaule if the market suffers from loss, and it's a positive one when market has some profit.

Then (1) might make sense, considering if totalDebtUsdX18represents markets PnL.

Even in this assumption, other things break:

In protocol, market's debt is distributed to connected vaults based on credit delegation pro rata.

If market's totalDebtUsdX18 represents market's PnL, we can rearticulate the above sentence as the following:

market's PnL is distributed to connected vaults' PnL, and vault's realized debt represents connected market's PnL

However, this is not true.

Check how Vault.getTotalCreditCapacityUsdis implemented:

creditCapacityUsdX18 = totalAssetsUsdX18.intoSD59x18().sub(getTotalDebt(self));

If vault's debt represents vault's PnL, totalDebtshould not be subtracted from totalAssetsUsd. It should be added.

Also check how Vault.getUnsettledRealizedDebtis calculated:

unsettledRealizedDebtUsdX18 =
sd59x18(self.marketsRealizedDebtUsd).add(unary(ud60x18(self.depositedUsdc).intoSD59x18()));

It is calculated as marketsRealizedDebtUsd - depositedUsdc. As depositedUsdc represents market's profit, this means vault's debt represents debt, not vault's PnL.

The conclusion is, market's totalDebtUsdX18does not represent PnL, it represents actual debt.

So total credit capacity should deduct total debt, instead of adding.

Impact

Market's credit capacity affects the following area:

  • usd token minting capability

  • adjusted profit of market

So incorrect calculation of market credit capacity will bring the following vulnerabillity:

  • Usd token can be minted as much as market's total debt. This will ultimately lead to protocol insolvency

  • market's adjusted profit will be calculated incorrectly.

Tools Used

Manual Review, Foundry

Recommendations

Market's credit capacity usd should be calculated like

Updates

Lead Judging Commences

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

Market::getCreditCapacityUsd overestimates the credit capacity (it adds instead of substracting)

Support

FAQs

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