ScrvusdVerifierV1.sol computes the account key hash (SCRVUSD_HASH) for the scrvUSD contract as keccak256(abi.encodePacked(SCRVUSD)), passing it to Verifier.extractAccountFromProof() to verify Ethereum state proofs. However, Ethereum’s state trie requires account keys to be hashed as keccak256(RLP.encode(address)). This mismatch causes proof verification to fail consistently, as the provided key does not correspond to any valid trie path. As a result, the contract cannot extract scrvUSD storage data, preventing oracle price updates to ScrvusdOracleV2. This critical flaw renders the verifier non-functional, leading to stale or default pricing in downstream systems, with a High Severity impact due to its direct effect on protocol functionality.
The vulnerability arises in how ScrvusdVerifierV1 prepares the key (SCRVUSD_HASH) to verify the scrvUSD account state within Ethereum’s state trie:
Incorrect Hash Computation:
abi.encodePacked(SCRVUSD): Outputs the raw 20-byte address (e.g., 0x0655977FEb2f289A4aB78af67BAB0d17aAb84367).
keccak256(abi.encodePacked(SCRVUSD)): Hashes the 20 bytes directly, producing a bytes32 value (e.g., keccak256(0x0655977FEb2f289A4aB78af67BAB0d17aAb84367)).
Usage in Proof Verification:
SCRVUSD_HASH is passed as the key to extractAccountFromProof(), which expects the trie key for SCRVUSD’s account data.
Ethereum State Trie Expectation:
In Ethereum’s Patricia Merkle Trie, account keys are computed as keccak256(RLP.encode(address)).
RLP encoding of a 20-byte address prepends a length prefix (0xd4) to the address bytes (e.g., 0xd40655977feb2f289a4ab78af67bab0d17aab84367).
Correct key: keccak256(0xd40655977feb2f289a4ab78af67bab0d17aab84367) - differs from the raw hash.
Mismatch:
Provided: keccak256(raw 20 bytes) - doesn’t match any trie node.
Expected: keccak256(RLP-encoded address) - the actual path to SCRVUSD’s account in the state trie.
Result: extractAccountFromProof() fails to find the account, returning account.exists = false, triggering a revert at require(account.exists).
Affected Functions:
verifyScrvusdByBlockHash() and verifyScrvusdByStateRoot() call _extractParametersFromProof(), both failing due to this error.
Every verification attempt reverts at require(account.exists, "scrvUSD account does not exist"), preventing _extractParametersFromProof() from completing.
No parameters are extracted, so _updatePrice() is never called on ScrvusdOracleV2.
If never updated: ScrvusdOracleV2 remains at its initial state, misrepresenting scrvUSD’s true vault value.
If previously updated: Stale data persists, lagging behind Ethereum’s scrvUSD state.
Manual Code Review
Ethereum Documentation
Use RLP encoding to match the state trie key:
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.