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

Underflow Vulnerability in _smoothed_price Function Leading to Potential DoS

Summary

The operation unsafe_sub(raw_price + max_change, last_price) in the _smoothed_price function can revert if raw_price is significantly lower than last_price, causing an underflow.

Vulnerability Details

The _smoothed_price function in the ScrvusdOracleV2.vy contract is designed to calculate a smoothed price based on the last price and the current raw price. Here is the relevant code:

@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:
return last_price + max_change if raw_price > last_price else last_price - max_change
return raw_price

The operation unsafe_sub(raw_price + max_change, last_price) can cause an underflow if raw_price is much lower than last_price. This is because unsafe_sub does not handle cases where the result of the subtraction is negative, leading to a transaction revert.

Impact

Denial of Service (DoS)**: If raw_price is significantly lower than last_price, the unsafe_sub operation can cause an underflow and revert the transaction. This can be exploited to disrupt the normal functioning of the contract, causing a denial of service.

Tools Used

manual review

Recommendations

To mitigate this vulnerability, the logic should be reimplemented using safe operations. Here is a possible solution:

@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 raw_price > last_price:
if raw_price - last_price > max_change:
return last_price + max_change
else:
if last_price - raw_price > max_change:
return last_price - max_change
return raw_price

This implementation avoids the underflow by directly comparing raw_price and last_price and adjusting the smoothed price accordingly.

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.