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

`LiquidationBranch.sol#liquidateAccounts` function has mistake.

Summary

LiquidationBranch.sol#liquidateAccounts function has mistake of using requiredMaintenanceMarginUsdX18 instead of requiredMaintenanceMarginUsdX18 - ctx.marginBalanceUsdX18 for pnlUsdX18.

Vulnerability Details

LiquidationBranch.sol#liquidateAccounts function is the following.

function liquidateAccounts(uint128[] calldata accountsIds) external {
--- SKIP ---
// get account's required maintenance margin & unrealized PNL
138: (, UD60x18 requiredMaintenanceMarginUsdX18, SD59x18 accountTotalUnrealizedPnlUsdX18) =
tradingAccount.getAccountMarginRequirementUsdAndUnrealizedPnlUsd(0, SD59x18_ZERO);
// get then save margin balance into working data
ctx.marginBalanceUsdX18 = tradingAccount.getMarginBalanceUsd(accountTotalUnrealizedPnlUsdX18);
// if account is not liquidatable, skip to next account
// account is liquidatable if requiredMaintenanceMarginUsdX18 > ctx.marginBalanceUsdX18
if (!TradingAccount.isLiquidatable(requiredMaintenanceMarginUsdX18, ctx.marginBalanceUsdX18)) {
continue;
}
// deduct maintenance margin from the account's collateral
// settlementFee = liquidationFee
ctx.liquidatedCollateralUsdX18 = tradingAccount.deductAccountMargin({
feeRecipients: FeeRecipients.Data({
marginCollateralRecipient: globalConfiguration.marginCollateralRecipient,
orderFeeRecipient: address(0),
settlementFeeRecipient: globalConfiguration.liquidationFeeRecipient
}),
158: pnlUsdX18: requiredMaintenanceMarginUsdX18,
orderFeeUsdX18: UD60x18_ZERO,
settlementFeeUsdX18: ctx.liquidationFeeUsdX18
});
--- SKIP ---
}

As can be seen, in L158, requiredMaintenanceMarginUsdX18 is used mistakenly instead of requiredMaintenanceMarginUsdX18 - ctx.marginBalanceUsdX18 of L138.
It might be a developer's mistake.

Impact

The user may lose funds during liquidation.

Tools Used

Manual Review

Recommendations

Modify the LiquidationBranch.sol#liquidateAccounts function as follows.

function liquidateAccounts(uint128[] calldata accountsIds) external {
--- SKIP ---
// deduct maintenance margin from the account's collateral
// settlementFee = liquidationFee
ctx.liquidatedCollateralUsdX18 = tradingAccount.deductAccountMargin({
feeRecipients: FeeRecipients.Data({
marginCollateralRecipient: globalConfiguration.marginCollateralRecipient,
orderFeeRecipient: address(0),
settlementFeeRecipient: globalConfiguration.liquidationFeeRecipient
}),
-- pnlUsdX18: requiredMaintenanceMarginUsdX18,
++ pnlUsdX18: requiredMaintenanceMarginUsdX18 - ctx.marginBalanceUsdX18,
orderFeeUsdX18: UD60x18_ZERO,
settlementFeeUsdX18: ctx.liquidationFeeUsdX18
});
--- SKIP ---
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

deductAccountMargin() treats `required maintenance margin` as the `unrealized PnL` because it uses `requiredMaintenanceMarginUsdX18` in place of `pnlUsdX18`

Support

FAQs

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