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

`_unlocked_shares` calculation exposes a division error, leading to accumulative estimation error of unlocked shares

Title

_unlocked_shares calculation exposes a division error, leading to accumulative estimation error of unlocked shares

Summary

The _unlocked_shares function in the ScrvusdOracleV2 contract uses integer division to calculate unlocked shares out. This division has a truncation issue which could lead to accumulative mathmatical error if it's being conducted over an extended period.

Vulnerability Details

https://github.com/CodeHawks-Contests/2025-03-curve/blob/main/contracts/scrvusd/oracles/ScrvusdOracleV2.vy#L207

The issue lies in the _unlocked_shares function, which calculates unlocked shares using integer division. As in Vyper, truncation happens while integer division and this drives the result being rounded down over time.

In the code snippet below, it shows where and how it is affected to the calculation of _unlocked_shares:

def _unlocked_shares(
full_profit_unlock_date: uint256,
profit_unlocking_rate: uint256,
last_profit_update: uint256,
balance_of_self: uint256,
ts: uint256,
) -> uint256:
"""
Returns the amount of shares that have been unlocked.
To avoid sudden price_per_share spikes, profits can be processed
through an unlocking period. The mechanism involves shares to be
minted to the vault which are unlocked gradually over time. Shares
that have been locked are gradually unlocked over profit_max_unlock_time.
"""
unlocked_shares: uint256 = 0
if full_profit_unlock_date > ts:
# If we have not fully unlocked, we need to calculate how much has been.
>> unlocked_shares = profit_unlocking_rate * (ts - last_profit_update) // MAX_BPS_EXTENDED
elif full_profit_unlock_date != 0:
# All shares have been unlocked
unlocked_shares = balance_of_self
return unlocked_shares

Over time, this truncation is being accumulated which takes the underestimated unlocked_shares to the calculation of total supply and co. Consequent errors are to be taking place like having raw_price in an undervalued price.

Impact

The truncation error leads to a wrong calculation of the oracle’s raw_price. It will cause significant loss for liquidity providers as malicious actors can exploit the discrepancy to redeem scrvUSD for more underlying assets than expected.

Recommendations

Add a correction factor before performing the division to account for truncation, so as to minimize the effect of truncation.

Updates

Lead Judging Commences

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

[invalid] finding-precision-loss

All values will be scaled to a combined of 36 decimals before division (be it price-related values or totalSupply). Considering the 18 decimals of all values, no realistic values were presented in any duplicates to proof a substantial impact on precision loss.

Support

FAQs

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