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

Wrong calculation of `fundingRateX18` in `SettlementBranch::_fillOrder`

Summary

When a user's order is being filled the new funding fee is calculated in order to account it in the unrealizedPnl. The logic used for calculating funding fee is based on the skew of the market. The problem lies in the fact that the code is using the old skew instead of the new one which accounts for the sizeDelta of the order which results in wrong calculations of the funding fee.

Vulnerability Details

In SettlementBranch::_fillOdrer the new funding fee is calculated and updated for the market in order to be used for the current trade:

// get funding rates for this perp market
ctx.fundingRateX18 = perpMarket.getCurrentFundingRate();
ctx.fundingFeePerUnitX18 = perpMarket.getNextFundingFeePerUnit(ctx.fundingRateX18, fillPriceX18);
// update funding rates
perpMarket.updateFunding(ctx.fundingRateX18, ctx.fundingFeePerUnitX18);

If we see how fundingRateX18 is calculated by going in PerpMarket::getCurrentFundingRate we can see that it calls PerpMarket::getCurrentFundingVelocity where the skew of the market is used:

/// @notice Returns the current funding rate of the given market.
/// @param self The PerpMarket storage pointer.
function getCurrentFundingRate(Data storage self) internal view returns (SD59x18) {
return sd59x18(self.lastFundingRate).add(
getCurrentFundingVelocity(self).mul(getProportionalElapsedSinceLastFunding(self).intoSD59x18())
);
}
/// @notice Returns the current funding velocity of the given market.
/// @param self The PerpMarket storage pointer.
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);
}

But the skew of the market is updated only later on in the SettlementBranch::_fillOrder function, meaning that the current funding fee is outdated and will not be the correct value:

// get funding rates for this perp market
ctx.fundingRateX18 = perpMarket.getCurrentFundingRate();
ctx.fundingFeePerUnitX18 = perpMarket.getNextFundingFeePerUnit(ctx.fundingRateX18, fillPriceX18);
// update funding rates
perpMarket.updateFunding(ctx.fundingRateX18, ctx.fundingFeePerUnitX18);
// calculate order & settlement fees
ctx.orderFeeUsdX18 = perpMarket.getOrderFeeUsd(sizeDeltaX18, fillPriceX18);
ctx.settlementFeeUsdX18 = ud60x18(uint256(settlementConfiguration.fee));
...
// update open interest and skew for this perp market
@> perpMarket.updateOpenInterest(ctx.newOpenInterestX18, ctx.newSkewX18);

Impact

Incorrect calculation of funding fee which results in traders receiving more/less funds than they are supposed to.

Tools Used

Manual Review
VS Code

Recommendations

Use the updated skew when calculating the funding fee

Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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