Platform: Code4rena
Start Date: 28/10/2022
Pot Size: $165,500 USDC
Total HM: 2
Participants: 24
Period: 12 days
Judge: GalloDaSballo
Total Solo HM: 1
Id: 177
League: ETH
Rank: 20/24
Findings: 1
Award: $229.76
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0x1f8b
Also found by: Aymen0909, HardlyCodeMan, IllIllI, ReyAdmirado, Rolezn, TomJ, c3phas, gogo, mcwildy
229.7602 USDC - $229.76
Issue | Instances | |
---|---|---|
2 | Variables inside struct should be packed to save gas | 1 |
2 | x += y/x -= y costs more gas than x = x + y/x = x - y for state variables | 1 |
5 | Splitting require() statements that uses && saves gas | 22 |
4 | ++i/i++ should be unchecked{++i} /unchecked{i++} when it is not possible for them to overflow, as in the case when used in for & while loops | 4 |
struct
should be packed to save gas :As the solidity EVM works with 32 bytes, variables less than 32 bytes should be packed inside a struct so that they can be stored in the same slot, each slot saved can avoid an extra Gsset (20000 gas) for the first setting of the struct. Subsequent reads as well as writes have smaller gas savings.
There is 1 instance of this issue:
File: ethereum/contracts/zksync/Storage.sol Line 17-25
struct DiamondCutStorage { bytes32 proposedDiamondCutHash; uint256 proposedDiamondCutTimestamp; uint256 lastDiamondFreezeTimestamp; uint256 currentProposalId; mapping(address => bool) securityCouncilMembers; mapping(address => uint256) securityCouncilMemberLastApprovedProposalId; uint256 securityCouncilEmergencyApprovals; }
As the variables proposedDiamondCutTimestam
, lastDiamondFreezeTimestamp
, currentProposalId
and securityCouncilEmergencyApprovals
can't really overflow 2^128, their values should be packed to save gas, the struct should be modified as follow :
struct DiamondCutStorage { bytes32 proposedDiamondCutHash; mapping(address => bool) securityCouncilMembers; mapping(address => uint256) securityCouncilMemberLastApprovedProposalId; uint128 proposedDiamondCutTimestamp; uint128 lastDiamondFreezeTimestamp; uint128 currentProposalId; uint128 securityCouncilEmergencyApprovals; }
x += y/x -= y
costs more gas than x = x + y/x = x - y
for state variables :Using the addition operator instead of plus-equals saves 113 gas as explained here
There is 1 instance of this issue:
File: ethereum/contracts/zksync/facets/DiamondCut.sol Line 29
s.diamondCutStorage.currentProposalId += 1;
require()
statements that uses && saves gas :There are 2 instances of this issue :
File: ethereum/contracts/common/AllowList.sol 96 require( callersLength == _targets.length && callersLength == _functionSigs.length && callersLength == _enables.length, "yw" ); File: ethereum/contracts/common/L2ContractHelper.sol 65 require(version == 1 && _bytecodeHash[1] == bytes1(0), "zf");
++i/i++
should be unchecked{++i}/unchecked{i++}
when it is not possible for them to overflow, as in the case when used in for & while loops :There are 4 instances of this issue:
File: ethereum/contracts/zksync/libraries/Diamond.sol 94 for (uint256 i = 0; i < facetCutsLength; ++i) 132 for (uint256 i = 0; i < selectorsLength; ++i) 153 for (uint256 i = 0; i < selectorsLength; ++i) 173 for (uint256 i = 0; i < selectorsLength; ++i)
#0 - GalloDaSballo
2022-11-24T22:04:50Z
Will award 4k gas as it will roughly save 2 SLOADs and cost a little extra
34 from my benchmarks
50 gas each - 200
4234
#1 - c4-judge
2022-12-03T19:02:42Z
GalloDaSballo marked the issue as grade-b