Algo Ssstablecoinsss

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

[M-02] Liquidation Bonus Can Cause Underflow When Collateral Is Insufficient

Root + Impact

Description

  • During liquidation, the protocol calculates token_amount_from_debt_covered + bonus_collateral and attempts to redeem this total amount from the user.

  • When the user's collateral is less than this total (debt + 10% bonus), the subtraction in _redeem_collateral will underflow and revert.

  • This can prevent liquidations of positions that have fallen deeply underwater, leaving bad debt in the system.

// Root cause in the codebase with @> marks to highlight the relevant section
@external
def liquidate(collateral: address, user: address, debt_to_cover: uint256):
# ...
token_amount_from_debt_covered: uint256 = self._get_token_amount_from_usd(
collateral, debt_to_cover
)
bonus_collateral: uint256 = (
token_amount_from_debt_covered * LIQUIDATION_BONUS
) // LIQUIDATION_PRECISION
@> self._redeem_collateral(
@> collateral,
@> token_amount_from_debt_covered + bonus_collateral, # May exceed user's balance
@> user,
@> msg.sender,
@> )

Risk

Likelihood: Medium

  • Reason 1 // Occurs when positions fall deeply underwater

  • Reason 2 // Flash crashes can cause this scenario

Impact: High

  • Impact 1 // Bad positions cannot be liquidated

  • Impact 2 // Protocol accumulates bad debt

  • Impact 3 // Remaining users bear the losses

Proof of Concept

The following demonstrates how a deeply underwater position becomes unliquidatable. When the required collateral (debt + bonus) exceeds the user's actual balance, the liquidation reverts, leaving the bad debt in the system.

def test_liquidation_underflow():
# User has $1000 collateral, $900 debt (health factor ~1.1)
# Price drops 50%: collateral now worth $500, debt still $900
with boa.env.prank(liquidator):
debt_to_cover = to_wei(900, "ether")
# token_amount = $900 worth of ETH at new price
# bonus = 10% of token_amount
# total_needed = token_amount + bonus
# But user only has $500 worth of ETH at new price
# Subtraction underflows, liquidation reverts
with boa.reverts(): # Underflow!
dsce.liquidate(weth, user, debt_to_cover)
# Position is underwater but cannot be liquidated
# Bad debt remains in system

Recommended Mitigation

Add a check to ensure the user has sufficient collateral before attempting the redemption. When collateral is insufficient, either cap the liquidation amount or allow partial liquidations that take all available collateral.

@external
def liquidate(collateral: address, user: address, debt_to_cover: uint256):
# ...
token_amount_from_debt_covered: uint256 = self._get_token_amount_from_usd(
collateral, debt_to_cover
)
bonus_collateral: uint256 = (
token_amount_from_debt_covered * LIQUIDATION_BONUS
) // LIQUIDATION_PRECISION
+ total_collateral_needed: uint256 = token_amount_from_debt_covered + bonus_collateral
+ user_collateral: uint256 = self.user_to_token_address_to_amount_deposited[user][collateral]
+
+ # Cap to user's available collateral
+ if total_collateral_needed > user_collateral:
+ total_collateral_needed = user_collateral
self._redeem_collateral(
collateral,
- token_amount_from_debt_covered + bonus_collateral,
+ total_collateral_needed,
user,
msg.sender,
)
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 3 hours 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!