The _unlocked_shares
function computes unlocked shares using integer division, which truncates the fractional component. Over multiple periods, this truncation accumulates, leading to a systematic underestimation of unlocked shares.
As a result, the computed total supply is higher than it should be, causing the oracle’s raw_price
to be undervalued. This mispricing can be exploited by an attacker to redeem scrvUSD for more underlying assets than deserved, draining value from liquidity providers.
The function calculates unlocked shares as follows:
Integer division in Vyper truncates any fractional part. The formula:
where delta = ts - last_profit_update
, always rounds down.
Over successive periods, the slight underestimation of unlocked shares accumulates. This leads to a higher computed “active” total supply when the unlocked shares are subtracted:
A higher total supply in the denominator of the raw_price
calculation:
results in an undervalued price.
The design assumption that truncation does not lead to approximation losses is violated.
Over time, the systematic undervaluation leads to irreversible losses for liquidity providers, as funds are gradually drained from the pool. An attacker can time redemptions when the truncation error is significant, thereby redeeming scrvUSD for more underlying assets than justified by the actual value.
Manual Review
Modify the unlocked shares calculation to round to the nearest integer rather than always rounding down.
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.
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.