Platform: Code4rena
Start Date: 03/07/2023
Pot Size: $100,000 USDC
Total HM: 4
Participants: 36
Period: 10 days
Judge: gzeon
Total Solo HM: 3
Id: 257
League: ETH
Rank: 34/36
Findings: 1
Award: $55.30
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: c3phas
Also found by: 0xAnah, Aymen0909, JCN, K42, MohammedRizwan, Raihan, SAQ, SM3_SS, dharma09, flutter_developer, hunter_w3b, klau5, naman1778, petrichor
55.3038 USDC - $55.30
no | Issue | Instances | |
---|---|---|---|
[G-01] | Using fixed bytes is cheaper than using string | 3 | - |
[G-02] | Expressions for constant values such as a call to keccak256(), should use immutable rather than constant | 8 | - |
[G-03] | State variables should be cached in stack variables rather than re-reading them from storage | 4 | - |
[G-04] | Pre-increments and pre-decrements are cheaper than post-increments and post-decrements | 10 | - |
[G-05] | Not using the named return variable when a function returns, wastes deployment gas | 1 | - |
[G-06] | Can make the variable outside the loop to save gas | 3 | - |
[G-07] | Using calldata instead of memory for read-only arguments in external functions saves gas | 3 | - |
[G-08] | Should use arguments instead of state variable | 3 | - |
[G-09] | Before transfer of some functions, we should check some variables for possible gas save | 7 | - |
[G-10] | State Variable can be packed into fewer storage slots | 1 | - |
[G-11] | Bytes constants are more efficient than String constants | 5 | - |
[G-12] | Avoid Storage keyword during modifiers | 1 | - |
[G-13] | Don't initialize variables with default value | 9 | - |
[G-14] | State varaibles only set in the Constructor should be declared Immutable | 2 | - |
[G-15] | With assembly, .call (bool success) transfer can be done gas-optimized | 3 | - |
[G-16] | Use constants instead of type(uintx).max | 5 | - |
[G-17] | Use nested if and, avoid multiple check combinations | 5 | - |
[G-18] | Caching global variables is more expensive than using the actual variable (use msg.sender instead of caching it) | 4 | - |
[G-19] | Use selfbalance() instead of address(this).balance | 4 | - |
[G-20] | >= costs less gas than > | 3 | - |
[G-21] | Use hardcode address instead of address(this) | 10 | - |
[G-22] | Use assembly for math (add, sub, mul, div) | 8 | - |
[G-23] | Do not calculate constant | 5 | - |
[G-24] | Use != 0 instead of > 0 for unsigned integer comparison | 5 | - |
[G-25] | Non efficient zero initialization | 30 | - |
[G-26] | Sort Solidity operations using short-circuit mode | 1 | - |
[G-27] | internal functions not called by the contract should be removed to save deployment gas | 4 | - |
[G-28] | Use Mappings Instead of Arrays | 1 | - |
As a rule of thumb, use bytes for arbitrary-length raw byte data and string for arbitrary-length string (UTF-8) data. If you can limit the length to a certain number of bytes, always use one of bytes1 to bytes32 because they are much cheaper.
file: contracts/governance/NounsDAOLogicV2.sol 59 string public constant name = 'Nouns DAO';
File: contracts/governance/NounsDAOV3Votes.sol 44 string public constant name = 'Nouns DAO';
file: contracts/governance/fork/newdao/governance/NounsDAOLogicV1Fork.sol 116 string public constant name = 'Nouns DAO';
While it doesn't save any gas because the compiler knows that developers often make this mistake, it's still best to use theright tool for the task at hand. There is a difference between constant variables and immutable variables, and they shouldeach be used in their appropriate contexts. constants should be used for literal values written into the code, and immutablevariables should be used for expressions, or values calculated in, or passed into the constructor.
file: contracts/governance/NounsDAOLogicV2.sol 107 bytes32 public constant DOMAIN_TYPEHASH = 108 keccak256('EIP712Domain(string name,uint256 chainId,address verifyingContract)'); 111 bytes32 public constant BALLOT_TYPEHASH = keccak256('Ballot(uint256 proposalId,uint8 support)');
file: contracts/governance/NounsDAOV3Proposals.sol 141 bytes32 public constant DOMAIN_TYPEHASH = 142 keccak256('EIP712Domain(string name,uint256 chainId,address verifyingContract)'); 144 bytes32 public constant PROPOSAL_TYPEHASH = 145 keccak256( 146 'Proposal(address proposer,address[] targets,uint256[] values,string[] signatures,bytes[] calldatas,string description,uint256 expiry)' 149 bytes32 public constant UPDATE_PROPOSAL_TYPEHASH = 150 keccak256( 151 'UpdateProposal(uint256 proposalId,address proposer,address[] targets,uint256[] values,string[] signatures,bytes[] calldatas,string description,uint256 expiry)'
file: contracts/governance/NounsDAOV3Votes.sol 47 bytes32 public constant DOMAIN_TYPEHASH = 48 keccak256('EIP712Domain(string name,uint256 chainId,address verifyingContract)');
file: contracts/governance/fork/newdao/token/base/ERC721CheckpointableUpgradeable.sol 70 bytes32 public constant DOMAIN_TYPEHASH = 71 keccak256('EIP712Domain(string name,uint256 chainId,address verifyingContract)'); 74 bytes32 public constant DELEGATION_TYPEHASH = 75 keccak256('Delegation(address delegatee,uint256 nonce,uint256 expiry)');
The instances below point to the second+ access of a state variable within a function. Caching of a state variable replace each Gwarmaccess (100 gas) with a much cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses. Most of the times this if statement will be true and we will save 100 gas at a small possibility of 3 gas loss
file: contracts/governance/NounsDAOExecutor.sol#L152 ///@audit the ' queuedTransactions ' is state variable , its access second+ in one function. 152 require(queuedTransactions[txHash], "NounsDAOExecutor::executeTransaction: Transaction hasn't been queued."); 162 queuedTransactions[txHash] = false;
file: contracts/governance/fork/newdao/NounsAuctionHouseFork.sol ///@audit the ' auction ' is state variable , its access second+ in one function. 137 auction.amount = msg.value; 138 auction.bidder = payable(msg.sender); 143 auction.endTime = _auction.endTime = block.timestamp + timeBuffer; ///@audit the ' timeBuffer ' is state variable , its access second+ in one function. 141 bool extended = _auction.endTime - block.timestamp < timeBuffer; 143 auction.endTime = _auction.endTime = block.timestamp + timeBuffer; ///@audit the ' nouns ' is state variable , its access second+ in one function. 146 nouns.burn(_auction.nounId); 248 nouns.transferFrom(address(this), _auction.bidder, _auction.nounId); ///@audit the ' weth ' is state variable , its access second+ in one function. 263 IWETH(weth).deposit{ value: amount }(); 264 IERC20(weth).transfer(to, amount);
Saves 5 gas per iteration
file: contracts/governance/fork/NounsDAOForkEscrow.sol 105 numTokensInEscrow++; 138 forkId++;
file: contracts/governance/NounsDAOLogicV2.sol 239 proposalCount++;
file: contracts/governance/NounsDAOV3Proposals.sol 837 signers[numSigners++] = signer;
file: script/ProposeDAOV3UpgradeMainnet.s.sol 82 i++; 88 i++; 100 i++; 106 i++;
file: contracts/governance/fork/newdao/token/NounsTokenFork.sol 207 return _mintTo(minter, _currentNounId++);
file: contracts/governance/fork/newdao/token/base/ERC721CheckpointableUpgradeable.sol 153 require(nonce == nonces[signatory]++, 'ERC721Checkpointable::delegateBySig: invalid nonce');
file: script/DeployDAOV3NewContractsBase.s.sol 105 return timelockV2;
Consider making the stack variables before the loop which gonna save gas
file: contracts/governance/fork/NounsDAOV3Fork.sol 254 uint256 tokensToSend = (erc20token.balanceOf(address(timelock)) * tokenCount) / totalSupply;
file: contracts/governance/fork/newdao/token/NounsTokenFork.sol 150 uint256 nounId = tokenIds[i]; 173 uint256 nounId = tokenIds[i];
When a function with a memory array is called externally, the abi.decode () step has to use a for-loop to copy each index of the calldata to the memory index. Each iteration of this for-loop costs at least 60 gas (i.e. 60 * <mem_array>.length). Using calldata directly, obliviates the need for such a loop in the contract code and runtime execution.
file: contracts/governance/fork/newdao/token/NounsTokenFork.sol 198 function setContractURIHash(string memory newContractURIHash) external onlyOwner {
file: contracts/governance/fork/newdao/governance/NounsDAOLogicV1Fork.sol 206 function quit(uint256[] calldata tokenIds, address[] memory erc20TokensToInclude) external nonReentrant {
file: script/ProposeDAOV3UpgradeMainnet.s.sol 33 address[] memory erc20TokensToIncludeInFork = new address[](1);
state variables should not used in emit , This will save near 97 gas
file: contracts/governance/NounsDAOExecutor.sol ///@audit ' delay ' is state variable. 86 emit NewDelay(delay); ///@audit ' admin' is state variable. 94 emit NewAdmin(admin); ///@audit ' pendingAdmin' is state variable. 104 emit NewPendingAdmin(pendingAdmin);
Before transfer, we should check for amount being 0 so the function doesn't run when its not gonna do anything:
file: contracts/utils/ERC20Transferer.sol 34 IERC20(token).transferFrom(msg.sender, to, balance);
file: contracts/governance/fork/NounsDAOForkEscrow.sol 120 nounsToken.transferFrom(address(this), owner, tokenIds[i]); 151 nounsToken.transferFrom(address(this), to, tokenIds[i]);
file: contracts/governance/fork/NounsDAOV3Fork.sol 84 ds.nouns.safeTransferFrom(msg.sender, address(forkEscrow), tokenIds[i]); 154 ds.nouns.transferFrom(msg.sender, timelock, tokenIds[i]);
file: contracts/governance/fork/newdao/governance/NounsDAOLogicV1Fork.sol 224 nouns.transferFrom(msg.sender, address(timelock), tokenIds[i]);
file: contracts/governance/NounsDAOExecutorV2.sol 228 IERC20(erc20Token).safeTransfer(recipient, tokensToSend);
The EVM works with 32 byte words. Variables less than 32 bytes can be declared next to eachother in storage and this will pack the values together into a single 32 byte storage slot (if the values combined are <= 32 bytes). If the variables packed together are retrieved together in functions we will effectively save ~2000 gas with every subsequent SLOAD for that storage slot. This is due to us incurring a Gwarmaccess (100 gas) versus a Gcoldsload (2100 gas)
file: contracts/governance/fork/newdao/token/NounsTokenFork.sol 61 uint32 public forkId; 62 63 /// @notice How many tokens are still available to be claimed by Nouners who put their original Nouns in escrow 64 uint256 public remainingTokensToClaim; 65 66 /// @notice The forking period expiration timestamp, after which new tokens cannot be claimed by the original DAO 67 uint256 public forkingPeriodEndTimestamp; 68 69 /// @notice Whether the minter can be updated 70 bool public isMinterLocked; 71 72 /// @notice Whether the descriptor can be updated 73 bool public isDescriptorLocked; 74 75 /// @notice Whether the seeder can be updated 76 bool public isSeederLocked; 77 78 /// @notice The noun seeds 79 mapping(uint256 => INounsSeeder.Seed) public seeds; 80 81 /// @notice The internal noun ID tracker 82 uint256 private _currentNounId; 83 84 /// @notice IPFS content hash of contract-level metadata 85 string private _contractURIHash = 'QmZi1n79FqWt2tTLwCqiy6nLM6xLGRsEPQ5JmReJQKNNzX';
Sort Plcae of Variables.
/// @notice How many tokens are still available to be claimed by Nouners who put their original Nouns in escrow uint256 public remainingTokensToClaim; /// @notice The forking period expiration timestamp, after which new tokens cannot be claimed by the original DAO uint256 public forkingPeriodEndTimestamp; /// @notice The internal noun ID tracker uint256 private _currentNounId; /// @notice The noun seeds mapping(uint256 => INounsSeeder.Seed) public seeds; /// @notice IPFS content hash of contract-level metadata string private _contractURIHash = 'QmZi1n79FqWt2tTLwCqiy6nLM6xLGRsEPQ5JmReJQKNNzX'; uint32 public forkId; /// @notice Whether the minter can be updated bool public isMinterLocked; /// @notice Whether the descriptor can be updated bool public isDescriptorLocked; /// @notice Whether the seeder can be updated bool public isSeederLocked;
If data can fit into 32 bytes, then you should use bytes32 datatype rather than bytes or strings as it is cheaper in solidity.
file: contracts/governance/NounsDAOLogicV2.sol 59 string public constant name = 'Nouns DAO';
file: contracts/governance/NounsDAOV3Votes.sol 44 string public constant name = 'Nouns DAO';
file: contracts/governance/fork/newdao/NounsAuctionHouseFork.sol 48 string public constant NAME = 'NounsAuctionHouseFork';
file: contracts/governance/fork/newdao/token/NounsTokenFork.sol 46 string public constant NAME = 'NounsTokenFork';
file: contracts/governance/fork/newdao/governance/NounsDAOLogicV1Fork.sol 116 string public constant name = 'Nouns DAO';
The problem with using modifiers with storage variables is that these accesses will likely have to be obtained multiple times, to pass it to the modifier, and to read it into the method code.
file: contracts/governance/NounsDAOV3Admin.sol 150 modifier onlyAdmin(NounsDAOStorageV3.StorageV3 storage ds) {
file: contracts/governance/NounsDAOV3DynamicQuorum.sol 107 uint256 lower = 0;
file: contracts/governance/NounsDAOV3Votes.sol 224 bool isForVoteInLastMinuteWindow = false; 229 bool isDefeatedBefore = false;
file: script/ProposeDAOV3UpgradeMainnet.s.sol 75 uint256 i = 0; 84 values[i] = 0; 90 values[i] = 0; 102 values[i] = 0;
file: contracts/governance/fork/newdao/token/base/ERC721CheckpointableUpgradeable.sol 52 uint8 public constant decimals = 0; 193 uint32 lower = 0;
Avoids a Gsset (20000 gas) in the constructor, and replaces the first access in each transaction (Gcoldsload - 2100 gas) and each access thereafter (Gwarmacces - 100 gas) with a PUSH32 (3 gas).
While strings are not value types, and therefore cannot be immutable/constant if not hard-coded outside of the constructor, the same behavior can be achieved by making the current contract abstract with virtual functions for the string accessors, and having a child contract override the functions with the hard-coded implementation-specific values.
file: contracts/governance/NounsDAOExecutor.sol ///@audit admin and delay are state variabls 76 admin = admin_; 77 delay = delay_;
return data (bool success,) has to be stored due to EVM architecture, but in a usage like below, ‘out’ and ‘outsize’ values are given (0,0), this storage disappears and gas optimization is provided.
file: contracts/governance/fork/newdao/NounsAuctionHouseFork.sol 273 (bool success, ) = to.call{ value: value, gas: 30_000 }(new bytes(0));
file: contracts/governance/NounsDAOExecutor.sol 173 (bool success, bytes memory returnData) = target.call{ value: value }(callData);
file: contracts/governance/NounsDAOExecutorV2.sol 196 (bool success, bytes memory returnData) = target.call{ value: value }(callData);
type(uint120).max or type(uint128).max, etc. it uses more gas in the distribution process and also for each transaction than constant usage.
file: contracts/governance/NounsDAOLogicV2.sol 1079 require(n <= type(uint32).max, errorMessage); 1084 if (n > type(uint16).max) {
file: contracts/governance/NounsDAOV3Admin.sol 595 require(n <= type(uint32).max, errorMessage);
file: contracts/governance/NounsDAOV3DynamicQuorum.sol 146 require(n <= type(uint32).max, errorMessage); 151 if (n > type(uint16).max) {
Using nested if is cheaper than using && multiple check combinations. There are more advantages, such as easier to read code and better coverage reports.
file: contracts/governance/NounsDAOV3Votes.sol 240 if ( 241 // only for votes can trigger an objection period 242 // we're in the last minute window 243 isForVoteInLastMinuteWindow && 244 // first part of the vote flip check 245 // separated from the second part to optimize gas 246 isDefeatedBefore && 247 // haven't turn on objection yet 248 proposal.objectionPeriodEndBlock == 0 && 249 // second part of the vote flip check 250 !ds.isDefeated(proposal) 251 ) {
file: contracts/governance/NounsDAOLogicV2.sol 1026 if (pos > 0 && quorumParamsCheckpoints[pos - 1].fromBlock == blockNumber) {
file: contracts/governance/NounsDAOV3Admin.sol 585 if (pos > 0 && ds.quorumParamsCheckpoints[pos - 1].fromBlock == blockNumber) {
file: contracts/governance/fork/newdao/token/base/ERC721CheckpointableUpgradeable.sol 255 if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
file: contracts/governance/fork/newdao/governance/NounsDAOLogicV1Fork.sol 381 if (block.timestamp < delayedGovernanceExpirationTimestamp && nouns.remainingTokensToClaim() > 0) {
file: contracts/governance/NounsDAOExecutor.sol 91 admin = msg.sender;
file: contracts/governance/NounsDAOExecutorV2.sol 114 admin = msg.sender;
file: contracts/governance/NounsDAOProxy.sol 53 admin = msg.sender;
file: contracts/governance/fork/newdao/token/base/ERC721CheckpointableUpgradeable.sol 124 if (delegatee == address(0)) delegatee = msg.sender;
file: contracts/governance/NounsDAOLogicV2.sol 823 uint256 amount = address(this).balance; 1035 uint256 balance = address(this).balance;
file: contracts/governance/NounsDAOV3Admin.sol 469 uint256 amount = address(this).balance;
file: contracts/governance/NounsDAOV3Votes.sol 297 uint256 balance = address(this).balance;
The compiler uses opcodes GT and ISZERO for solidity code that uses >, but only requires LT for >=, which saves 3 gas \
Reference: https://gist.github.com/IllIllI000/3dc79d25acccfa16dee4e83ffdc6ffde
file: contracts/governance/NounsDAOV3Admin.sol 484 if (oldVoteSnapshotBlockSwitchProposalId > 0) {
file: contracts/governance/NounsDAOV3Proposals.sol 888 if (proposal.signers.length > 0) revert ProposerCannotUpdateProposalWithSigners();
file: contracts/governance/NounsDAOV3Votes.sol 132 if (votes > 0) {
Instead of using address(this), it is more gas-efficient to pre-calculate and use the hardcoded address. Foundry’s script.sol and solmate’s LibRlp.sol contracts can help achieve this. References: https://book.getfoundry.sh/reference/forge-std/compute-create-address
if the contract's address is needed in the code, it's more gas-efficient to hardcode the address as a constant rather than using the address(this) expression. This is because using address(this) requires additional gas consumption to compute the contract's address at runtime.
Here's an example :
contract MyContract { address constant public CONTRACT_ADDRESS = 0x1234567890123456789012345678901234567890; function getContractAddress() public view returns (address) { return CONTRACT_ADDRESS; } }
file: contracts/governance/NounsDAOExecutor.sol 99 msg.sender == address(this),
file: contracts/governance/NounsDAOExecutorV2.sol 104 require(msg.sender == address(this), 'NounsDAOExecutor::setDelay: Call must come from NounsDAOExecutor.');
file: contracts/governance/NounsDAOLogicV2.sol 595 abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainIdInternal(), address(this)) 823 uint256 amount = address(this).balance; 1035 uint256 balance = address(this).balance;
file: contracts/governance/NounsDAOV3Proposals.sol 985 bytes32 digest = sigDigest(typehash, proposalEncodeData, proposerSignature.expirationTimestamp, address(this));
file: contracts/governance/NounsDAOV3Votes.sol 165 abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), block.chainid, address(this))
file: contracts/governance/fork/NounsDAOForkEscrow.sol 120 nounsToken.transferFrom(address(this), owner, tokenIds[i]); 151 nounsToken.transferFrom(address(this), to, tokenIds[i]); 165 return nounsToken.balanceOf(address(this)) - numTokensInEscrow;
Use assembly for math instead of Solidity. You can check for overflow/underflow in assembly to ensure safety. If using Solidity versions < 0.8.0 and you are using Safemath, you can gain significant gas savings by using assembly to calculate values and checking for overflow/underflow
file: contracts/governance/fork/newdao/token/base/ERC721CheckpointableUpgradeable.sol 280 uint96 c = a + b; 291 return a - b;
file: contracts/governance/NounsDAOLogicV2.sol 1010 uint256 center = upper - (upper - lower) / 2; 1067 return (number * bps) / 10000;
file: contracts/governance/NounsDAOV3Admin.sol 488 uint256 newVoteSnapshotBlockSwitchProposalId = ds.proposalCount + 1;
file: contracts/governance/NounsDAOV3DynamicQuorum.sol 63 uint256 againstVotesBPS = (10000 * againstVotes) / totalSupply; 64 uint256 quorumAdjustmentBPS = (params.quorumCoefficient * againstVotesBPS) / 1e6;
file: contracts/governance/fork/newdao/NounsAuctionHouseFork.sol 215 uint256 endTime = startTime + duration;
When you define a constant in Solidity, the compiler can calculate its value at compile-time and replace all references to the constant with its computed value. This can be helpful for readability and reducing the size of the compiled code, but it can also increase gas usage at runtime.
file: contracts/governance/NounsDAOV3Admin.sol 118 uint256 public constant MIN_VOTING_PERIOD_BLOCKS = 1 days / 12; 121 uint256 public constant MAX_VOTING_PERIOD_BLOCKS = 2 weeks / 12; 127 uint256 public constant MAX_VOTING_DELAY_BLOCKS = 2 weeks / 12; 145 uint256 public constant MAX_OBJECTION_PERIOD_BLOCKS = 7 days / 12; 148 uint256 public constant MAX_UPDATABLE_PERIOD_BLOCKS = 7 days / 12;
it's generally more gas-efficient to use != 0 instead of > 0 when comparing unsigned integer types.
This is because the Solidity compiler can optimize the != 0 comparison to a simple bitwise operation, while the > 0 comparison requires an additional subtraction operation. As a result, using != 0 can be more gas-efficient and can help to reduce the overall cost of your contract.
Here's an example of how you can use != 0 instead of > 0:
contract MyContract { uint256 public myUnsignedInteger; function myFunction() public view returns (bool) { // Use != 0 instead of > 0 return myUnsignedInteger != 0; } }
file: contracts/governance/NounsDAOV3Admin.sol 585 if (pos > 0 && ds.quorumParamsCheckpoints[pos - 1].fromBlock == blockNumber) {
file: contracts/governance/fork/newdao/token/base/ERC721CheckpointableUpgradeable.sol 165 return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; 230 uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0; 237 uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0; 255 if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
Solidity does not recognize null as a value, so uint variables are initialized to zero. Setting a uint variable to zero is redundant and can waste gas.
file: contracts/governance/NounsDAOLogicV2.sol 305 for (uint256 i = 0; i < proposal.targets.length; i++) { 343 for (uint256 i = 0; i < proposal.targets.length; i++) { 372 for (uint256 i = 0; i < proposal.targets.length; i++) { 405 for (uint256 i = 0; i < proposal.targets.length; i++) {
file: contracts/governance/NounsDAOV3Admin.sol 602 for (uint256 i = 0; i < erc20tokens.length - 1; i++) {
file: contracts/governance/NounsDAOV3Proposals.sol 409 for (uint256 i = 0; i < proposerSignatures.length; ++i) { 446 for (uint256 i = 0; i < proposal.targets.length; i++) { 508 for (uint256 i = 0; i < proposal.targets.length; i++) { 553 for (uint256 i = 0; i < proposal.targets.length; i++) { 590 for (uint256 i = 0; i < signers.length; ++i) { 602 for (uint256 i = 0; i < proposal.targets.length; i++) { 826 for (uint256 i = 0; i < proposerSignatures.length; ++i) { 860 for (uint256 i = 0; i < txs.signatures.length; ++i) { 865 for (uint256 i = 0; i < txs.calldatas.length; ++i) {
file: contracts/governance/fork/NounsDAOForkEscrow.sol 117 for (uint256 i = 0; i < tokenIds.length; i++) { 148 for (uint256 i = 0; i < tokenIds.length; i++) {
file: contracts/governance/fork/NounsDAOV3Fork.sol 83 for (uint256 i = 0; i < tokenIds.length; i++) { 153 for (uint256 i = 0; i < tokenIds.length; i++) { 252 for (uint256 i = 0; i < erc20Count; ++i) {
file: contracts/governance/fork/newdao/token/NounsTokenFork.sol 149 for (uint256 i = 0; i < tokenIds.length; i++) { 172 for (uint256 i = 0; i < tokenIds.length; i++) {
file: contracts/governance/fork/newdao/governance/NounsDAOLogicV1Fork.sol 209 for (uint256 i = 0; i < erc20TokensToInclude.length; i++) { 223 for (uint256 i = 0; i < tokenIds.length; i++) { 231 for (uint256 i = 0; i < erc20TokensToInclude.length; i++) { 238 for (uint256 i = 0; i < erc20TokensToInclude.length; i++) { 248 for (uint256 i = 0; i < addresses.length; i++) { 397 for (uint256 i = 0; i < proposal.targets.length; i++) { 435 for (uint256 i = 0; i < proposal.targets.length; i++) { 452 for (uint256 i = 0; i < proposal.targets.length; i++) { 796 for (uint256 i = 0; i < erc20tokens.length - 1; i++) {
Short-circuiting is a solidity contract development model that uses OR/AND logic to sequence different cost operations.
file: contracts/governance/fork/newdao/NounsAuctionHouseFork.sol 171 if (auction.startTime == 0 || auction.settled) {
file: packages/nouns-contracts/contracts/governance/NounsDAOExecutorV2.sol 243 function _authorizeUpgrade(address) internal view override {
file: packages/nouns-contracts/contracts/governance/fork/newdao/NounsAuctionHouseFork.sol 281 function _authorizeUpgrade(address) internal view override onlyOwner {}
file: contracts/governance/fork/newdao/governance/NounsDAOLogicV1Fork.sol 789 function _authorizeUpgrade(address) internal view override {
file: contracts/governance/fork/newdao/token/NounsTokenFork.sol 327 function _authorizeUpgrade(address) internal view override onlyOwner {}
file: contracts/governance/fork/newdao/governance/NounsDAOStorageV1Fork.sol 56 address[] public erc20TokensToIncludeInQuit;
#0 - c4-judge
2023-07-25T10:19:07Z
gzeon-c4 marked the issue as grade-b