Algo Ssstablecoinsss

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

Missing Oracle Price Validation for Zero and Negative Values

Root + Impact

Description

  • * The protocol retrieves prices from Chainlink oracles to calculate USD values of collateral and determine token amounts from USD values. The oracle library checks for stale prices but doesn't validate price values.

    * The contract doesn't validate that oracle prices are positive and non-zero before using them in calculations. Chainlink oracles can return zero or negative prices in edge cases, which will cause division by zero errors or incorrect calculations.

    ```vyper

    @internal

    @view

    def _get_usd_value(token: address, amount: uint256) -> uint256:

    price_feed: AggregatorV3Interface = AggregatorV3Interface(

    self.token_address_to_price_feed[token]

    )

    round_id: uint80 = 0

    price: int256 = 0

    started_at: uint256 = 0

    updated_at: uint256 = 0

    answered_in_round: uint80 = 0

    (

    round_id, price, started_at, updated_at, answered_in_round

    ) = oracle_lib._stale_check_latest_round_data(price_feed.address)

    return (

    (convert(price, uint256) * ADDITIONAL_FEED_PRECISION) * amount // @> No validation price > 0

    ) // PRECISION

    ```

    ```vyper

    @internal

    @view

    def _get_token_amount_from_usd(

    token: address, usd_amount_in_wei: uint256

    ) -> uint256:

    price_feed: AggregatorV3Interface = AggregatorV3Interface(

    self.token_address_to_price_feed[token]

    )

    round_id: uint80 = 0

    price: int256 = 0

    started_at: uint256 = 0

    updated_at: uint256 = 0

    answered_in_round: uint80 = 0

    (

    round_id, price, started_at, updated_at, answered_in_round

    ) = oracle_lib._stale_check_latest_round_data(price_feed.address)

    return (

    (usd_amount_in_wei * PRECISION) // (

    convert(price, uint256) * ADDITIONAL_FEED_PRECISION // @> Division by zero if price is 0

    )

    )

    ```


Risk

Likelihood:

  • * Chainlink oracles can return zero prices during network issues or when feeds are being updated

    * Some Chainlink feeds can return negative prices for certain asset types (though uncommon for ETH/BTC)

    * Oracle manipulation attacks could potentially force zero or negative prices

Impact:

  • * Division by zero errors will cause all deposit, mint, redeem, and liquidation functions to revert, effectively DoS'ing the protocol

    * Negative prices converted to uint256 will underflow and revert, making functions unusable

    * Users cannot interact with the protocol when oracle returns invalid prices

Proof of Concept

```python
# Scenario 1: Zero price
# 1. Chainlink oracle returns price = 0 due to network issue
# 2. User tries to deposit collateral
# 3. _get_usd_value() called with price = 0
# 4. Calculation proceeds but returns 0 USD value
# 5. User can deposit collateral but get 0 USD value, allowing unlimited minting
# Scenario 2: Division by zero in _get_token_amount_from_usd
# 1. Oracle returns price = 0
# 2. Liquidator tries to liquidate
# 3. _get_token_amount_from_usd() called
# 4. Division by (0 * ADDITIONAL_FEED_PRECISION) causes revert
# 5. All liquidation attempts fail
```

Recommended Mitigation

```diff
@internal
@view
def _get_usd_value(token: address, amount: uint256) -> uint256:
price_feed: AggregatorV3Interface = AggregatorV3Interface(
self.token_address_to_price_feed[token]
)
round_id: uint80 = 0
price: int256 = 0
started_at: uint256 = 0
updated_at: uint256 = 0
answered_in_round: uint80 = 0
(
round_id, price, started_at, updated_at, answered_in_round
) = oracle_lib._stale_check_latest_round_data(price_feed.address)
+ assert price > 0, "DSCEngine__InvalidPrice"
return (
(convert(price, uint256) * ADDITIONAL_FEED_PRECISION) * amount
) // PRECISION
```
```diff
@internal
@view
def _get_token_amount_from_usd(
token: address, usd_amount_in_wei: uint256
) -> uint256:
price_feed: AggregatorV3Interface = AggregatorV3Interface(
self.token_address_to_price_feed[token]
)
round_id: uint80 = 0
price: int256 = 0
started_at: uint256 = 0
updated_at: uint256 = 0
answered_in_round: uint80 = 0
(
round_id, price, started_at, updated_at, answered_in_round
) = oracle_lib._stale_check_latest_round_data(price_feed.address)
+ assert price > 0, "DSCEngine__InvalidPrice"
return (
(usd_amount_in_wei * PRECISION) // (
convert(price, uint256) * ADDITIONAL_FEED_PRECISION
)
)
```
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 16 days 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!