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

liquidateAccounts() incorrectly sets openInterest/skew to 0

Summary

every time liquidateAccounts() is executed the market's openInterest/skew is cleared to 0 by error

Vulnerability Details

in liquidateAccounts()
We will update the openInterest/skew of the market.

function liquidateAccounts(uint128[] calldata accountsIds) external {
...
for (uint256 j; j < ctx.activeMarketsIds.length; j++) {
// load current active market id into working data
ctx.marketId = ctx.activeMarketsIds[j].toUint128();
...
// update funding rates for this perpetual market
perpMarket.updateFunding(ctx.fundingRateX18, ctx.fundingFeePerUnitX18);
// reset the position
position.clear();
// update account's active markets; this calls EnumerableSet::remove which
// is why we are iterating over a memory copy of the trader's active markets
tradingAccount.updateActiveMarkets(ctx.marketId, ctx.oldPositionSizeX18, SD59x18_ZERO);
// update perp market's open interest and skew; we don't enforce ipen
// interest and skew caps during liquidations as:
// 1) open interest and skew are both decreased by liquidations
// 2) we don't want liquidation to be DoS'd in case somehow those cap
// checks would fail
@> perpMarket.updateOpenInterest(ctx.newOpenInterestX18, ctx.newSkewX18);
}
function updateOpenInterest(Data storage self, UD60x18 newOpenInterest, SD59x18 newSkew) internal {
self.skew = newSkew.intoInt256().toInt128();
self.openInterest = newOpenInterest.intoUint128();
}

The method ends up executing perpMarket.updateOpenInterest(ctx.newOpenInterestX18, ctx.newSkewX18);
The problem is: ctx.newOpenInterestX18, ctx.newSkewX18 is not calculated, it is always 0
So after updateOpenInterest() the market's openInterest/skew will be set to 0

Impact

openInterest/skew is cleared to 0, causing any calculations that depend on these two variables to be wrong
For example

  1. openInterest is cleared, fillOrder()->checkOpenInterestLimits()->openInterest - oldPositionSize may underflow , order execution fails

  2. skew is cleared, getMarkPrice() is miscalculated.

  3. ... etc.

Tools Used

Recommendations

function liquidateAccounts(uint128[] calldata accountsIds) external {
...
for (uint256 j; j < ctx.activeMarketsIds.length; j++) {
+ ctx.newOpenInterestX18 = ud60x18(perpMarket.openInterest).sub(ctx.oldPositionSizeX18.abs().intoUD60x18());
+ ctx.newSkewX18 = ctx.newSkewX18.add(ctx.liquidationSizeX18);
perpMarket.updateOpenInterest(ctx.newOpenInterestX18, ctx.newSkewX18);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

`liquidateAccounts` calls `updateOpenInterest` with uninitialized OI and skew)

Support

FAQs

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