DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: low
Invalid

Division by Zero in PerpMarketBranch::getOpenInterest Function

Summary

The getOpenInterest function contains divisions that could result in division by zero if perpMarket.skew or perpMarket.openInterest equals zero.

Vulnerability Details

Code Reference:

function getOpenInterest(uint128 marketId)
external
view
returns (UD60x18 longsOpenInterest, UD60x18 shortsOpenInterest, UD60x18 totalOpenInterest)
{
PerpMarket.Data storage perpMarket = PerpMarket.load(marketId);
SD59x18 halfSkew = sd59x18(perpMarket.skew).div(sd59x18(2e18));
SD59x18 currentOpenInterest = ud60x18(perpMarket.openInterest).intoSD59x18();
SD59x18 halfOpenInterest = currentOpenInterest.div(sd59x18(2e18));
longsOpenInterest = halfOpenInterest.add(halfSkew).lt(SD59x18_ZERO)
? UD60x18_ZERO
: halfOpenInterest.add(halfSkew).intoUD60x18();
shortsOpenInterest = unary(halfOpenInterest).add(halfSkew).abs().intoUD60x18();
totalOpenInterest = longsOpenInterest.add(shortsOpenInterest);
}

Proof of Concept:
To demonstrate the risk of division by zero, consider the following steps:

Deployment and Initialization:

  • Deploy PerpMarketBranch.
    Initialize a market with marketId set to a non-zero value.

  • Scenario 1 - Zero Skew:
    Set skew to zero.
    Call getOpenInterest. Example:

uint128 marketId = 1;
(UD60x18 longsOpenInterest, UD60x18 shortsOpenInterest, UD60x18 totalOpenInterest) = perpMarketBranchInstance.getOpenInterest(marketId);

Scenario 2 - Zero Open Interest:

  • Set openInterest to zero.
    Call getOpenInterest. Example:

uint128 marketId = 1;
(UD60x18 longsOpenInterest, UD60x18 shortsOpenInterest, UD60x18 totalOpenInterest) = perpMarketBranchInstance.getOpenInterest(marketId);
  • Expected Behavior:
    Return calculated open interests without errors.

  • Actual Behavior:
    Encounters a division by zero error, causing runtime exceptions.

Impact

Low.
Division by zero can cause critical runtime errors, making open interest calculations unreliable and potentially halting market operations.

Tools Used

Manual code review

Recommendations

Implement a check to ensure indexPrice is greater than zero:

function getOpenInterest(uint128 marketId)
external
view
returns (UD60x18 longsOpenInterest, UD60x18 shortsOpenInterest, UD60x18 totalOpenInterest)
{
PerpMarket.Data storage perpMarket = PerpMarket.load(marketId);
+ if (perpMarket.skew == 0 || perpMarket.openInterest == 0) {
+ return (UD60x18_ZERO, UD60x18_ZERO, UD60x18_ZERO);
}
SD59x18 halfSkew = sd59x18(perpMarket.skew).div(sd59x18(2e18));
SD59x18 currentOpenInterest = ud60x18(perpMarket.openInterest).intoSD59x18();
SD59x18 halfOpenInterest = currentOpenInterest.div(sd59x18(2e18));
longsOpenInterest = halfOpenInterest.add(halfSkew).lt(SD59x18_ZERO)
? UD60x18_ZERO
: halfOpenInterest.add(halfSkew).intoUD60x18();
shortsOpenInterest = unary(halfOpenInterest).add(halfSkew).abs().intoUD60x18();
totalOpenInterest = longsOpenInterest.add(shortsOpenInterest);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge over 1 year 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!