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
Rank: 89/110
Findings: 2
Award: $14.58
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: deth
Also found by: 00xSEV, 0xCiphky, 0xHelium, ABAIKUNANBAEV, Aamir, AkshaySrivastav, King_, Pechenite, SpicyMeatball, Tricko, ast3ros, ayden, bart1e, deth, fnanni, ke1caM, mahdirostami, peanuts, pep7siup, pontifex, ptsanev, roland, rvierdiiev, y4y
7.2215 USDC - $7.22
Judge has assessed an item in Issue #286 as 2 risk. The relevant finding follows:
[L-02] Quorum for existing piece cannot be changed [L-03] Token inflation gives advantage to new pieces
#0 - c4-judge
2024-01-07T18:56:27Z
MarioPoneder marked the issue as duplicate of #449
#1 - c4-judge
2024-01-07T18:56:37Z
MarioPoneder marked the issue as satisfactory
🌟 Selected for report: 0xmystery
Also found by: 00xSEV, 0xCiphky, 0xDING99YA, 0xhitman, ABAIKUNANBAEV, Aamir, BARW, IllIllI, King_, MrPotatoMagic, Pechenite, SovaSlava, SpicyMeatball, Topmark, Ward, ZanyBonzy, ast3ros, bart1e, cheatc0d3, deth, developerjordy, hals, imare, kaveyjoe, ktg, leegh, osmanozdemir1, peanuts, roland, rvierdiiev, shaka, sivanesh_808, spacelord47
7.359 USDC - $7.36
Issue | Description |
---|---|
[L-01] | No option to withdraw vote |
[L-02] | Quorum for existing piece cannot be changed |
[L-03] | Token inflation gives advantage to new pieces |
[L-04] | Vote allocation for ERC721 minted for active auction is counted in totalVotesSupply |
[L-05] | Front-running createPiece |
[L-06] | block.number accuracy in an L2 deployment |
[N-01] | Unnecessary double negation in require statement |
[N-02] | Code comment mismatch in getVote() |
[N-03] | No ownership checks on metadata content |
[N-04] | Code and error message mismatch on AuctionHouse initialization |
There is currently no option for a user to withdraw their vote in CultureIndex.sol. Although this seems to be by design, in a voting process where art pieces are competing with each other and the available option pool can change dramatically every day, it would be reasonable to assume a user has the option to reevaluate their choice after a change in circumstances.
Adding a function to nullify votes but have them count towards quorum would fix this issue.
There is currently no option to change the quorum value for an art piece that has already been created in CultureIndex.sol. This can lead to situations in which a more popular older piece with stricter quorum requirements stays in the contract, while a newer piece with fewer votes but more relaxed quorum requirements proceeds to auction.
Unify quorum across all art pieces. Instead of storing quorumVotes in the ArtPiece struct, calculate the value in dropTopVotedPiece()
with piece.totalVotesSupply
and current quorumVotesBPS
ICultureIndex.ArtPiece memory piece = getTopVotedPiece(); - require(totalVoteWeights[piece.pieceId] >= piece.quorumVotes, "Does not meet quorum votes to be dropped."); + require(totalVoteWeights[piece.pieceId] >= (quorumVotesBPS * piece.totalVotesSupply) / 10_000, "Does not meet quorum votes to be dropped.");
With constant token inflation and the vote winner being determined by absolute votes, the system will give preference to newer pieces, as they could end up having orders of magnitude greater eligible voting numbers.
Reconsider snapshotting user voting power, allowing each piece to have the same potential number of votes. The governance attack risk is greatly minimised by the non-transferable nature of the ERC20 governance tokens, as well as the illiquidity of the ERC721 tokens.
In CultureIndex.sol#L228, totalVotesSupply includes the corresponding votes of the ERC721 currently being auctioned off, although it will not be able to used to vote for the created piece, even after the auction end. The impact on voting process and quorum can vary depending on ERC721 voting weight.
In CultureIndex.sol#L228, a malicious user might monitor art piece submissions in createPiece()
, and front-run the transaction with the same metadata but different creator addresses, to give legitimacy to the front-ran piece and gain advantage in the vote or auction.
In an L2 deployment of the protocol, getPastVotes()
might revert if voting on a newly created piece within the same L1 block as the art piece creation block in CultureIndex.sol#L233
Double negation in CultureIndex.sol#L457 makes the statement unnecessarily confusing.
Improve readability by removing double negation.
- require(!(votes[pieceId][voter].voterAddress != address(0)), "Already voted"); + require(votes[pieceId][voter].voterAddress == address(0), "Already voted");
While getVote() in CultureIndex.sol#L457 returns a single vote struct, given a pieceId and voter address, the function comments describe the return value to be an array of Vote structs given a pieceId. Tests indicate the code to be correct and the comments to be wrong.
While anyone can permissionlessly submit art piece in CultureIndex.sol, they can also submit duplicates of art already submitted or auctioned off, for the purpose of diluting or stealing votes.
@ audit error message should be changed to "Creator rate must be greater than or equal to the minimum creator rate" require( _auctionParams.creatorRateBps >= _auctionParams.minCreatorRateBps, "Creator rate must be greater than or equal to the creator rate" );
#0 - raymondfam
2023-12-24T17:43:06Z
Possible upgrades:
L-02 & L03 --> #449 L-04 --> #18
#1 - c4-pre-sort
2023-12-24T17:43:11Z
raymondfam marked the issue as sufficient quality report
#2 - MarioPoneder
2024-01-07T18:55:24Z
Possible upgrades:
L-02 & L03 --> #449 L-04 --> #18
L-02/03: Upgrade
L-04: Insufficient elaboration for upgrade
#3 - c4-judge
2024-01-07T19:40:44Z
MarioPoneder marked the issue as grade-b