Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Invalid

Incorrect Leverage Calculation Due to Negative Margin Balance

Summary

The getAccountLeverage function incorrectly calculates leverage when an account has a negative margin balance, leading to misleading leverage metrics.

Vulnerability Details

The getAccountLeverage function is responsible for calculating the leverage of a trading account by dividing the total notional value of the account's positions by its margin balance. The function retrieves the margin balance as a signed value (SD59x18), which can be negative if the account is undercollateralized. It then converts this signed value to an unsigned value (UD60x18) using intoUD60x18(). This conversion can lead to incorrect leverage calculations if the margin balance is negative, as the conversion from signed to unsigned types without handling negative values can result in unexpected behavior, such as reverting or producing large incorrect leverage values.

This misrepresents the account's actual risk, potentially hiding insolvency or leading to erroneous risk assessments.

Impact

I'm rating this as medium because it allows for incorrect leverage calculations, which can misrepresent the account's actual risk and potentially hide insolvency.

Tools Used

Manual Review

Recommendations

Make sure the conversion from signed to unsigned types handles negative values appropriately, possibly by enforcing a check that prevents negative margin balances from being converted or used in leverage calculations.

function getAccountLeverage(uint128 tradingAccountId) external view returns (UD60x18) {
TradingAccount.Data storage tradingAccount = TradingAccount.loadExisting(tradingAccountId);
SD59x18 marginBalanceUsdX18 = tradingAccount.getMarginBalanceUsd(tradingAccount.getAccountUnrealizedPnlUsd());
UD60x18 totalPositionsNotionalValue;
if (marginBalanceUsdX18.isZero()) return marginBalanceUsdX18.intoUD60x18();
// Check for negative margin balance
if (marginBalanceUsdX18.lt(SD59x18_ZERO)) {
revert Errors.NegativeMarginBalance(tradingAccountId);
}
for (uint256 i; i < tradingAccount.activeMarketsIds.length(); i++) {
uint128 marketId = tradingAccount.activeMarketsIds.at(i).toUint128();
PerpMarket.Data storage perpMarket = PerpMarket.load(marketId);
Position.Data storage position = Position.load(tradingAccountId, marketId);
UD60x18 indexPrice = perpMarket.getIndexPrice();
UD60x18 markPrice = perpMarket.getMarkPrice(unary(sd59x18(position.size)), indexPrice);
UD60x18 positionNotionalValueX18 = position.getNotionalValue(markPrice);
totalPositionsNotionalValue = totalPositionsNotionalValue.add(positionNotionalValueX18);
}
return totalPositionsNotionalValue.intoSD59x18().div(marginBalanceUsdX18).intoUD60x18();
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope

Support

FAQs

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

Give us feedback!