Core Contracts

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

Inability to Update Vote Decision

Summary

The castVote function does not allow users to update their vote once it has been cast. If a user votes for a proposal but later decides to vote against (or vice versa), they cannot change their decision. This limitation reduces the flexibility and usability of the governance system.

Vulnerability Details

Root Cause:

The issue stems from the following logic in the castVote function:

if (proposalVote.hasVoted[msg.sender]) {
revert AlreadyVoted(proposalId, msg.sender, block.timestamp);
}
  • Once a user has voted, the hasVoted mapping is set to true, preventing them from voting again.

  • There is no mechanism to update or change a vote.

Impact

  • Reduced Flexibility: Users cannot change their vote if they change their mind or make a mistake.

  • Inefficient Governance: Votes may not accurately reflect the current preferences of the community.

  • User Frustration: Users may feel locked into their initial decision, reducing engagement in the governance process.

PoC

Example Scenario:

  1. A user votes for a proposal with their full voting power.

  2. After further consideration, the user decides to vote against the proposal.

  3. The user attempts to call castVote again but is blocked by the AlreadyVoted check.

  4. The user's initial for vote remains counted, even though it no longer reflects their preference.

Tools Used

Manual Review

Recommendations

To address this issue, implement a mechanism that allows users to update their vote.

Allow Vote Updates:

  • Modify the castVote function to allow users to update their vote.

  • Subtract their previous vote weight before applying the new vote.

  • Example:

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];
uint256 weight = _veToken.getVotingPower(msg.sender);
if (weight == 0) {
revert NoVotingPower(msg.sender, block.number);
}
// If the user has already voted, subtract their previous vote weight
if (proposalVote.hasVoted[msg.sender]) {
if (proposalVote.lastVoteSupport[msg.sender]) {
proposalVote.forVotes -= proposalVote.lastVoteWeight[msg.sender];
} else {
proposalVote.againstVotes -= proposalVote.lastVoteWeight[msg.sender];
}
}
// Apply the new vote
if (support) {
proposalVote.forVotes += weight;
} else {
proposalVote.againstVotes += weight;
}
// Update the user's voting status
proposalVote.hasVoted[msg.sender] = true;
proposalVote.lastVoteSupport[msg.sender] = support;
proposalVote.lastVoteWeight[msg.sender] = weight;
emit VoteCast(msg.sender, proposalId, support, weight, "");
return weight;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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