Algo Ssstablecoinsss

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

Oracle library accepts non-positive prices

Root + Impact

Description

  • Oracle validation should reject non-positive prices because a zero or negative USD price is not a valid collateral price.

  • oracle_lib._stale_check_latest_round_data checks freshness fields but never checks price > 0. A fresh round with price == 0 passes the oracle library and later causes division by zero in _get_token_amount_from_usd. A negative price can also revert during convert(price, uint256).

# src/oracle_lib.vy
(
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
return (round_id, price, started_at, updated_at, answered_in_round)
# src/dsc_engine.vy
@> return (
@> (usd_amount_in_wei * PRECISION) // (
@> convert(price, uint256) * ADDITIONAL_FEED_PRECISION
@> )
@> )

Risk

Likelihood:

  • This occurs when a price feed returns a fresh round with a zero or negative answer.

  • The mock contracts already support updating the answer to 0, demonstrating that the engine accepts the feed shape until the arithmetic path fails.

Impact:

  • Liquidation and price conversion can revert due to division by zero or failed int-to-uint conversion.

  • Unhealthy positions for the affected collateral can become temporarily non-liquidatable.

Proof of Concept

def test_zero_price_passes_stale_check_but_breaks_token_amount_conversion(dsce, eth_usd, weth):
# updateAnswer sets updated_at to the current timestamp, so the value is fresh.
eth_usd.updateAnswer(0)
# _get_token_amount_from_usd divides by price * ADDITIONAL_FEED_PRECISION.
# With price == 0, the denominator is zero and the call reverts.
with boa.reverts():
dsce.get_token_amount_from_usd(weth, 100 * 10**18)

Recommended Mitigation

(
round_id, price, started_at, updated_at, answered_in_round
) = staticcall price_price.latestRoundData()
+assert price > 0, "DSCEngine_InvalidPrice"
assert updated_at != 0, "DSCEngine_StalePrice"
assert answered_in_round >= round_id, "DSCEngine_StalePrice"

Reject zero and negative oracle answers directly in the oracle library before any conversion or division uses the price.

Updates

Lead Judging Commences

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