Incorrect shortcut used in isLiquidatable
Description
The isLiquidatable
function in the ClearingHouseLib library directly returns true
if the margin
input is less than zero.
function isLiquidatable(ClearingHouse storage self, address account, uint256 subaccount, int256 margin)
internal
view
returns (bool)
{
if (margin < 0) return true;
bytes32[] memory positions = self.getPositions(account, subaccount);
int256 totalPnL;
uint256 totalMarginReq;
int256 pnl;
uint256 marginReq;
for (uint256 i; i < positions.length; ++i) {
(pnl, marginReq) = self.market[positions[i]].getLiquidatableUPnLAndMarginRequirement(account, subaccount);
totalPnL += pnl;
totalMarginReq += marginReq;
}
return (margin + totalPnL) < totalMarginReq.toInt256();
}
This shortcut bypasses further profit and loss (PNL) computations. Consequently, an account could be flagged for liquidation despite potentially possessing sufficient unrealized profit to cover the margin requirement.
A similar issue exists in the PerpManager contract. Its isLiquidatable
view function includes the shortcut if (fundingPaymentResult.debt > 0) return true;
, which also incorrectly bypasses further PNL computations.
Impact
This flaw may lead to the incorrect liquidation of user accounts that have sufficient unrealized profits across markets to meet overall margin requirements.
Recommendations
We recommend removing these shortcuts in the solvency calculation logic to ensure all PNL is considered before determining an account's liquidatable status.
Remediation
This issue has been acknowledged by Liquid Labs, Inc., and a fix was implemented in commit 1222a4dd↗.