Accounts will not be liquidated when they are meant to.
In the case that the totalMaintenance*liquidationFee is higher than the account's totalCollateral, liquidators are paid the totalCollateral. I think one of the reasons for this is to avoid the case where liquidating an account would attempt to debit fees that is greater than the collateral balance The problem is that, the value of totalCollateral used as fee is slightly higher value than the current collateral balance, which means that in such cases, attempts to liquidate the account would revert due to underflow errors.\\nHere is the `liquidate` function:\\n```\\nfunction liquidate(\\n        address account,\\n        IProduct product\\n    ) external nonReentrant notPaused isProduct(product) settleForAccount(account, product) {\\n        if (product.isLiquidating(account)) revert CollateralAccountLiquidatingError(account);\\n\\n        UFixed18 totalMaintenance = product.maintenance(account); maintenance?\\n        UFixed18 totalCollateral = collateral(account, product); \\n\\n        if (!totalMaintenance.gt(totalCollateral))\\n            revert CollateralCantLiquidate(totalMaintenance, totalCollateral);\\n\\n        product.closeAll(account);\\n\\n        // claim fee\\n        UFixed18 liquidationFee = controller().liquidationFee();\\n      \\n        UFixed18 collateralForFee = UFixed18Lib.max(totalMaintenance, controller().minCollateral()); \\n        UFixed18 fee = UFixed18Lib.min(totalCollateral, collateralForFee.mul(liquidationFee)); \\n\\n        _products[product].debitAccount(account, fee); \\n        token.push(msg.sender, fee);\\n\\n        emit Liquidation(account, product, msg.sender, fee);\\n    }\\n```\\n\\n`fee=min(totalCollateral,collateralForFee*liquidationFee)` But the PROBLEM is, the value of `totalCollateral` is fetched before calling `product.closeAll`, and `product.closeAll` debits the closePosition fee from the collateral balance. So there is an attempt to debit `totalCollateral`, when the current collateral balance of the account is totalCollateral-closePositionFees This allows the following:\\nThere is an ETH-long market with following configs:\\nmaintenance=5%\\nminCollateral=100USDC\\nliquidationFee=20%\\nETH price=$1000\\nUser uses 500USDC to open $10000(10ETH) position\\nPrice of ETH spikes up to $6000\\nRequired maintenance= 60000*5%=$3000 which is higher than account's collateral balance(500USDC), therefore account should be liquidated\\nA watcher attempts to liquidate the account which does the following:\\ntotalCollateral=500USDC\\n`product.closeAll` closes the position and debits a makerFee of 10USDC\\ncurrent collateral balance=490USDC\\ncollateralForFee=totalMaintenance=$3000\\nfee=min(500,3000*20%)=500\\n`_products[product].debitAccount(account,fee)` attempts to subtract 500 from 490 which would revert due to underflow\\naccount does not get liquidated\\nNow, User is not liquidated even when he is using 500USD to control a $60000 position at 120x leverage(whereas, maxLeverage=20x)\\nNOTE: This would happen when the market token's price increases by (1/liquidationFee)x. In the above example, price of ETH increased by 6x (from 1000USD to 6000USD) which is greater than 5(1/20%)
`totalCollateral` that would be paid to liquidator should be refetched after `product.closeAll` is called to get the current collateral balance after closePositionFees have been debited.
A User's position will not be liquidated even when his collateral balance falls WELL below the required maintenance. I believe this is of HIGH impact because this scenario is very likely to happen, and when it does, the protocol will be greatly affected because a lot of users will be trading abnormally high leveraged positions without getting liquidated.
```\\nfunction liquidate(\\n        address account,\\n        IProduct product\\n    ) external nonReentrant notPaused isProduct(product) settleForAccount(account, product) {\\n        if (product.isLiquidating(account)) revert CollateralAccountLiquidatingError(account);\\n\\n        UFixed18 totalMaintenance = product.maintenance(account); maintenance?\\n        UFixed18 totalCollateral = collateral(account, product); \\n\\n        if (!totalMaintenance.gt(totalCollateral))\\n            revert CollateralCantLiquidate(totalMaintenance, totalCollateral);\\n\\n        product.closeAll(account);\\n\\n        // claim fee\\n        UFixed18 liquidationFee = controller().liquidationFee();\\n      \\n        UFixed18 collateralForFee = UFixed18Lib.max(totalMaintenance, controller().minCollateral()); \\n        UFixed18 fee = UFixed18Lib.min(totalCollateral, collateralForFee.mul(liquidationFee)); \\n\\n        _products[product].debitAccount(account, fee); \\n        token.push(msg.sender, fee);\\n\\n        emit Liquidation(account, product, msg.sender, fee);\\n    }\\n```\\n