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

Incorrect Profit Unlocking Logic (ScrvusdOracleV2.vy)

Summary:

Hi,

I have found out a potential bug in the contract 'ScrvusdOracleV2.vy' in which the profit unlocking logic is not calculated in correct way because of it's assumptions for parameters full_profit_unlock_date and profit_unlocking_rate.

Vulnerability Details:

The key details for this potential vulnerability can be given as follows:

The _unlocked_shares function calculates the no. of shares based on profit_unlocking_rate and time elapsed. But the logic assumes that full_profit_unlock_date is always set correctly and profit_unlocking_rate is non-zero when unlocking is in progress. And the function doesn't handle where ts (timestamp) is less than last_profit_update, which could happen if parameters are updated with an incorrect timestamp.

Impact:

  • If full_profit_unlock_date is set to past timestamp or profit_unlocking_rate is zero, the contract may assumes all shares are unlocked, leading to inflated price calculations.

  • If in case of ts < last_profit_update, the calculation ts - last_profit_update will underflow, causing the contract to revert or produce incorrect results.

Tools Used:

Manual Code Analysis

Recommendations:

  • Add explicit checks in _unlocked_shares to ensure ts >= last_profit_update and handle edge cases for full_profit_unlock_date and profit_unlocking_rate.

@view
def _unlocked_shares(
full_profit_unlock_date: uint256,
profit_unlocking_rate: uint256,
last_profit_update: uint256,
balance_of_self: uint256,
ts: uint256,
) -> uint256:
assert ts >= last_profit_update, "Invalid timestamp"
unlocked_shares: uint256 = 0
if full_profit_unlock_date > ts:
if profit_unlocking_rate > 0:
unlocked_shares = profit_unlocking_rate * (ts - last_profit_update) // MAX_BPS_EXTENDED
elif full_profit_unlock_date != 0:
unlocked_shares = balance_of_self
return unlocked_shares
  • Validate full_profit_unlock_date and profit_unlocking_rate in the update_price function to ensure they are consistent with the vault’s state (e.g., full_profit_unlock_date should not be in the past unless all shares are unlocked).

Updates

Lead Judging Commences

0xnevi Lead Judge
6 months ago
0xnevi Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope
Assigned finding tags:

[invalid] finding-missing-proof-content-validation

- See [here]([https://github.com/CodeHawks-Contests/2025-03-curve?tab=readme-ov-file#blockhash-oracle)](https://github.com/CodeHawks-Contests/2025-03-curve?tab=readme-ov-file#blockhash-oracle) on how it is used to verify storage variable - All state roots and proofs must be verified by the OOS `StateProofVerifier` inherited as `Verifier` (where the price values and params are extracted), so there is no proof that manipulating timestamp/inputs can affect a price update - It is assumed that the OOS prover will provide accurate data and the OOS verifier will verify the prices/max unlock time to be within an appropriate bound/values - There is a account existance check in L96 of `ScrvusdVerifierV1.sol`, in which the params for price updates are extracted from

Support

FAQs

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