Summary
The getMarkPrice
function in PerpMarket.sol
is susceptible to a division by zero error due to the absence of a check for zero in the skewScale
variable.
Vulnerability Details
The getMarkPrice
function calculates the mark price based on the skew
and the skew scale
. However, if the skewScale
is zero, it will cause a division by zero error, leading to revert.
PerpMarket.sol#L98
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));
}
Here, skewScale
is converted into a signed decimal type (SD59x18). If skewScale
is zero
or can be zero, this could be a potential issue in the subsequent division operation.
SD59x18 priceImpactBeforeDelta = skew.div(skewScale);
This check is correctly implemented in the getCurrentFundingVelocity
function but is missing in getMarkPriceFunction
.
function getCurrentFundingVelocity(Data storage self) internal view returns (SD59x18) {
SD59x18 maxFundingVelocity = sd59x18(uint256(self.configuration.maxFundingVelocity).toInt256());
SD59x18 skewScale = sd59x18(uint256(self.configuration.skewScale).toInt256());
SD59x18 skew = sd59x18(self.skew);
@> if (skewScale.isZero()) {
return SD59x18_ZERO;
}
SD59x18 proportionalSkew = skew.div(skewScale);
SD59x18 proportionalSkewBounded = Math.min(Math.max(unary(SD_UNIT), proportionalSkew), SD_UNIT);
return proportionalSkewBounded.mul(maxFundingVelocity);
}
Impact
getMarkPrice
function will revert
Tools Used
Manual Review
Recommendations
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);
+ if (skewScale.isZero()) {
+ return SD59x18_ZERO;
+ }
SD59x18 priceImpactBeforeDelta = skew.div(skewScale);
SD59x18 newSkew = skew.add(skewDelta);
SD59x18 priceImpactAfterDelta = newSkew.div(skewScale);
....snip....
}