Platform: Code4rena
Start Date: 12/09/2022
Pot Size: $75,000 USDC
Total HM: 19
Participants: 110
Period: 7 days
Judge: HardlyDifficult
Total Solo HM: 9
Id: 160
League: ETH
Rank: 49/110
Findings: 2
Award: $117.70
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Lambda
Also found by: 0x1f8b, 0x4non, 0x52, 0x5rings, 0xDanielC, 0xNazgul, 0xSmartContract, 0xbepresent, Anth3m, Aymen0909, B2, CRYP70, CertoraInc, Ch_301, Chom, ChristianKuri, CodingNameKiki, Deivitto, Funen, JC, JansenC, Jeiwan, KIntern_NA, MasterCookie, MiloTruck, Olivierdem, PaludoX0, R2, RaymondFam, ReyAdmirado, StevenL, The_GUILD, Tomo, Trust, V_B, __141345__, asutorufos, ayeslick, bin2chen, brgltd, bulej93, c3phas, cccz, ch0bu, cryptphi, csanuragjain, d3e4, delfin454000, djxploit, erictee, fatherOfBlocks, gogo, hansfriese, indijanc, ladboy233, leosathya, lukris02, malinariy, martin, pedr02b2, pfapostol, rvierdiiev, slowmoses, smiling_heretic, tnevler, wagmi
82.3482 USDC - $82.35
// An address that receieves an extra share of the final voting power
Change receieves
to receives
ListOnOpenseaProposal.sol: L303
// Emit the the coordinated OS event so their backend can detect this order.
Remove repeated word the
The same typo (recipeint
) occurs in both lines below:
Example (Crowdfund.sol: L46):
// Fee recipeint for governance distributions.
Change recipeint
to recipient
// Deploys and initializes a a `Party` instance via the `PartyFactory`
Remove repeated word a
Long comments are wrapped using inconsistent syntax in the contest. Some are wrapped conventionally, using a few additional spaces after the ///
or //
in the second (and any subsequent lines), as shown below:
/// @dev proposal.cancelDelay seconds must have passed since it was first /// executed for this to be valid.
This flags for the reader that the comment is continuing. However, the majority of multiline comments in the contest are not indented in the second (and any subsequent wrapped lines). For example:
/// Allows one to simply transfer and call `createDistribution()` without /// fussing with allowances.
In addition, some comments wrap using extra-wide indentations, as shown below:
/// @notice Create a new crowdfund to bid on an auction for a specific NFT /// (i.e. with a known token ID). /// @param opts Options used to initialize the crowdfund. These are fixed /// and cannot be changed later. /// @param createGateCallData Encoded calldata used by `createGate()` to create /// the crowdfund if one is specified in `opts`.
Suggestion: For increased readability, wrap multiline comments using consistent syntax throughout Party DAO
return
variable not usedThe existence of a named return variable that is not subsequently used (here, newGateKeeperId
) is potentially perplexing
CrowdfundFactory.sol: L107-122
function _prepareGate( IGateKeeper gateKeeper, bytes12 gateKeeperId, bytes memory createGateCallData ) private returns (bytes12 newGateKeeperId) { if ( address(gateKeeper) == address(0) || gateKeeperId != bytes12(0) ) { // Using an existing gate on the gatekeeper // or not using a gate at all. return gateKeeperId; }
require
revert stringsA require
message should be included to enable users to understand reason for failure
Recommendation: Add a brief (<= 32 char) explanatory message to each of the three requires
referenced below. Also, consider using custom error codes (which would be cheaper than revert strings).
require(msg.sender == address(this));
ProposalExecutionEngine.sol: L246
require(proposalType != ProposalType.Invalid);
ProposalExecutionEngine.sol: L247
require(uint8(proposalType) < uint8(ProposalType.NumProposalTypes));
for
loopsOne of the for
loop counters is not initiated to zero, as shown below:
CollectionBuyCrowdfund.sol: L62
for (uint256 i; i < hosts.length; i++) {
However, the remaining 13 of the for
loop counters are initialized to zero, as the example below shows:
ArbitraryCallsProposal.sol: L52
for (uint256 i = 0; i < hadPreciouses.length; ++i) {
It is not necessary to initialize for
loop counters to zero since this is their default value. For consistency, it makes sense to omit counter initializations in all of the for
loops
🌟 Selected for report: CertoraInc
Also found by: 0x1f8b, 0x4non, 0x5rings, 0x85102, 0xNazgul, 0xSmartContract, 0xkatana, Amithuddar, Aymen0909, B2, Bnke0x0, CRYP70, Chom, ChristianKuri, CodingNameKiki, Deivitto, Diraco, Fitraldys, Funen, IgnacioB, JAGADESH, JC, Lambda, LeoS, Matin, Metatron, MiloTruck, Noah3o6, Ocean_Sky, Olivierdem, PaludoX0, RaymondFam, ReyAdmirado, Rohan16, Rolezn, Saintcode_, Sm4rty, SnowMan, StevenL, Tomio, Tomo, V_B, Waze, __141345__, ajtra, asutorufos, aysha, brgltd, bulej93, c3phas, ch0bu, d3e4, delfin454000, dharma09, djxploit, erictee, fatherOfBlocks, francoHacker, gianganhnguyen, gogo, got_targ, ignacio, jag, karanctf, ladboy233, leosathya, lukris02, m_Rassska, malinariy, martin, natzuu, pashov, peanuts, peiw, pfapostol, prasantgupta52, robee, simon135, slowmoses, sryysryy, tnevler
35.348 USDC - $35.35
Initializing uint
variables to their default value of 0
is unnecessary and costs gas
uint256 low = 0;
Change to:
uint256 low;
for
loopSince calculating the array length costs gas, it's best to read the length of the array from memory before executing the loop
CollectionBuyCrowdfund.sol: L62-67
for (uint256 i; i < hosts.length; i++) { if (hosts[i] == msg.sender) { isHost = true; break; } }
Suggestion:
uint256 numHosts = hosts.length; for (uint256 i; i < numHosts; i++) { if (hosts[i] == msg.sender) { isHost = true; break; } }
Similarly for the eleven additional for
loops referenced below:
ArbitraryCallsProposal.sol: L52-57
ArbitraryCallsProposal.sol: L61-74
ArbitraryCallsProposal.sol: L78-87
TokenDistributor.sol: L230-232
TokenDistributor.sol: L239-241
ListOnOpenseaProposal.sol: L291-298
++i
instead of i++
to increase count in a for
loopSince use of i++
(or equivalent counter) costs more gas, it is better to use ++i
CollectionBuyCrowdfund.sol: L62-67
for (uint256 i; i < hosts.length; i++) { if (hosts[i] == msg.sender) { isHost = true; break; } }
Suggestion:
uint256 numHosts = hosts.length; for (uint256 i; i < numHosts; ++i) { if (hosts[i] == msg.sender) { isHost = true; break; } }
___ ___ ### Avoid use of default "checked" behavior in a `for` loop Underflow/overflow checks are made every time `++i` (or equivalent counter) is called. Such checks are unnecessary since `i` is already limited. Therefore, use `unchecked ++i` instead ___ [CollectionBuyCrowdfund.sol: L62-67](https://github.com/PartyDAO/party-contracts-c4/blob/3896577b8f0fa16cba129dc2867aba786b730c1b/contracts/crowdfund/CollectionBuyCrowdfund.sol#L62-L67) ```solidity for (uint256 i; i < hosts.length; i++) { if (hosts[i] == msg.sender) { isHost = true; break; } }
Suggestion:
uint256 numHosts = hosts.length; for (uint256 i; i < numHosts;) { if (hosts[i] == msg.sender) { isHost = true; break; unchecked { ++i; } } }
Similarly for the thirteen additional for
loops referenced below:
ArbitraryCallsProposal.sol: L52-57
ArbitraryCallsProposal.sol: L61-74
ArbitraryCallsProposal.sol: L78-87
TokenDistributor.sol: L230-232
TokenDistributor.sol: L239-241
ListOnOpenseaProposal.sol: L291-298