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: 37/110
Findings: 2
Award: $118.65
🌟 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
83.2171 USDC - $83.22
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/PartyFactory.sol#L12
The comment should be rewritten as:
/// @notice Factory used to deploy new proxified Party
instances.
The comment should be rewritten as:
// Inherited by contracts to perform read-only delegate calls.
The comment should be rewritten as:
// A temporary state set by the contract during complex operations to
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/globals/Globals.sol#L27-L28
transferMultiSig()
should be implemented giving ownership to another address in a pending state. And then, a claimMultiSig()
should be introduced for the new owner(s) to claim ownership. This will ensure the new set of owners are going to be fully aware of their ownership in new duties.
Where possible, include a zero address check for transferMultiSig()
to avoid non-functional calls on claimMultiSig()
, as well as emitting an event on the new ownership transferred.
Consider indexing parameters for events, serving as logs filter when looking for specifically wanted data. Up to three parameters in an event function can receive the attribute indexed which will cause the respective arguments to be treated as log topics instead of data. The following links are some of the instances entailed:
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/IPartyFactory.sol#L11 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/proposals/ArbitraryCallsProposal.sol#L35
transferFrom
ERC721 has both safeTransferFrom
and transferFrom
, where safeTransferFrom
throws an error if the receiving contract's onERC721Received
method doesn't return a specific magic number. This will ensure a receiving contract is capable of receiving the token to prevent a permanent loss. Where possible, disable transferFrom()
by rewriting it as follows to prevent calls emanating outside the UI:
error VotesTransferDisabled(); function transferFrom(address owner, address to, uint256 tokenId) public override onlyDelegateCall { revert VotesTransferDisabled(); }
Zero address and zero value checks should be implemented when initializer is delegatecalled by Proxy
constructor. This is because there is no setter functions for these options or initData parameters. In the event a mistake was committed, not only that all calls associated with it would be non-functional, the contract would also have to be redeployed. Here are some of the instances entailed:
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/BuyCrowdfund.sol#L64-L88 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/Party.sol#L33-L45
call
, which returns a boolean value indicating success or failure, in combination with re-entrancy guard is the recommended method to use after December 2019. And, guard against re-entrancy by making all state changes before calling other contracts using re-entrancy guard modifier. Here's one instance entailed:
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/crowdfund/Crowdfund.sol#L487
withdraw()
for Additional ETH Left in the ContractThe following line of code could receive ETH returned from an auction and also other sources including someone forces (suicides) ETH into the contract. The inherited functions from Crowdfund.sol
seem to only cater for address(this).balance at the initializer for the initial contributors, and refund ethOwed
based on unused contributions. Consider implementing a withdraw()
just in case there will be additional ETH stuck in the contract.
#0 - HardlyDifficult
2022-10-03T22:27:42Z
🌟 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.4285 USDC - $35.43
When running a function we could pass the function parameters as calldata or memory for variables such as strings, structs, arrays etc. If we are not modifying the passed parameter we should pass it as calldata because calldata is more gas efficient than memory. Here are some of the instances entailed:
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/PartyGovernanceNFT.sol#L50-L54 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/Party.sol#L33
If a variable is not set/initialized, it is assumed to have the default value (0, false, 0x0 etc depending on the data type). If you explicitly initialize it with its default value, you will be incurring more gas. Hence, in the for loop of the following instances, refrain from doing i = 0. Here are some of the instances entailed:
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/proposals/ArbitraryCallsProposal.sol#L52 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/proposals/ArbitraryCallsProposal.sol#L61 https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/proposals/ArbitraryCallsProposal.sol#L78
In the EVM, there is no opcode for non-strict inequalities (>=, <=) and two operations are performed (> + =.) Consider replacing >= with the strict counterpart >. For instance, the following line of code could be rewritten as:
if (call.data.length > 3)
The order of function will also have an impact on gas consumption. Because in smart contracts, there is a difference in the order of the functions. Each position will have an extra 22 gas. The order is dependent on method ID. So, if you rename the frequently accessed function to more early method ID, you can save gas cost. Please visit the following site for further information:
Before deploying your contract, activate the optimizer when compiling using “solc --optimize --bin sourceFile.sol”. By default, the optimizer will optimize the contract assuming it is called 200 times across its lifetime. If you want the initial contract deployment to be cheaper and the later function executions to be more expensive, set it to “ --optimize-runs=1”. Conversely, if you expect many transactions and do not care for higher deployment cost and output size, set “--optimize-runs” to a high number. Please visit the following site for further information:
https://docs.soliditylang.org/en/v0.5.4/using-the-compiler.html#using-the-commandline-compiler
"Checked" math, which is default in 0.8.0 is not free. The compiler will add some overflow checks, somehow similar to those implemented by SafeMath
. While it is reasonable to expect these checks to be less expensive than the current SafeMath
, one should keep in mind that these checks will increase the cost of "basic math operation" that were not previously covered. This particularly concerns variable increments in for loops. Considering no arithmetic overflow/underflow is going to happen in the for loop instance below, unchecked { ++i ;}
to use the previous wrapping behavior further saves gas:
for (uint256 i=0; i < opts.hosts.length;) { isHost[opts.hosts[i]] = true; unchecked { ++i; } }
+=
generally costs more gas than writing out the assigned equation explicitly. As an example, the following line of code could be rewritten as:
https://github.com/PartyDAO/party-contracts-c4/blob/main/contracts/party/PartyGovernance.sol#L595
values.votes = values.votes + votingPower;
The assert()
function when false, uses up all the remaining gas and reverts all the changes made. On the other hand, a require()
function when false, also reverts back all the changes made to the contract but does refund all the remaining gas fees we offered to pay.
On a side note, the assert function should only be used to examine invariants and test for internal problems. When used correctly, it can assess your contract and discover the conditions and function calls that will result in a failed assert. A properly running program should never reach a failing assert statement; if this occurs, there is a flaw in your contract that has to be addressed.
Consider having the logic of a modifier embedded through an internal or private function to reduce contract size if need be. For instance, the following instance of modifier may be rewritten as follows:
function _onlyPartyDaoOrHost() private view { address partyDao = _GLOBALS.getAddress(LibGlobals.GLOBAL_DAO_WALLET); if (msg.sender != partyDao && !isHost[msg.sender]) { revert OnlyPartyDaoOrHostError(msg.sender, partyDao); } } modifier onlyPartyDaoOrHost() { _onlyPartyDaoOrHost(); _; }
++i costs less gas compared to i++ or i += 1 for unsigned integers considering the pre-increment operation is cheaper (about 5 GAS per iteration).
i++ increments i and makes the compiler create a temporary variable for returning the initial value of i. In contrast, ++i returns the actual incremented value without making the compiler do extra job.
Here's one instance entailed:
#0 - 0xble
2022-09-26T01:19:25Z
Unhelpful bot response