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
11 months ago
0xnevi Lead Judge 10 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.

Give us feedback!