Platform: Code4rena
Start Date: 03/05/2023
Pot Size: $60,500 USDC
Total HM: 25
Participants: 114
Period: 8 days
Judge: Picodes
Total Solo HM: 6
Id: 234
League: ETH
Rank: 72/114
Findings: 2
Award: $54.07
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: hyh
Also found by: Jiamin, Juntao, aashar, bytes032, circlelooper, mrpathfindr
17.8317 USDC - $17.83
A proposal receives no vote can still be updated in slate.
Any project can submit a proposal in screening stage, the top ten proposals receiving the most votes in screening stage are then voted upon in the funding stage, once the voting period ends, the winning proposals that can be executed are decided through a one week challenge period. In the challenge period, anyone can submit a set of winning proposals to execute, if the the sum of votes in the submitted proposal slate is larger than the previously submitted slate of proposals, then it becomes the new winning slate. This updating logic is implement in updateSlate function and validation is done through _validateSlate function:
function _validateSlate(uint24 distributionId_, uint256 endBlock, uint256 distributionPeriodFundsAvailable_, uint256[] calldata proposalIds_, uint256 numProposalsInSlate_) internal view returns (uint256 sum_) { // check that the function is being called within the challenge period if (block.number <= endBlock || block.number > _getChallengeStageEndBlock(endBlock)) { revert InvalidProposalSlate(); } // check that the slate has no duplicates if (_hasDuplicates(proposalIds_)) revert InvalidProposalSlate(); uint256 gbc = distributionPeriodFundsAvailable_; uint256 totalTokensRequested = 0; // check each proposal in the slate is valid for (uint i = 0; i < numProposalsInSlate_; ) { Proposal memory proposal = _standardFundingProposals[proposalIds_[i]]; // check if Proposal is in the topTenProposals list if (_findProposalIndex(proposalIds_[i], _topTenProposals[distributionId_]) == -1) revert InvalidProposalSlate(); // account for fundingVotesReceived possibly being negative if (proposal.fundingVotesReceived < 0) revert InvalidProposalSlate(); // update counters sum_ += uint128(proposal.fundingVotesReceived); // since we are converting from int128 to uint128, we can safely assume that the value will not overflow totalTokensRequested += proposal.tokensRequested; // check if slate of proposals exceeded budget constraint ( 90% of GBC ) if (totalTokensRequested > (gbc * 9 / 10)) { revert InvalidProposalSlate(); } unchecked { ++i; } } }
However, system does not check if the funding votes of the submitted proposals is 0, it only checks if the votes being negative:
if (proposal.fundingVotesReceived < 0) revert InvalidProposalSlate();
This could lead to any proposal with 0 votes being updated in the slate and is then be executed.
Manual Review
system should check if the funding votes received by a proposal is 0:
if (proposal.fundingVotesReceived <= 0) revert InvalidProposalSlate();
Context
#0 - c4-judge
2023-05-18T14:10:04Z
Picodes marked the issue as primary issue
#1 - c4-judge
2023-05-18T14:11:21Z
Picodes marked issue #465 as primary and marked this issue as a duplicate of 465
#2 - c4-judge
2023-05-30T20:12:20Z
Picodes marked the issue as partial-25