Core Contracts

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

No Restriction on Canceling a Failed Proposal After Voting Ends

Summary

The cancel() function in the governance contract does not check whether the proposal has already failed (Ended) before allowing cancellation. This means a proposal that has already failed due to insufficient votes or quorum can still be canceled after voting has ended, leading to unnecessary gas usage, governance confusion, and potential spam attacks.

Vulnerability Details

Affected Function:

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");
}

Issue:

  • The function does not check if the proposal has already failed before allowing cancellation.

  • This allows users to cancel a failed proposal even after the voting period has ended.

Impact

1️⃣ Gas Wastage & Network Congestion

  • Users may waste gas fees by canceling an already failed proposal, even though the action has no effect.

  • This can lead to unnecessary transactions on the blockchain, increasing congestion.

2️⃣ Governance Transparency Issues

  • Failed proposals should remain as Failed to maintain clear governance history.

  • Canceling them after they have already failed might confuse users into thinking the proposal was manually rejected.

3️⃣ Spam Attack Risk

  • A malicious user could create multiple failed proposals and then cancel them to manipulate governance tracking.

  • This can flood governance logs and make proposal history harder to audit.

Tools Used

Manuel Review

Recommendations

To prevent this issue, add a check to ensure that failed proposals cannot be canceled after voting has ended:

✅ Fixed Code:

function cancel(uint256 proposalId) external override {
ProposalCore storage proposal = _proposals[proposalId];
if (proposal.startTime == 0) revert ProposalDoesNotExist(proposalId);
ProposalState currentState = state(proposalId);
// ❌ Prevent cancellation if the proposal has already failed after the voting period ended
if (block.timestamp > proposal.endTime && currentState == ProposalState.Failed) {
revert InvalidProposalState(proposalId, currentState, ProposalState.Failed, "Cannot cancel a failed proposal");
}
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");
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
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!