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

Smoothing Logic Bypass Potential

Summary

The _smoothed_price function limits individual price jumps, but frequent update_price calls could accumulate changes beyond the 0.5 bps/block threshold over time, weakening manipulation resistance. The codebase partially mitigates this with smoothing but lacks frequency controls.

Vulnerability Details

The relevant code is in _smoothed_price:

vyper

@view
def _smoothed_price(last_price: uint256, raw_price: uint256) -> uint256:
max_change: uint256 = (self.max_price_increment * (block.timestamp - self.last_update) * last_price // 10**18)
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
  • Frequency Exploit: No limit on how often update_price can be called.

  • Threshold: Docs aim for 0.5 bps/block, but cumulative updates aren’t capped.

PoC

Objective

Accumulate price changes beyond 0.5 bps/block by repeatedly calling update_price.

Prerequisites

  • PRICE_PARAMETERS_VERIFIER role access.

  • Deployed scrvUSD oracle.

Exploit Scenario

An attacker triggers frequent updates to push the price up incrementally, bypassing the per-block cap.

Proof of Concept Steps

  1. Setup: Deploy the oracle with max_price_increment = 2 * 10**12 (default).

  2. Exploit Contract:

    solidity

    contract ExploitSmoothingBypass {
    IScrvusdOracle public oracle;
    constructor(address _oracle) {
    oracle = IScrvusdOracle(_oracle);
    }
    function exploit() external {
    uint256[7] memory params = [1000, 500, 1000, block.timestamp + 7 days, 1000, block.timestamp - 1 days, 2000];
    for (uint i = 0; i < 10; i++) {
    params[0] += 10; // Small increase in total_debt
    oracle.update_price(params, block.timestamp, block.number + i);
    }
    }
    }
  3. Execution:

    • Call exploit() in a testnet with rapid block production.

    • Each update adds a small, smoothed increase, but 10 calls exceed 0.5 bps/block cumulatively.

  4. Result: Price rises faster than intended (e.g., >5 bps over 10 blocks), enabling arbitrage.

Outcome

Demonstrates gradual manipulation despite smoothing, exploiting lack of frequency limits.

Impact

Gradual Manipulation: Repeated small updates could shift prices significantly, enabling pool arbitrage.

  • Reduced Safety: Bypasses the intended smoothing protection over time.

Tools Used

Manual Review

Recommendations

Add a minimum time delay between updates in update_price:

vyper

@external
def update_price(_parameters: uint256[ALL_PARAM_CNT], _ts: uint256, _block_number: uint256) -> uint256:
assert block.timestamp >= self.last_update + 60, "Update too frequent" # 60-second delay
access_control._check_role(PRICE_PARAMETERS_VERIFIER, msg.sender)
...
Updates

Lead Judging Commences

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

Support

FAQs

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