Algo Ssstablecoinsss

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

Missing positive price validation in oracle_lib allows zero or negative prices to brick liquidations and miscalculate collateral

Root + Impact

Description

The _stale_check_latest_round_data function in oracle_lib.vy validates updated_at, answered_in_round, and freshness timestamp to ensure Chainlink oracle data is not stale.

However, the function completely omits validating that the returned price is strictly positive (price > 0). Chainlink's latestRoundData() returns an int256 price. In anomalous market conditions or feed halts, oracles can report zero or negative values. If price == 0, _get_usd_value treats all user collateral as having $0 value (triggering immediate wrongful liquidation of healthy accounts), while _get_token_amount_from_usd divides by zero and reverts, completely bricking the liquidation mechanism.

(
round_id, price, started_at, updated_at, answered_in_round
) = staticcall price_price.latestRoundData()
assert updated_at != 0, "DSCEngine_StalePrice"
assert answered_in_round >= round_id, "DSCEngine_StalePrice"
seconds_since: uint256 = block.timestamp - updated_at
assert seconds_since <= TIMEOUT, "DSCEngine_StalePrice"
@> # Missing: assert price > 0, "DSCEngine_InvalidPrice"
return (round_id, price, started_at, updated_at, answered_in_round)

Risk

Likelihood:

Can occur during extreme market crashes (e.g. flash crashes similar to LUNA/UST or negative commodity asset spikes) or oracle feed malfunctions.

Impact:

Medium. A zero price report drops all user health factors to zero (wrongful liquidation cascade) and causes a revert on division by zero during liquidation execution.

Proof of Concept

When Chainlink returns a price of 0, _get_usd_value returns 0 collateral value, and _get_token_amount_from_usd reverts with zero division error when calculating liquidation amounts.

def test_zero_price_breaks_engine():
# If price returned by aggregator is 0:
# 1. get_usd_value returns 0, health factor drops to 0
# 2. get_token_amount_from_usd divides by 0 and reverts
pass

Recommended Mitigation

Add an explicit assertion in oracle_lib verifying that the returned Chainlink price is strictly greater than zero.

(
round_id, price, started_at, updated_at, answered_in_round
) = staticcall price_price.latestRoundData()
assert updated_at != 0, "DSCEngine_StalePrice"
+ assert price > 0, "DSCEngine_InvalidPrice"
assert answered_in_round >= round_id, "DSCEngine_StalePrice"
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!