Summary
When a trader's old position has a positive PnL and the market is in the ADL state, the trader's pnlUsd
is deducted twice at lines 499 and 505.
Vulnerability Details
if (ctx.pnlUsdX18.gt(SD59x18_ZERO)) {
IMarketMakingEngine marketMakingEngine = IMarketMakingEngine(perpsEngineConfiguration.marketMakingEngine);
ctx.marginToAddX18 =
499: marketMakingEngine.getAdjustedProfitForMarketId(marketId, ctx.pnlUsdX18.intoUD60x18().intoUint256());
tradingAccount.deposit(perpsEngineConfiguration.usdToken, ctx.marginToAddX18);
505: marketMakingEngine.withdrawUsdTokenFromMarket(marketId, ctx.marginToAddX18.intoUint256());
}
function withdrawUsdTokenFromMarket(uint128 marketId, uint256 amount) external onlyRegisteredEngine(marketId) {
...
if (market.isAutoDeleverageTriggered(delegatedCreditUsdX18, marketTotalDebtUsdX18)) {
UD60x18 adjustedUsdTokenToMintX18 =
market.getAutoDeleverageFactor(delegatedCreditUsdX18, marketTotalDebtUsdX18).mul(amountX18);
291: amountToMint = adjustedUsdTokenToMintX18.intoUint256();
market.updateNetUsdTokenIssuance(adjustedUsdTokenToMintX18.intoSD59x18());
} else {
market.updateNetUsdTokenIssuance(amountX18.intoSD59x18());
}
MarketMakingEngineConfiguration.Data storage marketMakingEngineConfiguration =
MarketMakingEngineConfiguration.load();
UsdToken usdToken = UsdToken(marketMakingEngineConfiguration.usdTokenOfEngine[msg.sender]);
usdToken.mint(msg.sender, amountToMint);
emit LogWithdrawUsdTokenFromMarket(msg.sender, marketId, amount, amountToMint);
}
When a trader's old position has a positive PnL and the market is in the ADL state, the trader's pnlUsd is deducted twice at lines 499 and 505.
Therefore, the trader receives the margin, which is deducted once with UsdToken, but the market issues the double-deducted UsdToken.
Impact
Due to the shortage of UsdToken, some traders may not receive their funds.
Accounting will be miscalculated because the market's accounting of debt is inaccurate.
Recommendations
Considering the full withdrawal in the withdrawUsdTokenFromMarket
function.