Orbiting Sangria Porpoise
Medium
During liquidation the protocol calculates the amount of cTokens to seize or seizeTokens
like here. There is however
- no check throughout the liquidation flow to verify if
seizeTokens > 0
. - no slippage control param (for example, minAmountExpected) which the liquidator can specify while calling the liquidate functions.
This can result in the liquidator ending up paying repayAmount
and reducing the borrower's debt but not receiving anything in return.
Imagine the following:
- Numa per cNuma = 2e8 (as per current rates observable in tests)
- rEth per Numa = 1_000_000e18 (Numa has appreciated considerably in future)
- Bob has borrowed
0.18e18 rEth
. This is equivalent to18e10 Numa
which turns out to be900 cNuma
- Alice wants to liquidate Bob's unhealthy debt and calls
liquidateBadDebt()
with_percentagePosition1000
as1
. This denotes0.1%
of debt to be liquidated. Note that this works similarly in a regular non-bad debt (just shortfall) situation too - the calls to the other liquidate functions need a repayAmount param instead of a percentage param, based on which a ratio is calculated andseizeTokens
are calculated ( See inside liquidateCalculateSeizeTokens() ). - rEth amount equal to
0.18e15
is pulled from Alice's account to commence liquidation - In return she gets:
seizeTokens = 1 * 900 / 1000 = 0
. - No further checks revert due to this and the liquidation flow concludes.
Note that such a situation can happen inadvertently during periods of high volatility too. Alice may have calculated correctly prior to sending her tx so that she receives non-zero seizeTokens but by the time the tx executes, price movement could well rob her of any returns.
Liquidator can end up paying repayAmount
and reducing the borrower's debt but not receiving anything in return.
- Add verification for
seizeTokens > 0
. - Add a slippage control param (for example, minAmountExpected) which a liquidator can specify while calling the liquidate functions.