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

Potential Underflow in _smoothed_price Function in ScrvusdOracleV2.vy

Summary

A potential underflow exists in the _smoothed_price function due to the usage of unsafe_sub(). If raw_price + max_change is less than last_price, the subtraction operation underflows, leading to incorrect behavior or unexpected results. This could impact price smoothing calculations and introduce security vulnerabilities.

Vulnerability Details

The issue can be found here: https://github.com/CodeHawks-Contests/2025-03-curve/blob/main/contracts/scrvusd/oracles/ScrvusdOracleV2.vy#L155-L164

@view
def _smoothed_price(last_price: uint256, raw_price: uint256) -> uint256:
# Ideally should be (max_price_increment / 10**18) ** (block.timestamp - self.last_update)
# Using linear approximation to simplify calculations
max_change: uint256 = (
self.max_price_increment * (block.timestamp - self.last_update) * last_price // 10**18
)
# -max_change <= (raw_price - last_price) <= max_change
if unsafe_sub(raw_price + max_change, last_price) > 2 * max_change: #@audit here
return last_price + max_change if raw_price > last_price else last_price - max_change
return raw_price

unsafe_sub(a, b) does not perform underflow checks.

If raw_price + max_change < last_price, the subtraction operation underflows.

Vyper’s unsafe_sub() removes the built-in safety checks, causing unintended behavior.

Example Scenario:

Assumptions:

  • raw_price = 0.90 * 10**18

  • last_price = 1.00 * 10**18

  • max_change = 0.05 * 10**18

Execution:

unsafe_sub(0.90 * 1018 + 0.05 * 1018, 1.00 * 10**18)

= unsafe_sub(0.95 * 1018, 1.00 * 1018)

Since 0.95 * 1018 < 1.00 * 1018, this results in an underflow, causing an incorrect result or unexpected behavior.

Impact

The function may return incorrect smoothed price values, affecting downstream logic.

Tools Used

Manual Review

Recommendations

Use Vyper’s built-in safe arithmetic:

if raw_price + max_change > last_price:
diff: uint256 = raw_price + max_change - last_price
else:
diff: uint256 = 0
Updates

Lead Judging Commences

0xnevi Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

[invalid] finding-unsafe-sub-underflow

If underflow occurs, it must have meant that `raw_price` has deviated from `last_price` by more than `max_change`, meaning it is correct to restrict the `last_price` increment to `max_change`

Support

FAQs

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