Boost _ Folks Finance 33947 - [Smart Contract - Low] During liquidations when borrowToRepay collater

Submitted on Fri Aug 02 2024 09:38:03 GMT-0400 (Atlantic Standard Time) by @iamandreiski for Boost | Folks Finance

Report ID: #33947

Report type: Smart Contract

Report severity: Low

Target: https://testnet.snowtrace.io/address/0xc1FBF54B25816B60ADF322d8A1eaCA37D9A50317

Impacts:

  • Protocol insolvency

  • Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield

Description

Brief/Intro

When a user is undercollateralized and eligible for liquidation, a liquidator can initiate a liquidation process in which the borrowed amount(either partial or whole) of the token-in-question + interest will be transferred to the liquidator for later repayment as well as the collateral in the amount of the borrowed token + 10% liquidation bonus. The problem arises when the borrow amount that should be repaid is greater than the collateral amount to-be-received by the liquidator. In those cases, due to invalid calculations, the liquidator will actually receive 10% more borrow amount to repay (or 10% less collateral than the borrow amount), effectively damaging the liquidator.

Vulnerability Details

There are more than one outcome in which this can result:

  • Violator will pay 10% less collateral for the borrowed amount, effectively "incentivizing" users with underwater loans.

  • This will disincentivize liquidators to liquidate these kind of loans effectively leading to the accumulation of more bad debt and essentially undercollateralized loans / protocol/pool insolvency.

When a user initiates a liquidation, eventually calcLiquidationAmounts() will be called in order to calculate the collateral and borrow amounts based on amounts owed, user input, etc.

First the repayBorrowAmount will be calculated based on the following "formula":

It will take the smaller amount between a user-input value of the amount that they'd want to liquidate OR either the balance of the loan OR the maxRepayBorrowAmount (which is a calculation based upon the amount that needs to be liquidated to make the loan healthy).

For the sake of this situation let's say that the violatorLoanBorrow.balance was picked as the "smallest" to be liquidated, which is the total balance of the loan of that pool.

After the above-mentioned amount was determined, it will be converted to its equivalent collateral value:

For the sake of this example, let's say that the borrowed amount to be repaid is 1 WETH, and the collateral is USDC, with the WETH/USDC price at 3000 USDC.

In underlying collateral amount, this would be 3300 USDC (Taking in consideration the liquidation bonus(if it's 10%)).

The problem arises if the collateral that the user has in the pool is less than this, let's say 2500 USDC.

The following will occur:

The seizeUnderlyingCollateralAmount will be the violatorUnderlingCollateralBalance which is the underlying amount OR 2500 USDC.

But when the repayBorrowAmount is calculated in order to determine how much of the borrow amount should the liquidator repay:

This would result in converting 2500 USDC to WETH, or 0.83 WETH, the problem is that the liquidation bonus would be added to this value:

This would cause the liquidator to receive only 2500 USDC collateral, but pay the equivalent of 2750 USDC in borrow amount, due to the incorrect calculation.

  • It should be : assetAmount * 1e4 / (1e4 + liquidationBonus)

Even if liquidators intentionally input lower-than-collateral maxAmountToRepay values, after some time this will also result in bad debt accumulation as the collateral would be transferred to liquidators, but there would be "residual" borrow amounts.

Impact Details

Loans in which the collateral is less than the amount-to-be-repayed will result in the liquidator paying 10% more borrowAmount, while receiving 10% less collateral amount. This is effectively damaging the liquidator in the benefit of the borrower, and could potentially lead to a pool insolvency if enough bad debt is accumulated.

References

Below PoC is in Foundry, the only thing needed to run it is the importation of MathUtils in the test suite.

Proof of concept

Proof of Concept

Last updated

Was this helpful?