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

Incorrect Mapping Slot Calculation for balanceOf in ScrvusdVerifierV1

Summary

The ScrvusdVerifierV1 contract incorrectly calculates the storage slot for the balanceOf mapping, causing it to read from the wrong location in the scrvUSD contract's storage. This results in the oracle using an incorrect (likely zero) value for balance_of_self, which affects price calculations.

Vulnerability Details

In Ethereum's storage layout, the correct way to calculate a storage slot for a mapping at position p with key k is:

keccak256(abi.encode(k, uint256(p)))

However, in ScrvusdVerifierV1, the contract reverses this order when calculating the slot for balanceOf:

uint256[PROOF_CNT] internal PARAM_SLOTS = [
uint256(0), // filler for account proof
uint256(21), // total_debt
uint256(22), // total_idle
uint256(20), // totalSupply
uint256(38), // full_profit_unlock_date
uint256(39), // profit_unlocking_rate
uint256(40), // last_profit_update
uint256(keccak256(abi.encode(18, SCRVUSD))) // balanceOf(self)
];

The comment indicates that slot 18 is the balanceOf mapping and SCRVUSD is the address whose balance we want to read. The correct calculation should be:

keccak256(abi.encode(SCRVUSD, uint256(18)))

Since the parameters are reversed in the calculation, the verifier will read from an entirely different storage slot than intended. This slot is likely to contain zero or some unrelated value.

Impact

This vulnerability impacts the accuracy of price calculations in the oracle system:

The balance_of_self parameter is used in several critical calculations:

  • In _obtain_price_params to calculate gain:

gain: uint256 = (params.balance_of_self * (params.total_idle + params.total_debt) // params.total_supply)
  • In _unlocked_shares to determine unlocked shares when all profits are unlocked:

elif full_profit_unlock_date != 0:
# All shares have been unlocked
unlocked_shares = balance_of_self
  1. These calculations directly influence the price of scrvUSD on the target chain.

  2. Using an incorrect (likely zero) balance_of_self value would:

  • Underestimate the calculated gain per period

  • Incorrectly report unlocked shares

  • Eventually lead to undercalculation of the scrvUSD price
    This results in a lower-than-actual price for scrvUSD on the target chain, potentially allowing users to buy scrvUSD at a discount compared to its true value.

Tools Used

Manual code review

Recommendations

Correct the storage slot calculation by reversing the parameter order:

uint256[PROOF_CNT] internal PARAM_SLOTS = [
uint256(0), // filler for account proof
uint256(21), // total_debt
uint256(22), // total_idle
uint256(20), // totalSupply
uint256(38), // full_profit_unlock_date
uint256(39), // profit_unlocking_rate
uint256(40), // last_profit_update
uint256(keccak256(abi.encode(SCRVUSD, uint256(18)))) // balanceOf(self)
];
Updates

Lead Judging Commences

0xnevi Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

[invalid] finding-ScrvusdVerifierV1-incorrect-storage-slot-balanceOf-compute

- Per sponsor comments, verified slot is vyper, solidity contract only verifies it. - Vyper computes storage slots different from solidity as seen [here](https://ethereum.stackexchange.com/questions/149311/storage-collision-in-vyper-hashmap)

Support

FAQs

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