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

maxSkew more than skewScale can break the protocol

Summary

The protocol's core functionality is broken maxSkew is more than skewScale in MarketConfiguration of perp market. skew can range from -maxSkew to maxSkew in most of scenarios(unless owner changes maxSkew variable when abs(skew) > maxSkew), which can lead to incorrect calculations of priceImpactBeforeDelta and priceImpactAfterDeltaand even revert of getMarkPricefunction. Looking at tentative deployment script by the protocol, it is possibility that maxSkewcan be more than skewScale. Also, the sponsor confirmed that there can be possibility of this(but if you think there's a potential vector when max_skew > skew_scale please try to explore it)

Vulnerability Details

The function getMarkPricein PerpMarketis as follows. Now, let's analyze about what if maxSkewis more than skewScale. maxSkewand skewScaleare positive uint256variable. skewcan range between -maxSkewto maxSkew. For the sake of simplicity, let's assume skewand newSkeware negative and their absolute value lies between skewScaleand maxSkew. i.e. skewScale< abs(skew)< maxSkewand skewScale< abs(newSkew)< maxSkew.So, in following function, priceImpactBeforeDeltawill be less than -1and priceImpactAfterDeltawill also be less than -1. Due to this, cachedIndexPriceX18.add(cachedIndexPriceX18.mul(priceImpactBeforeDelta)).intoUD60x18();will revert because cachedIndexPriceX18.add(cachedIndexPriceX18.mul(priceImpactBeforeDelta))is negative and can't be converted to UD60x18. The error reverted is CastingErrors.PRBMath_SD1x18_ToUD60x18_Underflow(x).

https://github.com/Cyfrin/2024-07-zaros/blob/d687fe96bb7ace8652778797052a38763fbcbb1b/src/perpetuals/leaves/PerpMarket.sol#L98-L122

function getMarkPrice(
Data storage self,
SD59x18 skewDelta,
UD60x18 indexPriceX18
)
internal
view
returns (UD60x18 markPrice)
{
SD59x18 skewScale = sd59x18(self.configuration.skewScale.toInt256());
SD59x18 skew = sd59x18(self.skew);
SD59x18 priceImpactBeforeDelta = skew.div(skewScale);
SD59x18 newSkew = skew.add(skewDelta);
SD59x18 priceImpactAfterDelta = newSkew.div(skewScale);
SD59x18 cachedIndexPriceX18 = indexPriceX18.intoSD59x18();
UD60x18 priceBeforeDelta =
cachedIndexPriceX18.add(cachedIndexPriceX18.mul(priceImpactBeforeDelta)).intoUD60x18();
UD60x18 priceAfterDelta =
cachedIndexPriceX18.add(cachedIndexPriceX18.mul(priceImpactAfterDelta)).intoUD60x18();
markPrice = priceBeforeDelta.add(priceAfterDelta).div(ud60x18Convert(2));
}

Impact

Due to revert in getMarkPricefunction, all the functions using it will revert. Due to this, no market orders can be created, no orders(onchain and offchain) can be settled and no accounts can be liquidated

1) Creation of order in OrderBranch
2) fillMarketOrder and fillOffChainOrders in SettlementBranch
3) liquidateAccounts in LiquidationBranch

Tools Used

Manual review

Recommendations

Ensure that skewScaleis always more than maximum value the skewcan reach. Otherwise, priceImpactBeforeDeltaand priceImpactAfterDeltacan be bounded to [-1,1]as done in getCurrentFundingVelocity

Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Appeal created

cryptomoon Submitter
about 1 year ago
inallhonesty Lead Judge
about 1 year ago
cryptomoon Submitter
about 1 year ago
inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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