Revolution Protocol - pontifex's results

A protocol to empower communities to raise funds, fairly distribute governance, and maximize their impact in the world.

General Information

Platform: Code4rena

Start Date: 13/12/2023

Pot Size: $36,500 USDC

Total HM: 18

Participants: 110

Period: 8 days

Judge: 0xTheC0der

Id: 311

League: ETH

Collective

Findings Distribution

Researcher Performance

Rank: 100/110

Findings: 1

Award: $7.22

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

7.2215 USDC - $7.22

Labels

bug
2 (Med Risk)
satisfactory
sufficient quality report
duplicate-449

External Links

Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L313-L322 https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L292-L298

Vulnerability details

Impact

The order of pieces at the MaxHeap is determined by the number of votes they received. But the required quorum for each pieceId may differ due to different totalSupply at the time of creation. Thus, the zero position can be taken by a pieceId that has more votes, but does not reach a quorum, and other pieceIds with sufficient quorum will not be able to get into the auction.

Proof of Concept

The MaxHeap contract sorts the pieceId according to the size of the value. The number of user votes is used as value.

        uint256 weight = _getPastVotes(voter, pieces[pieceId].creationBlock);
        require(weight > minVoteWeight, "Weight must be greater than minVoteWeight");

        votes[pieceId][voter] = Vote(voter, weight);
        totalVoteWeights[pieceId] += weight;

        uint256 totalWeight = totalVoteWeights[pieceId];

        // TODO add security consideration here based on block created to prevent flash attacks on drops?
        maxHeap.updateValue(pieceId, totalWeight);

Pieces with index zero are included in the auction, i.e. the maximum number of votes from all pieceIds. But it is also checked that the play has received enough votes to pass a quorum. This logic is done in the CultureIndex.dropTopVotedPiece function.

        ICultureIndex.ArtPiece memory piece = getTopVotedPiece();
        require(totalVoteWeights[piece.pieceId] >= piece.quorumVotes, "Does not meet quorum votes to be dropped.");

Quorum is defined as the percentage of the total number of votes at the time of creation of the pieceId.

        newPiece.quorumVotes = (quorumVotesBPS * newPiece.totalVotesSupply) / 10_000;

Therefore, for different pieceIds, the quorum size may differ, as well as the maximum number of votes. Accordingly, a situation may occur when a pieceID with a large number of votes, but with insufficient quorum, is located above other pieces, with a smaller number of maximum allowed votes determined at the time of creation.

Tools Used

Manual review

Consider using the ratio of the number of votes to the required quorum for ordering at the MaxHeap binary tree.

Assessed type

Governance

#0 - c4-pre-sort

2023-12-23T03:03:50Z

raymondfam marked the issue as sufficient quality report

#1 - c4-pre-sort

2023-12-23T03:03:58Z

raymondfam marked the issue as duplicate of #16

#2 - c4-pre-sort

2023-12-24T15:11:31Z

raymondfam marked the issue as duplicate of #449

#3 - c4-judge

2024-01-06T16:03:36Z

MarioPoneder marked the issue as satisfactory

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter