Core Contracts

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

Unused `recordVote` Function in `veRAACToken` Contract: Inefficiency and Potential Enhancement

Summary

The veRAACToken contract contains a function named recordVote, which records a voter's participation in a proposal. However, this function is never called within the Governance contract, nor is the _hasVotedOnProposal mapping utilized in any way. This discrepancy contradicts the protocol's stated objective of comprehensive vote tracking and proposal state management. While the Governance::castVote function efficiently tracks votes, the existence of recordVote without usage introduces unnecessary redundancy. However, rather than being redundant, this function can be repurposed to enhance voter incentives by integrating a rewards mechanism based on voting participation.

Vulnerability Details

recordVote Function in veRAACToken Contract

function recordVote(address voter, uint256 proposalId) external {
if (_hasVotedOnProposal[voter][proposalId]) revert AlreadyVoted();
_hasVotedOnProposal[voter][proposalId] = true;
uint256 power = getVotingPower(voter);
emit VoteCast(voter, proposalId, power);
}

The function simply records a voter's participation and emits a VoteCast event. However, since it is never invoked in the Governance contract, its effect is nullified.

castVote Function in Governance Contract

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

The castVote function properly tracks votes within the governance system but does not call recordVote. This results in an inconsistency where the recordVote function exists without serving any meaningful purpose.

Impact

  1. Inefficiency & Redundancy: The existence of an unused function (recordVote) adds unnecessary complexity and confusion.

  2. Missed Opportunity for Reward Mechanism: The protocol can utilize recordVote to track voting participation, allowing voters to earn incentives for their governance engagement.

  3. Inconsistent Vote Tracking: The protocol claims comprehensive vote tracking, but not using recordVote contradicts this statement.

Tools Used

  • Manual Review

  • AI (ChatGPT)

Recommended Fix: Implement Voting-Based Rewards

Instead of removing the recordVote function, we recommend utilizing it to introduce a voter reward system. By tracking voter participation across multiple proposals, the protocol can reward governance participants with additional veRAAC tokens or boost their governance influence.

Solution

Modify the castVote function to call recordVote:

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;
veRAACToken.recordVote(msg.sender, proposalId); // Call recordVote
if (support) {
proposalVote.forVotes += weight;
} else {
proposalVote.againstVotes += weight;
}
emit VoteCast(msg.sender, proposalId, support, weight, "");
return weight;
}

Reward Mechanism

Once recordVote is used to track participation, a reward mechanism can be integrated by leveraging the _updateBoostState function:

function _updateBoostState(address user, uint256 newAmount) internal {
_boostState.votingPower = _votingState.calculatePowerAtTimestamp(user, block.timestamp);
_boostState.totalVotingPower = totalSupply();
_boostState.totalWeight = _lockState.totalLocked;
_boostState.updateBoostPeriod();
// _boostState.updateUserBalance(user, newAmount);
}

Implementation Steps:

  1. Track Number of Proposals Voted On: Maintain a mapping to store the number of times a user has voted.

  2. Integrate Reward Distribution: Distribute veRAAC tokens to users based on their participation levels.

  3. Boost Governance Power: Use _updateBoostState to enhance the governance influence of active voters.

By implementing this approach, the recordVote function gains meaningful utility, aligning with the protocol’s goal of comprehensive vote tracking while incentivizing governance participation.

Conclusion

The recordVote function in veRAACToken currently serves no purpose, contradicting the protocol's comprehensive vote-tracking claim. Instead of removing it, we propose repurposing it to track voter participation and reward engaged voters through additional veRAAC tokens or governance influence boosts. This approach enhances voter incentives, improves governance engagement, and aligns with the protocol’s stated goals.

Updates

Lead Judging Commences

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

Appeal created

theirrationalone Submitter
4 months ago
inallhonesty Lead Judge
4 months ago
inallhonesty Lead Judge 3 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.