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: 48/110
Findings: 2
Award: $117.71
🌟 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.3374 USDC - $82.34
_safeMint()
should be used rather than _mint()
wherever possible_mint()
is discouraged (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4d8d2ed9798cc3383912a23b5e8d5cb602f7d4b/contracts/token/ERC721/ERC721.sol#L271) in favor of _safeMint()
which ensures that the recipient is either an EOA or implements IERC721Receiver
. Both OpenZeppelin and solmate have versions of this function
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/Crowdfund.sol
439 _mint(contributor);
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/PartyGovernanceNFT.sol
132 _mint(owner, tokenId);
In the contracts, floating pragmas should not be used. Contracts should be deployed with the same compiler version and flags that they have been tested with thoroughly. Locking the pragma helps to ensure that contracts do not accidentally get deployed using, for example, an outdated compiler version that might introduce bugs that affect the contract system negatively.
Proof of Concept https://swcregistry.io/docs/SWC-103
All contracts
All contracts
All contracts are missing @author, @title messages. Some contracts do not have any NatSpec messages at all.
indexed
fieldsEach event
should use three indexed
fields if there are three or more fields.
22 event FractionalV1VaultCreated( 23 IERC721 indexed token 24 uint256 indexed tokenId, 25 uint256 vaultId, 26 IERC20 vault, 27 uint256 listPrice 28 );
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/proposals/ListOnZoraProposal.sol
45 event ZoraAuctionCreated( 46 uint256 auctionId, 47 IERC721 token, 48 uint256 tokenId, 49 uint256 startingPrice, 50 uint40 duration, 51 uint40 timeoutTime 52 );
35 event ArbitraryCallExecuted(uint256 proposalId, uint256 idx, uint256 count);
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/BuyCrowdfundBase.sol
52 event Won(Party party, IERC721 token, uint256 tokenId, uint256 settledPrice);
63 event OpenseaOrderListed( 64 IOpenseaExchange.OrderParameters orderParams, 65 bytes32 orderHash, 66 IERC721 token, 67 uint256 tokenId, 68 uint256 listPrice, 69 uint256 expiry 70 ); 71 event OpenseaOrderSold( 72 bytes32 orderHash, 73 IERC721 token, 74 uint256 tokenId, 75 uint256 listPrice 76 ); 77 event OpenseaOrderExpired( 78 bytes32 orderHash, 79 IERC721 token, 80 uint256 tokenId, 81 uint256 expiry 82 ); 83 // Coordinated event w/OS team to track on-chain orders. 84 event OrderValidated( 85 bytes32 orderHash, 86 address indexed offerer, 87 address indexed zone, 88 IOpenseaExchange.OfferItem[] offer, 89 IOpenseaExchange.ConsiderationItem[] consideration, 90 IOpenseaExchange.OrderType orderType, 91 uint256 startTime, 92 uint256 endTime, 93 bytes32 zoneHash, 94 uint256 salt, 95 bytes32 conduitKey, 96 uint256 counter 97 );
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/Crowdfund.sol
82 event Burned(address contributor, uint256 ethUsed, uint256 ethOwed, uint256 votingPower); 83 event Contributed(address contributor, uint256 amount, address delegate, uint256 previousTotalContributions);
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/PartyGovernance.sol
151 event Proposed( 152 uint256 proposalId, 153 address proposer, 154 Proposal proposal 155 ); 156 event ProposalAccepted( 157 uint256 proposalId, 158 address voter, 159 uint256 weight 160 );
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/tokens/IERC1155.sol
20 event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
37 event DistributionFeeClaimed( 38 ITokenDistributorParty indexed party, 39 address indexed feeRecipient, 40 TokenType tokenType, 41 address token, 42 uint256 amount 43 );
It is good to add a require() statement that checks the return value of token transfers or to use something like OpenZeppelin’s safeTransfer/safeTransferFrom unless one is sure the given token reverts in case of a failure. Failure to do so will cause silent failures of transfers and affect token accounting in contract.
Reference: This similar medium-severity finding from Consensys Diligence Audit of Fei Protocol: https://consensys.net/diligence/audits/2021/01/fei-protocol/#unchecked-return-value-for-iweth-transfer-call
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/PartyGovernanceNFT.sol
143 super.transferFrom(owner, to, tokenId);
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/Crowdfund.sol
301 preciousTokens[i].transferFrom(address(this), address(party_), preciousTokenIds[i]);
keccak256()
, should use immutable rather than constanthttps://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/proposals/ProposalStorage.sol
19 uint256 private constant SHARED_STORAGE_SLOT = uint256(keccak256("ProposalStorage.SharedProposalStorage"));
80 uint256 private constant _STORAGE_SLOT = uint256(keccak256('ProposalExecutionEngine.Storage'));
#0 - 0xble
2022-09-26T01:13:10Z
Unhelpful bot response with some suggestions that don't make sense.
🌟 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.3735 USDC - $35.37
revert()/require()
stringsAll contracts
++i
costs less gas compared to i++
or i += 1
, same for --i/i--
. Especially in for loops++i
costs less gas compared to i++
or i += 1
for unsigned integer, as pre-increment is cheaper (about 5 gas per iteration). This statement is true even with the optimizer enabled.
i++
increments i and returns the initial value of i
.
uint i = 1; i++; // == 1 but i == 2
But ++i returns the actual incremented value:
uint i = 1; ++i; // == 2 and i == 2 too, so no need for a temporary variable
In the first case, the compiler has to create a temporary variable (when used) for returning 1 instead of 2
I suggest using ++i instead of i++ to increment the value of an uint variable.
If done inside for loop, saves 6 gas per loop.
62 for (uint256 i; i < hosts.length; i++) {
If a variable is not set/initialized, it is assumed to have the default value (0 for uint, false for bool, address(0) for address…). Explicitly initializing it with its default value is an anti-pattern and wastes gas.
As an example: for (uint256 i = 0; i < hadPreciouses.length; ++i) {
should be replaced with for (uint256 i; i < hadPreciouses.length; ++i) {
52 for (uint256 i = 0; i < hadPreciouses.length; ++i) { 61 for (uint256 i = 0; i < calls.length; ++i) { 78 for (uint256 i = 0; i < hadPreciouses.length; ++i) {
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/distribution/TokenDistributor.sol
230 for (uint256 i = 0; i < infos.length; ++i) { 239 for (uint256 i = 0; i < infos.length; ++i) {
291 for (uint256 i = 0; i < fees.length; ++i) {
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/Crowdfund.sol
180 for (uint256 i = 0; i < contributors.length; ++i) { 242 for (uint256 i = 0; i < numContributions; ++i) { 300 for (uint256 i = 0; i < preciousTokens.length; ++i) { 348 for (uint256 i = 0; i < numContributions; ++i) {
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/proposals/LibProposal.sol
14 for (uint256 i = 0; i < preciousTokens.length; ++i) { 32 for (uint256 i = 0; i < preciousTokens.length; ++i) {
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/PartyGovernance.sol
306 for (uint256 i=0; i < opts.hosts.length; ++i) { 432 uint256 low = 0;
In Solidity 0.8+, there’s a default overflow check on unsigned integers. It’s possible to uncheck this in for-loops and save some gas at each iteration, but at the cost of some code readability, as this uncheck cannot be made inline. This saves 30-40 gas PER LOOP.
52 for (uint256 i = 0; i < hadPreciouses.length; ++i) { 61 for (uint256 i = 0; i < calls.length; ++i) { 78 for (uint256 i = 0; i < hadPreciouses.length; ++i) {
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/distribution/TokenDistributor.sol
230 for (uint256 i = 0; i < infos.length; ++i) { 239 for (uint256 i = 0; i < infos.length; ++i) {
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/PartyGovernance.sol
306 for (uint256 i=0; i < opts.hosts.length; ++i) {
291 for (uint256 i = 0; i < fees.length; ++i) {
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/Crowdfund.sol
180 for (uint256 i = 0; i < contributors.length; ++i) { 242 for (uint256 i = 0; i < numContributions; ++i) { 300 for (uint256 i = 0; i < preciousTokens.length; ++i) { 348 for (uint256 i = 0; i < numContributions; ++i) {
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/proposals/LibProposal.sol
14 for (uint256 i = 0; i < preciousTokens.length; ++i) { 32 for (uint256 i = 0; i < preciousTokens.length; ++i) {
The overheads outlined below are PER LOOP, excluding the first loop
Caching the length changes each of these to a DUP<N> (3 gas), and gets rid of the extra DUP<N> needed to store the stack offset
52 for (uint256 i = 0; i < hadPreciouses.length; ++i) { 61 for (uint256 i = 0; i < calls.length; ++i) { 78 for (uint256 i = 0; i < hadPreciouses.length; ++i) {
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/distribution/TokenDistributor.sol
230 for (uint256 i = 0; i < infos.length; ++i) { 239 for (uint256 i = 0; i < infos.length; ++i) {
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/PartyGovernance.sol
306 for (uint256 i=0; i < opts.hosts.length; ++i) {
291 for (uint256 i = 0; i < fees.length; ++i) {
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/Crowdfund.sol
180 for (uint256 i = 0; i < contributors.length; ++i) { 300 for (uint256 i = 0; i < preciousTokens.length; ++i) {
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/proposals/LibProposal.sol
14 for (uint256 i = 0; i < preciousTokens.length; ++i) { 32 for (uint256 i = 0; i < preciousTokens.length; ++i) {
When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.
These can be found in most contracts that have variable assignments. Whenever possible consider using uint256 instead of smaller uint types.
Here is just a couple of examples: https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/BuyCrowdfund.sol#L30 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/BuyCrowdfund.sol#L39 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/CollectionBuyCrowdfund.sol#L51 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/BuyCrowdfundBase.sol#L94
abi.encode()
is less efficient than abi.encodepacked()
Whenever possible consider using abi.encodepacked()
to save gas.
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/proposals/ListOnZoraProposal.sol
115 return abi.encode(ZoraStep.ListedOnZora, ZoraProgressData({
164 return abi.encode(ListOnOpenseaStep.ListedOnZora, ZoraProgressData({ 219 return abi.encode(ListOnOpenseaStep.ListedOnOpenSea, orderHash, expiry);
// Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled.
Use uint256(1) and uint256(2) for true/false
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/globals/Globals.sol
12 mapping(uint256 => mapping(bytes32 => bool)) private _includedWordValues;
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/distribution/TokenDistributor.sol
30 mapping(uint256 => bool) hasPartyTokenClaimed; 62 bool public emergencyActionsDisabled;
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/Crowdfund.sol
106 bool private _splitRecipientHasBurned;
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/PartyGovernance.sol
148 mapping (address => bool) hasVoted; 197 bool public emergencyExecuteDisabled; 207 mapping(address => bool) public isHost;
This can be found in most contracts that have return functions.
Some examples: https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/globals/Globals.sol#L32 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/globals/Globals.sol#L36 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/globals/Globals.sol#L40 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/CrowdfundNFT.sol#L99 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/PartyGovernanceNFT.sol#L72 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/proposals/ListOnZoraProposal.sol#L181 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/proposals/ListOnZoraProposal.sol#L193
#0 - 0xble
2022-09-26T01:08:38Z
Unhelpful bot report