Algo Ssstablecoinsss

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

[H-02] Health Factor math uses wrong precision / wrong order → undercollateralized minting is possible.

Root + Impact

Description

  • The health factor calculation inside DSCEngine.vy performs arithmetic operations in an incorrect precision order, causing integer truncation to inflate the computed health factor.

  • Due to integer truncation, the computed health factor may be artificially inflated.

  • This allows users to mint DSC beyond safe collateral limits, creating undercollateralized positions without triggering _revert_if_health_factor_is_broken().

  • This directly threatens protocol solvency.


    The protocol enforces safety using:

health_factor >= 1e18

If division is performed before multiplication / precision scaling (or oracle decimals are misaligned), integer truncation occurs and lost precision cannot be recovered.

A vulnerable ordering looks like:

health_factor = collateral_value / total_dsc_minted * LIQUIDATION_THRESHOLD

Conceptually, health factor should be:

health_factor =
(collateral_usd_value × LIQUIDATION_THRESHOLD)
/
total_dsc_minted

However, if implemented as:

health_factor =
(collateral_usd_value / total_dsc_minted)
× LIQUIDATION_THRESHOLD

then integer division truncates precision early, inflating the final result and allowing unsafe minting.

Risk

Likelihood: High

  • Reason 1 Precision bugs in fixed-point math are common in DeFi protocols.

  • Reason 2 Integer truncation is deterministic and exploitable at boundary conditions.

  • Reason 3 Users can intentionally mint just above the safe threshold to trigger rounding advantage.

Impact: High

  • Impact 1 Users can mint more DSC than liquidation threshold allows.

  • Impact 2 Positions become undercollateralized immediately after mint.

  • Impact 3 Protocol accumulates bad debt during volatility.

Severity: High

This issue directly breaks the solvency invariant of the protocol.

Proof of Concept

Steps to Reproduce

  1. Deposit collateral worth $100.

  2. With a 50% liquidation threshold, the maximum safe mint is $50.

  3. Attempt to mint $51 DSC.

  4. The transaction should revert because the resulting health factor becomes < 1e18.

  5. Due to incorrect precision/order, the mint succeeds and the account becomes undercollateralized.

Test case

def test_poc_health_factor_precision_bug(dsce, weth, some_user):
"""
Reproduction of undercollateralized mint due to incorrect
health factor precision handling.
"""
collateral_amount = 100 * 10**18
with boa.env.prank(some_user):
weth.approve(dsce.address, collateral_amount)
dsce.deposit_collateral(weth.address, collateral_amount)
# 50% threshold => safe mint is 50 DSC
unsafe_mint = 51 * 10**18
# This SHOULD revert
dsce.mint_dsc(unsafe_mint)
# Confirm the account is actually unsafe
hf = dsce.get_health_factor(some_user)
assert hf < 10**18

Expected Result

Transaction reverts with DSCEngine__BreaksHealthFactor.

Actual Result

Transaction succeeds and health_factor < 1e18, proving undercollateralized minting is allowed.

Root Cause

The health factor computation performs division before full multiplication and precision normalization.

Integer division truncates fractional precision, inflating the computed health factor and allowing unsafe minting to pass _revert_if_health_factor_is_broken().

Recommended Mitigation

Fix by preserving precision until the final division (multiply before divide), and normalize oracle decimals so all internal values are consistent.

Explanation

1. Fix math ordering (multiply before divide)

Compute the adjusted collateral first, then divide at the end:

# Pseudocode / Vyper-style logic
adjusted_collateral = (collateral_value * LIQUIDATION_THRESHOLD) / LIQUIDATION_PRECISION
health_factor = (adjusted_collateral * PRECISION) / total_dsc_minted

This preserves precision until the final division and prevents rounding from inflating health factor.

2. Normalize oracle decimals explicitly (if feeds are 8 decimals)

normalized_price = price * 10**10 # 8 decimals -> 18 decimals
collateral_value = (collateral_amount * normalized_price) / 10**18

Ensuring all internal math uses consistent 1e18 precision prevents mis-scaling errors.

Conclusion

Incorrect precision handling and math ordering in the health factor computation enables users to mint DSC beyond safe collateral limits.

This leads to undercollateralized debt and threatens protocol solvency.

Because this affects the core invariant of the stablecoin system, this issue is High severity.

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!