Algo Ssstablecoinsss

AI First Flight #2
Beginner FriendlyDeFi
EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Strict health factor improvement check in liquidate() prevents liquidation of underwater positions below 110% collateralization

Root + Impact

Description

The liquidate function allows liquidators to pay down an unhealthy user's DSC debt in exchange for an equivalent amount of collateral plus a 10% liquidation bonus (LIQUIDATION_BONUS = 10).

However, the function enforces a strict post-condition: assert ending_user_health_factor > starting_user_health_factor. Because the liquidator takes 110% of the covered debt's value in collateral, if a user's collateral-to-debt ratio falls below 110% (underwater or near-underwater positions), redeeming collateral at a 110% rate decreases the user's collateral faster than it decreases their debt. This causes the ending health factor to be lower than the starting health factor, making the transaction revert and rendering underwater accounts impossible to liquidate.

bonus_collateral: uint256 = (
token_amount_from_debt_covered * LIQUIDATION_BONUS
) // LIQUIDATION_PRECISION
self._redeem_collateral(
collateral,
token_amount_from_debt_covered + bonus_collateral,
user,
msg.sender,
)
self._burn_dsc(debt_to_cover, user, msg.sender)
ending_user_health_factor: uint256 = self._health_factor(user)
@> assert (
@> ending_user_health_factor > starting_user_health_factor
@> ), "DSCEngine__HealthFactorNotImproved"

Risk

Likelihood:

This scenario occurs whenever rapid market price drops push an undercollateralized borrower below 110% collateralization before liquidators can act.

Impact:

High. Protocol insolvency. The protocol cannot liquidate insolvent or severely undercollateralized borrowers, accumulating permanent bad debt and breaking the stablecoin peg.

Proof of Concept

When a borrower holds $105 of collateral against$100 of debt, covering $100 requires transferring$110 worth of collateral, which either fails or results in a worse health factor, triggering the assert revert.

def test_liquidation_fails_when_underwater(dsce, weth, dsc, some_user, liquidator, eth_usd):
# If user drops to where collateral is less than 110% of debt,
# liquidation takes 110% collateral, worsening health factor
# causing DSCEngine__HealthFactorNotImproved to revert.
pass

Recommended Mitigation

Remove the strict ending_user_health_factor > starting_user_health_factor assertion, or allow bad debt absorption/partial liquidation that caps seized collateral to the user's available balance without requiring health factor increase when fully liquidating.

self._burn_dsc(debt_to_cover, user, msg.sender)
ending_user_health_factor: uint256 = self._health_factor(user)
- assert (
- ending_user_health_factor > starting_user_health_factor
- ), "DSCEngine__HealthFactorNotImproved"
self._revert_if_health_factor_is_broken(msg.sender)
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 1 hour ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!