Issue | Instances | |
---|---|---|
[GAS-1] | Cache array length outside of loop | 1 |
[GAS-2] | Use != 0 instead of > 0 for unsigned integer comparison | 5 |
[GAS-3] | Don't initialize variables with default value | 14 |
[GAS-4] | Use shift Right/Left instead of division/multiplication if possible | 3 |
[GAS-5] | Using bools for storage incurs overhead | 6 |
[GAS-6] | Use Custom Errors | 93 |
If not cached, the solidity compiler will always read the length of the array during each iteration. That is, if it is a storage array, this is an extra sload operation (100 additional extra gas for each iteration except for the first) and if it is a memory array, this is an extra mload operation (3 additional gas for each iteration except for the first).
Instances (1):
File: ethereum/contracts/zksync/facets/Executor.sol
111: for (uint256 i = 0; i < emittedL2Logs.length; i = i.uncheckedAdd(L2_TO_L1_LOG_SERIALIZE_SIZE)) {
Instances (5):
File: ethereum/contracts/bridge/L1ERC20Bridge.sol
117: require(amount > 0, "1T"); // empty deposit amount
210: require(amount > 0, "y1");
File: ethereum/contracts/zksync/facets/DiamondCut.sol
16: assert(SECURITY_COUNCIL_APPROVALS_FOR_EMERGENCY_UPGRADE > 0);
File: ethereum/contracts/zksync/libraries/Diamond.sol
100: require(selectors.length > 0, "B"); // no functions for diamond cut
File: ethereum/contracts/zksync/libraries/Merkle.sol
23: require(pathLength > 0, "xc");
Instances (14):
File: ethereum/contracts/common/AllowList.sol
69: for (uint256 i = 0; i < targetsLength; i = i.uncheckedInc()) {
103: for (uint256 i = 0; i < callersLength; i = i.uncheckedInc()) {
File: ethereum/contracts/zksync/facets/Executor.sol
111: for (uint256 i = 0; i < emittedL2Logs.length; i = i.uncheckedAdd(L2_TO_L1_LOG_SERIALIZE_SIZE)) {
162: for (uint256 i = 0; i < blocksLength; i = i.uncheckedInc()) {
180: for (uint256 i = 0; i < _nPriorityOps; i = i.uncheckedInc()) {
210: for (uint256 i = 0; i < nBlocks; i = i.uncheckedInc()) {
240: for (uint256 i = 0; i < committedBlocksLength; i = i.uncheckedInc()) {
File: ethereum/contracts/zksync/facets/Getters.sol
163: for (uint256 i = 0; i < facetsLen; i = i.uncheckedInc()) {
File: ethereum/contracts/zksync/facets/Mailbox.sol
223: for (uint256 i = 0; i < factoryDepsLen; i = i.uncheckedInc()) {
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) {
File: ethereum/contracts/zksync/libraries/Merkle.sol
28: for (uint256 i = 0; i < pathLength; i = i.uncheckedInc()) {
Instances (3):
File: zksync/contracts/bridge/L2ERC20Bridge.sol
12: import "./L2StandardERC20.sol";
13: import {L2ContractHelper} from "../L2ContractHelper.sol";
File: zksync/contracts/bridge/L2ETHBridge.sol
5: import {L2ContractHelper} from "../L2ContractHelper.sol";
Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas), and to avoid Gsset (20000 gas) when changing from ‘false’ to ‘true’, after having been ‘true’ in the past. See source.
Instances (6):
File: ethereum/contracts/bridge/L1ERC20Bridge.sol
40: mapping(uint256 => mapping(uint256 => bool)) public isWithdrawalFinalized;
File: ethereum/contracts/bridge/L1EthBridge.sol
37: mapping(uint256 => mapping(uint256 => bool)) public isWithdrawalFinalized;
File: ethereum/contracts/common/AllowList.sol
26: mapping(address => bool) public isAccessPublic;
30: mapping(address => mapping(address => mapping(bytes4 => bool))) public hasSpecialAccessToCall;
File: ethereum/contracts/zksync/Storage.sol
22: mapping(address => bool) securityCouncilMembers;
77: mapping(address => bool) validators;
Source Instead of using error strings, to reduce deployment and runtime cost, you should use Custom Errors. This would save both deployment and runtime cost.
Instances (93):
File: ethereum/contracts/bridge/L1ERC20Bridge.sol
77: require(_factoryDeps.length == 2, "mk");
117: require(amount > 0, "1T"); // empty deposit amount
207: require(success, "yn");
210: require(amount > 0, "y1");
232: require(!isWithdrawalFinalized[_l2BlockNumber][_l2MessageIndex], "pw");
249: require(success, "nq");
271: require(_l2ToL1message.length == 76, "kk");
274: require(bytes4(functionSignature) == this.finalizeWithdrawal.selector, "nt");
File: ethereum/contracts/bridge/L1EthBridge.sol
93: require(_l1Token == CONVENTIONAL_ETH_ADDRESS, "bx");
141: require(_l1Token == CONVENTIONAL_ETH_ADDRESS, "sj");
166: require(success, "ju");
189: require(!isWithdrawalFinalized[_l2BlockNumber][_l2MessageIndex], "jj");
205: require(success, "rj");
File: ethereum/contracts/common/AllowList.sol
33: require(_owner != address(0), "kq");
38: require(msg.sender == owner, "kx");
67: require(targetsLength == _enables.length, "yg"); // The size of arrays should be equal
155: require(msg.sender == newOwner, "n0"); // Only proposed by current owner address can claim the owner rights
File: ethereum/contracts/common/AllowListed.sol
15: require(_allowList.canCall(msg.sender, address(this), functionSig), "nr");
File: ethereum/contracts/common/L2ContractHelper.sol
50: require(_bytecode.length % 32 == 0, "po");
53: require(bytecodeLenInWords < 2**16, "pp"); // bytecode length must be less than 2^16 words
54: require(bytecodeLenInWords % 2 == 1, "pr"); // bytecode length in words must be odd
65: require(version == 1 && _bytecodeHash[1] == bytes1(0), "zf"); // Incorrectly formatted bytecodeHash
67: require(bytecodeLen(_bytecodeHash) % 2 == 1, "uy"); // Code length in words must be odd
File: ethereum/contracts/common/ReentrancyGuard.sol
55: require(lockSlotOldValue == 0, "1B");
72: require(_status == _NOT_ENTERED, "r1");
File: ethereum/contracts/zksync/DiamondProxy.sol
13: require(_chainId == block.chainid, "pr");
24: require(msg.data.length >= 4 || msg.data.length == 0, "Ut");
29: require(facetAddress != address(0), "F"); // Proxy has no facet for this selector
30: require(!diamondStorage.isFrozen || !facet.isFreezable, "q1"); // Facet is frozen
File: ethereum/contracts/zksync/facets/Base.sol
16: require(msg.sender == s.governor, "1g"); // only by governor
22: require(s.validators[msg.sender], "1h"); // validator is not active
File: ethereum/contracts/zksync/facets/DiamondCut.sol
23: require(s.diamondCutStorage.proposedDiamondCutTimestamp == 0, "a3"); // proposal already exists
40: require(_resetProposal(), "g1"); // failed cancel diamond cut
55: require(approvedBySecurityCouncil || upgradeNoticePeriodPassed, "a6"); // notice period should expire
56: require(approvedBySecurityCouncil || !diamondStorage.isFrozen, "f3");
65: require(_resetProposal(), "a5"); // failed reset proposal
80: require(!diamondStorage.isFrozen, "a9"); // diamond proxy is frozen already
94: require(diamondStorage.isFrozen, "a7"); // diamond proxy is not frozen
106: require(s.diamondCutStorage.securityCouncilMembers[msg.sender], "a9"); // not a security council member
108: require(s.diamondCutStorage.securityCouncilMemberLastApprovedProposalId[msg.sender] < currentProposalId, "ao"); // already approved this proposal
111: require(s.diamondCutStorage.proposedDiamondCutTimestamp != 0, "f0"); // there is no proposed diamond cut
112: require(s.diamondCutStorage.proposedDiamondCutHash == _diamondCutHash, "f1"); // proposed diamond cut do not match to the approved
File: ethereum/contracts/zksync/facets/Executor.sol
28: require(_newBlock.blockNumber == _previousBlock.blockNumber + 1, "f"); // only commit next block
39: require(_previousBlock.blockHash == previousBlockHash, "l");
41: require(expectedPriorityOperationsHash == _newBlock.priorityOperationsHash, "t");
52: require(timestampNotTooSmall, "h"); // New block timestamp is too small
53: require(timestampNotTooBig, "h1"); // New block timestamp is too big
117: require(keccak256(l2Messages[currentMessage]) == hashedMessage, "k2");
129: require(!isSystemContextLogProcessed, "fx");
136: require(bytecodeHash == L2ContractHelper.hashL2Bytecode(factoryDeps[currentBytecode]), "k3");
142: require(currentBytecode == factoryDeps.length, "ym");
143: require(currentMessage == l2Messages.length, "pl");
145: require(isSystemContextLogProcessed, "by");
159: require(s.storedBlockHashes[s.totalBlocksCommitted] == _hashStoredBlockInfo(_lastCommittedBlockData), "i"); // incorrect previous block data
192: require(currentBlockNumber == s.totalBlocksExecuted + _executedBlockIdx + 1, "k"); // Execute blocks in order
199: require(priorityOperationsHash == _storedBlock.priorityOperationsHash, "x"); // priority operations hash does not match to expected
216: require(s.totalBlocksExecuted <= s.totalBlocksVerified, "n"); // Can't execute blocks more then committed and proven currently.
237: require(_hashStoredBlockInfo(_prevBlock) == s.storedBlockHashes[currentTotalBlocksVerified], "t1");
261: require(successVerifyProof, "p"); // Proof verification fail
265: require(successProofAggregation, "hh"); // Proof aggregation must be valid
268: require(currentTotalBlocksVerified <= s.totalBlocksCommitted, "q");
337: require(s.totalBlocksCommitted > _newLastBlock, "v1"); // the last committed block is less new last block
File: ethereum/contracts/zksync/facets/Getters.sol
148: require(ds.selectorToFacet[_selector].facetAddress != address(0), "g2");
File: ethereum/contracts/zksync/facets/Governance.sol
30: require(msg.sender == pendingGovernor, "n4"); // Only proposed by current governor address can claim the governor rights
File: ethereum/contracts/zksync/facets/Mailbox.sol
56: require(_blockNumber <= s.totalBlocksExecuted, "xx");
63: require(hashedLog != L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH, "tw");
66: require(_proof.length == L2_TO_L1_LOG_MERKLE_TREE_HEIGHT, "rz");
124: require(_ergsLimit <= PRIORITY_TX_MAX_ERGS_LIMIT, "ui");
File: ethereum/contracts/zksync/libraries/Diamond.sol
100: require(selectors.length > 0, "B"); // no functions for diamond cut
109: revert("C"); // undefined diamond cut action
126: require(_facet != address(0), "G"); // facet with zero address cannot be added
135: require(oldFacet.facetAddress == address(0), "J"); // facet for this selector already exists
150: require(_facet != address(0), "K"); // cannot replace facet with zero address
156: require(oldFacet.facetAddress != address(0), "L"); // it is impossible to replace the facet with zero address
170: require(_facet == address(0), "a1"); // facet address must be zero
176: require(oldFacet.facetAddress != address(0), "a2"); // Can't delete a non-existent facet
214: require(_isSelectorFreezable == ds.selectorToFacet[selector0].isFreezable, "J1");
279: require(_calldata.length == 0, "H"); // Non-empty calldata for zero address
283: require(success, "I"); // delegatecall failed
287: require(data.length == 32, "lp");
288: require(abi.decode(data, (bytes32)) == DIAMOND_INIT_SUCCESS_RETURN_VALUE, "lp1");
File: ethereum/contracts/zksync/libraries/Merkle.sol
23: require(pathLength > 0, "xc");
24: require(pathLength < 256, "bt");
25: require(_index < 2**pathLength, "pz");
File: ethereum/contracts/zksync/libraries/PriorityQueue.sol
64: require(!_queue.isEmpty(), "D"); // priority queue is empty
72: require(!_queue.isEmpty(), "s"); // priority queue is empty
File: zksync/contracts/bridge/L2ERC20Bridge.sol
58: require(msg.sender == l1Bridge, "mq");
63: require(deployedToken == expectedL2Token, "mt");
95: require(l1Token != address(0), "yh");
File: zksync/contracts/bridge/L2ETHBridge.sol
49: require(msg.sender == l1Bridge, "ni");
64: require(_l2Token == CONVENTIONAL_ETH_ADDRESS, "zn");
File: zksync/contracts/bridge/L2StandardERC20.sol
44: require(l1Address == address(0), "in5"); // Is already initialized
45: require(_l1Address != address(0), "in6"); // Should be non-zero address