Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Invalid

Missing Function / Logic to Populate `proposalPowerSnapshots[proposalId]`

veRAACToken.sol

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/veRAACToken.sol#L393

Overview

The contract defines:

mapping(uint256 => uint256) public proposalPowerSnapshots;
function getVotingPowerForProposal(
address account,
uint256 proposalId
) external view returns (uint256) {
uint256 snapshotBlock = proposalPowerSnapshots[proposalId];
if (snapshotBlock == 0) revert InvalidProposal();
return getPastVotes(account, snapshotBlock);
}

nowhere in the code snippet do we see a function to set proposalPowerSnapshots[proposalId] for valid proposals. If no external entity updates it, or if it’s assumed to be done by an external contract that also lacks logic, snapshotBlock remains 0 for all proposals, causing:

  1. Revert with InvalidProposal() for every query, or

  2. Permanent 0 block references, making the governance snapshot logic inoperable.

Attack / Demonstration

  1. Owner or Governance Attempting to Use Snapshots

    • A legitimate proposal is introduced, but no function sets proposalPowerSnapshots[id] = someBlockNumber.

  2. Call getVotingPowerForProposal(...)

    • The function fetches proposalPowerSnapshots[proposalId]0.

    • The code sees if (snapshotBlock == 0) revert InvalidProposal(); → reverts.

Result: All queries revert or produce invalid data, effectively breaking the governance snapshot concept.

Impact

  • Broken Governance Snapshot: The system cannot record or retrieve block snapshots per proposal, preventing stable “historical voting power” checks.

  • Impossible to Validate Past Votes: The contract’s design to check historical power at the snapshot block is moot if that block is never set.

  • Inconsistent Protocol Flow: Off-chain or external processes might assume the contract sets the snapshot automatically, but discover no function does so. This can cause confusion or wasted calls.

Recommended Fix

Add a function to set or update each proposal’s snapshot block, for instance:

function setProposalSnapshotBlock(uint256 proposalId, uint256 snapshotBlock) external onlyGovernance {
require(proposalId != 0, "Invalid proposalId");
require(snapshotBlock != 0, "Snapshot block cannot be zero");
proposalPowerSnapshots[proposalId] = snapshotBlock;
}
  • Access Control: Restrict to a legitimate governance contract or the owner.

  • Validation: Ensure snapshotBlock is nonzero and that the proposalId is recognized/valid if needed.

Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!