Core Contracts

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

Cancelled Proposals Can Still Be Voted On in Governance Contract

Summary

In the Governance contract, when a proposal is cancelled, the contract only updates its state with a canceled flag, without invalidating the proposal data. As a result, the castVote function does not check if a proposal has been cancelled, allowing users to vote on proposals that should no longer be active.

Vulnerability Details

  • Affected Functions:

    • cancel(uint256 proposalId):

      function cancel(uint256 proposalId) external override {
      ProposalCore storage proposal = _proposals[proposalId];
      if (proposal.startTime == 0) revert ProposalDoesNotExist(proposalId);
      ProposalState currentState = state(proposalId);
      if (currentState == ProposalState.Executed) {
      revert InvalidProposalState(proposalId, currentState, ProposalState.Active, "Cannot cancel executed proposal");
      }
      if (msg.sender != proposal.proposer &&
      _veToken.getVotingPower(proposal.proposer) >= proposalThreshold) {
      revert InsufficientProposerVotes(proposal.proposer,
      _veToken.getVotingPower(proposal.proposer), proposalThreshold, "Proposer lost required voting power");
      }
      proposal.canceled = true;
      emit ProposalCanceled(proposalId, msg.sender, "Proposal canceled by proposer");
      }
    • castVote(uint256 proposalId, bool support):

      function castVote(uint256 proposalId, bool support) external override returns (uint256) {
      ProposalCore storage proposal = _proposals[proposalId];
      if (proposal.startTime == 0) revert ProposalDoesNotExist(proposalId);
      if (block.timestamp < proposal.startTime) {
      revert VotingNotStarted(proposalId, proposal.startTime, block.timestamp);
      }
      if (block.timestamp > proposal.endTime) {
      revert VotingEnded(proposalId, proposal.endTime, block.timestamp);
      }
      ProposalVote storage proposalVote = _proposalVotes[proposalId];
      if (proposalVote.hasVoted[msg.sender]) {
      revert AlreadyVoted(proposalId, msg.sender, block.timestamp);
      }
      uint256 weight = _veToken.getVotingPower(msg.sender);
      if (weight == 0) {
      revert NoVotingPower(msg.sender, block.number);
      }
      proposalVote.hasVoted[msg.sender] = true;
      if (support) {
      proposalVote.forVotes += weight;
      } else {
      proposalVote.againstVotes += weight;
      }
      emit VoteCast(msg.sender, proposalId, support, weight, "");
      return weight;
      }
  • Issue:
    The cancel function only sets the canceled flag for a proposal but does not fully invalidate the proposal, leaving it eligible for further actions like voting. The castVote function does not verify whether the proposal has been cancelled, meaning users can still vote on proposals that should no longer be active.

Impact

  • Inconsistent Governance State:
    Votes can be cast on proposals that have already been cancelled, leading to misleading vote counts and confusion in the governance process.

  • Loss of Trust in Governance:
    If users realize that cancelled proposals can still receive votes, they may lose confidence in the system's ability to enforce proper governance rules.

Tools Used

  • Manual Code Review

Recommendations

  1. Ensure Proposal Cancellation is Enforced in Voting:
    Modify the castVote function to check if a proposal has been cancelled before allowing any votes to be cast. For example:

    if (proposal.canceled) {
    revert ProposalCancelled(proposalId);
    }
  2. Invalidate Cancelled Proposals Completely:
    Consider modifying how cancelled proposals are stored or marked to prevent any further interaction with them, including voting.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Governance::castVote lacks canceled/executed proposal check, allowing users to waste gas voting on proposals that can never be executed

inallhonesty Lead Judge about 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Governance::castVote lacks canceled/executed proposal check, allowing users to waste gas voting on proposals that can never be executed

Support

FAQs

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