DeFiLayer 1Layer 2
14,723 OP
View results
Submission Details
Severity: medium
Invalid

ScrvusdOracleV2 lacks timestamp information for price staleness verification

Summary

The price query functions in ScrvusdOracleV2.vy (price_v0(), price_v1(), and price_v2()) do not provide timestamp information alongside the returned prices, preventing users from verifying the freshness of the price data.

Vulnerability Details

The oracle contract ScrvusdOracleV2.vy implements three price query functions that return different versions of price calculations:

@view
@external
def price_v0(_i: uint256 = 0) -> uint256:
"""
@notice Get lower bound of `scrvUSD.pricePerShare()`
@dev Price is updated in steps, need to verify every % changed
@param _i 0 (default) for `pricePerShare()` and 1 for `pricePerAsset()`
"""
return self._price_v0() if _i == 0 else 10**36 // self._price_v0()
@view
@external
def price_v1(_i: uint256 = 0) -> uint256:
"""
@notice Get approximate `scrvUSD.pricePerShare()`
@dev Price is simulated as if noone interacted to change `scrvUSD.pricePerShare()`,
need to adjust rate when too off.
@param _i 0 (default) for `pricePerShare()` and 1 for `pricePerAsset()`
"""
return self._price_v1() if _i == 0 else 10**36 // self._price_v1()
@view
@external
def price_v2(_i: uint256 = 0) -> uint256:
"""
@notice Get approximate `scrvUSD.pricePerShare()`
@dev Uses assumption that crvUSD gains same rewards.
@param _i 0 (default) for `pricePerShare()` and 1 for `pricePerAsset()`
"""
return self._price_v2() if _i == 0 else 10**36 // self._price_v2()

The critical issue is that these functions only return price values without any associated timestamp information. Without timestamps, users integrating with the oracle have no mechanism to determine when the prices were last updated or if they are stale.

Impact

  • Users cannot validate the freshness of price data

  • Potential use of stale prices in downstream applications

  • Reduced reliability of the oracle system

Tools Used

Manual Review

Recommendations

  1. Modify the price query functions to return both price and timestamp data, using self.price_params_ts as the timestamp reference

  2. Consider implementing a struct return type that includes:

    • Price value

    • Last update timestamp

    • Any additional metadata relevant to price freshness

Updates

Lead Judging Commences

0xnevi Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Lack of quality
Assigned finding tags:

[invalid] finding-missing-sequencer-check-stale-price

I believe this to be at best informational severity as - The moment sequencer is up again, the price updates that retrieve storage values from mainnet will be pushed. To note, price updates are retrieved from storage proofs are retrieved from Ethereum scrvUSD contract, so the concept of the next updated price being outdated is not possible, given mainnet does not utilize sequencers. - There are no problems with small lags if used in liquidity pools due to fees. Fees generate spread within which price can be lagged. - All price updates are subjected to smoothing, and as you can see from the historical price movements as seen [here](https://coinmarketcap.com/currencies/savings-crvusd/), there is never a large discrepancy in prices (absolute terms), and even more unlikely given sequencer downtimes will unlikely be long. This small price changes can be safely arbitrage aligning with [protocol design](https://github.com/CodeHawks-Contests/2025-03-curve?tab=readme-ov-file#parameters) , along with the above mentioned fees - Combined with the above, the max price increments can be temporarily increased to more effectively match the most updated price.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.