Core Contracts

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

Governance::castVote do not take power at timestamp of proposal but block.timestamp, user can add more to their voting power

Summary

Governance::castVote() use power at time of vote and not at time of proposal. Any user can increase() their locked stack to have more influence on decisive proposals.

Vulnerability Details

If a proposal that do not fit with the idea of a user, he can instantly create and lock() RAACToken to have more voting in a proposition.

The power should be calculated at the time of proposal and not when a user call castVote(). It should call getVotingPower(address account, uint256 timestamp)

Impact

  • Governance voting power can be manipulated after proposal creation

  • No snapshot system to prevent time-based manipulation

  • Undermines fair voting process

  • Can be exploited to force proposal outcomes

Tools Used

Manual

Recommendations

castVote() should use timestamp of the proposal instead of block.timestamp, and call getVotingPower(address account, uint256 timestamp) instead of getVotingPower(address account)

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);
+ uint256 weight = _veToken.getVotingPower(msg.sender, proposal.startTime);
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;
}
Updates

Lead Judging Commences

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

Governance.castVote uses current voting power instead of proposal creation snapshot, enabling vote manipulation through token transfers and potential double-voting

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

Governance.castVote uses current voting power instead of proposal creation snapshot, enabling vote manipulation through token transfers and potential double-voting

Support

FAQs

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