Part 2

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

Incorrect credit capacity calculation in `getCreditCapacityForMarketId()`

Summary

The getCreditCapacityForMarketId() function incorrectly adds total debt to delegated credit instead of subtracting it, causing incorrect credit capacity calculations.

Vulnerability Details

In CreditDelegationBranch.sol, the credit capacity calculation is performed when checking market's credit capacity:

File: CreditDelegationBranch.sol
113: function getCreditCapacityForMarketId(uint128 marketId) public view returns (SD59x18) {
114: Market.Data storage market = Market.loadExisting(marketId);
115:
116: return Market.getCreditCapacityUsd(market.getTotalDelegatedCreditUsd(), market.getTotalDebt());
117: }
File: Market.sol
189: function getCreditCapacityUsd(
190: UD60x18 delegatedCreditUsdX18,
191: SD59x18 totalDebtUsdX18
192: )
193: internal
194: pure
195: returns (SD59x18 creditCapacityUsdX18)
196: {
197: creditCapacityUsdX18 = delegatedCreditUsdX18.intoSD59x18().add(totalDebtUsdX18);
198: }

In getCreditCapacityUsd(), it adds total debt to delegated credit but it's incorrect because a negative total debt means that the market has more credit.

We can confirm that from getTotalDebt() and getRealizedDebtUsd(). When depositCreditForMarket() is called netUsdTokenIssuance is decreased which means that negative netUsdTokenIssuance and also debt mean that the market has more credit.

File: Market.sol
264: function getTotalDebt(Data storage self) internal view returns (SD59x18 totalDebtUsdX18) {
265: totalDebtUsdX18 = getUnrealizedDebtUsd(self).add(getRealizedDebtUsd(self));
266: }
File: Market.sol
234: function getRealizedDebtUsd(Data storage self) internal view returns (SD59x18 realizedDebtUsdX18) {
235: // prepare the credit deposits usd value variable;
236: UD60x18 creditDepositsValueUsdX18;
237:
238: // if the credit deposits usd value cache is up to date, return the stored value
239: if (block.timestamp <= self.lastCreditDepositsValueRehydration) {
240: creditDepositsValueUsdX18 = ud60x18(self.creditDepositsValueCacheUsd);
241: } else {
242: // otherwise, we'll need to loop over credit deposits to calculate it
243: creditDepositsValueUsdX18 = getCreditDepositsValueUsd(self);
244: }
245:
246: // finally after determining the market's latest credit deposits usd value, sum it with the stored net usd
247: // token issuance to return the net realized debt usd value
248: realizedDebtUsdX18 = creditDepositsValueUsdX18.intoSD59x18().add(sd59x18(self.netUsdTokenIssuance));
249: }
File: CreditDelegationBranch.sol
212: // note: storage updates must occur using zaros internal precision
213: if (collateralAddr == usdToken) {
214: // if the deposited collateral is USD Token, it reduces the market's realized debt
215: market.updateNetUsdTokenIssuance(unary(amountX18.intoSD59x18()));

Impact

The system calculates the credit capacity incorrectly that will affect many operations.

Recommendations

Modify the credit capacity calculation to subtract total debt from delegated credit instead of adding it.

Updates

Lead Judging Commences

inallhonesty Lead Judge 6 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.