Summary
The getAdjustedProfitForMarketId()
function uses stale credit capacity data leading to incorrect profit calculations.
Vulnerability Details
In _fillOrder()
, when calculating the margin to add for positive PnL positions, the code uses outdated credit capacity values:
File: SettlementBranch.sol
494:
495: if (ctx.pnlUsdX18.gt(SD59x18_ZERO)) {
496: IMarketMakingEngine marketMakingEngine = IMarketMakingEngine(perpsEngineConfiguration.marketMakingEngine);
497:
498: ctx.marginToAddX18 =
499: marketMakingEngine.getAdjustedProfitForMarketId(marketId, ctx.pnlUsdX18.intoUD60x18().intoUint256());
500:
501: tradingAccount.deposit(perpsEngineConfiguration.usdToken, ctx.marginToAddX18);
502:
503:
504:
505: marketMakingEngine.withdrawUsdTokenFromMarket(marketId, ctx.marginToAddX18.intoUint256());
506: }
It's because getAdjustedProfitForMarketId()
returns stale credit capacity without updating the credit capacity.
function getAdjustedProfitForMarketId(
uint128 marketId,
uint256 profitUsd
)
public
view
returns (UD60x18 adjustedProfitUsdX18)
{
Market.Data storage market = Market.loadLive(marketId);
SD59x18 marketTotalDebtUsdX18 = market.getTotalDebt();
UD60x18 delegatedCreditUsdX18 = market.getTotalDelegatedCreditUsd();
SD59x18 creditCapacityUsdX18 = Market.getCreditCapacityUsd(delegatedCreditUsdX18, marketTotalDebtUsdX18);
if (creditCapacityUsdX18.lte(SD59x18_ZERO)) {
revert Errors.InsufficientCreditCapacity(marketId, creditCapacityUsdX18.intoInt256());
}
adjustedProfitUsdX18 = ud60x18(profitUsd);
if (market.isAutoDeleverageTriggered(delegatedCreditUsdX18, marketTotalDebtUsdX18)) {
adjustedProfitUsdX18 =
market.getAutoDeleverageFactor(delegatedCreditUsdX18, marketTotalDebtUsdX18).mul(adjustedProfitUsdX18);
}
}
Impact
The discrepancy between previewed and actual withdrawn amounts can lead to incorrect internal accounting and potential protocol insolvency.
Recommendations
The recalculateVaultsCreditCapacity()
should be called before calculating adjustedProfitUsdX18
in the _fillOrder()
function.