Potential revert griefing in the liquidation flow
The liquidateBorrowAllowed
function in the Comptroller contract is called when an account may be liquidated, and it checks if the liquidation is allowed:
function liquidateBorrowAllowed(
address tTokenBorrowed,
address tTokenCollateral,
address liquidator,
address borrower,
uint256 repayAmount
) external view override returns (uint256) {
// [...]
+ /* allow accounts to be liquidated if the market is deprecated */
+ if (isDeprecated(TToken(tTokenBorrowed))) {
+ require(borrowBalance >= repayAmount, "Can not repay more than the total borrow");
+ } else {
+ // [...]
+ }
return uint256(Error.NO_ERROR);
}
This logic determines whether a liquidation should proceed based on several state conditions such as including market status and account liquidity. However, the newly added require check (require(borrowBalance >= repayAmount)
) in the case of deprecated tTokens introduces a potential griefing risk. This check prevents liquidation of more than the total borrowed amount, but this enables borrowers to bypass liquidation if the borrower executes a self-liquidation or repayment of a smaller amount to decrease borrowBalance
before the liquidation call. This results in a revert and unnecessary gas costs for the liquidator.
Although this is concerning, we noted this as a discussion point instead of a finding because the upstream code contains the same logic and assumption, where if liquidateBorrowAllowed
is called with an excess repayAmount
, it reverts. This is likely acceptable because, in the long run, liquidators would be sophisticated market participants and can be expected to either liquidate from a contract or have off-chain arrangements with block builders to ensure the state is consistent with their expectations before the liquidation is requested.