ScrvusdOracleV2 Contract contains an arithmetic underflow issue when calculating unlocked shares. Specifically, if the _unlocked_shares()
function returns a value greater than p.total_supply
, the subsequent subtraction in _total_supply
produces a negative result and triggers a revert in Vyper. This revert halts normal price update operations, potentially causing disruptions for integrators and rendering parts of the protocol inoperable. The problem arises due to the absence of a constraint ensuring that unlocked shares cannot surpass the total supply, especially under scenarios where large amounts of shares become unlocked over extended periods.
This underflow issue arises in the ScrvusdOracleV2 Contract when _unlocked_shares()
returns a value exceeding p.total_supply
. Subtracting that value within _total_supply
leads to a negative result, which Vyper handles by reverting the transaction. Under normal conditions, the protocol relies on consistent price updates to function properly. However, if an attacker or unusual input parameters inflate balance_of_self
beyond the total supply—especially when a large amount of time has passed—subsequent price update calls can revert, creating a denial-of-service scenario.
By triggering repeated reverts, an attacker could disrupt critical functions related to price determination. This effectively breaks the protocol’s guarantee of reliable pricing, preventing integrators and other smart contracts from obtaining the correct asset valuation. The logic for calculating unlocked shares lacks a safeguard ensuring the unlocked portion cannot exceed the total supply, allowing a malicious or extreme set of parameters to propagate into _total_supply
and cause the underflow-based revert.
This arithmetic underflow issue prevents normal execution of price updates whenever _unlocked_shares()
returns a value greater than p.total_supply
, causing a revert in Vyper. As a result, the affected contract becomes unable to provide accurate pricing data, disrupting dependent systems and integrators. While no direct token loss occurs immediately, the revert effectively halts a critical function of the protocol and can lead to broader availability issues. If exploits or extreme conditions repeatedly trigger this scenario, the resulting disruption can cause significant damage by blocking essential liquidity operations and preventing users from interacting with the protocol as intended.
The underflow condition depends on specific parameters being set such that the unlocked shares exceed the total supply. While this scenario may not arise under normal operations, especially if the system’s parameters are carefully controlled and updated regularly, it remains plausible that a large accumulation of shares or unexpected time gaps could trigger it. If these parameters are externally influenced or if the vault operates under high volatility or extended periods without updates, the chance of encountering this issue increases. Thus, while not guaranteed to happen in a typical setup, it is sufficiently possible to warrant caution and corrective measures.
An underflow arises when the _unlocked_shares()
function returns a value greater than p.total_supply
. Consequently, subtracting this value in _total_supply
yields a negative result, causing a revert in Vyper. Although the transaction fails, this issue can halt normal execution and potentially leave the protocol in an inoperable state along that execution path.
Below is a simplified, annotated snippet illustrating where the issue occurs:
( ! ) If unlocked_shares
exceeds p.total_supply
, an underflow occurs, causing the execution to revert in Vyper.
The _unlocked_shares
function calculates unlocked shares based on factors such as elapsed time and profit_unlocking_rate
. If the resulting value surpasses p.total_supply
, the subtraction in _total_supply
triggers an underflow and reverts the transaction. This revert disrupts price updates and impacts the function’s availability, hindering normal protocol operations.
The system receives parameters that boost the vault’s balance_of_self
above its total supply. In addition, the elapsed time (ts - last_profit_update
) can be large enough for _unlocked_shares
to grow significantly. When _total_supply
is invoked, _unlocked_shares
surpasses p.total_supply
, the subtraction yields a negative result, and the contract reverts, blocking price updates and halting normal protocol operations.
This test confirms that if the unlocked shares (_unlocked_shares
) exceed the vault's total_supply
, the contract reverts due to arithmetic underflow. In the test, balance_of_self
was set greater than total_supply
while configuring a past full_profit_unlock_date
, causing _unlocked_shares
to be higher than total_supply
. The resulting underflow triggers a revert, which the test successfully detects. The final output indicates 1 passed, confirming that the contract properly reverts under these conditions.
Add the following test to tests/scrvusd/oracle/unitary/test_v2.py
Review of the logic confirms that without an explicit cap on the unlocked share count relative to total_supply
, an underflow inevitably occurs if certain parameters and extended time periods are met. This issue is genuine and causes transaction failures in the contract whenever the described condition materializes.
Manual Code Review
The contract code was meticulously analyzed line by line to detect logical oversights and confirm the underflow condition through targeted tests.
Implement a safeguard preventing _unlocked_shares
from exceeding total_supply
. For instance:
This ensures no arithmetic underflow when subtracting unlocked shares from p.total_supply
.
Note that `total_supply` and `profit_unlocking_rate` is initially set to 1 and 0 respectively when the `ScrvusdOracleV2.vy` is deployed 1. `total_supply` and `profit_unlocking_rate` is part of the price param updates within `update_price`, which must have gone through verification via the OOS `StateProofVerifier` contract, so there is no evidence that a 0 supply is allowed either via a 0 supply update or an extremely high `profit_unlocking_rate`. 2. Since price is retrieved via values retrived from the V3Vault, if there is no supply, there is arguably no price to be posted. As such, reverting is arguably the correct choice since a 0 price value is not expected from scrvUSD, which is a stable coin.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.