Skip to content

Latest commit

 

History

History
2547 lines (1629 loc) · 146 KB

zksync.md

File metadata and controls

2547 lines (1629 loc) · 146 KB

Report

Gas Optimizations

Issue Instances Total Gas Savings
GAS-1 abi.encode is more efficient than abi.encodePacked 11
GAS-2 With assembly, .call (bool success) transfer can be done gas-optimized 5
GAS-3 Use assembly to emit events 71
GAS-4 Use assembly for small keccak256 hashes, in order to save gas 18
GAS-5 Use uint256(1)/uint256(2) instead for true and false boolean states 8
GAS-6 .length should not be looked up in every loop of a for-loop 11
GAS-7 For Operations that will not overflow, you could use unchecked 77
GAS-8 Don't compare boolean expressions to boolean literals 1

| GAS-10 | Multiplication/division by two should use bit shifting | 27 | | GAS-11 | >=/ <= costs less gas than >/< | 70 | | GAS-12 | Use hardcode address instead of address(this) | 18 | | GAS-13 | Don't initialize variables with default value | 35 | | GAS-14 | Long revert strings | 63 | | GAS-15 | Constructors can be marked payable | 17 |

| GAS-19 | Use shift Right/Left instead of division/multiplication if possible | 3 |

| GAS-22 | Using this to access functions results in an external call, wasting gas | 1 | | GAS-23 | ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in forand whileloops | 7 | | GAS-24 | Use != 0 instead of > 0 for unsigned integer comparison | 25 |

Total Gas Savings for GAS Issues: 200868 gas

Total: 942 instances over 24 issues

[GAS-1] abi.encode is more efficient than abi.encodePacked

abi.encode uses less gas than abi.encodePacked: the gas saved depends on the number of arguments, with an average of ~90 per argument. Test available here.

There are 11 instances of this issue:
File: /state-transition/chain-deps/facets/Executor.sol

461:                     abi.encodePacked(

517:             abi.encodePacked(

528:             abi.encodePacked(

548:             abi.encodePacked(

610:         bytes memory precompileInput = abi.encodePacked(_versionedHash, _openingPoint, _openingValueCommitmentProof);

655:                 abi.encodePacked(blobVersionedHash, _pubdataCommitments[i:i + PUBDATA_COMMITMENT_COMMITMENT_OFFSET])
File: /state-transition/chain-deps/facets/Mailbox.sol

113:             abi.encodePacked(_log.l2ShardId, _log.isService, _log.txNumberInBatch, _log.sender, _log.key, _log.value)
File: /system-contracts/contracts/L1Messenger.sol

96:             abi.encodePacked(
File: /system-contracts/contracts/SystemContext.sol

234:         return keccak256(abi.encodePacked(uint32(_blockNumber)));
File: /system-contracts/contracts/libraries/TransactionHelper.sol

133:                 keccak256(abi.encodePacked(_transaction.factoryDeps)),

142:         return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));

[461] ,[517] ,[528] ,[548] ,[610] ,[655] ,[113] ,[96] ,[234] ,[133] ,[142] ,

[GAS-2] With assembly, .call (bool success) transfer can be done gas-optimized

When using assembly language, it is possible to call the transfer function of an Ethereum contract in a gas-optimized way by using the .call function with specific input parameters. The .call function takes a number of input parameters, including the address of the contract to call, the amount of Ether to transfer, and a specification of the gas limit for the call. By specifying a lower gas limit than the default, it is possible to reduce the gas cost of the transfer.

Instances of this issue:

File: /governance/Governance.sol

174:         _execute(_operation.calls);

193:         _execute(_operation.calls);

226:             (bool success, bytes memory returnData) = _calls[i].target.call{value: _calls[i].value}(_calls[i].data);
File: /system-contracts/contracts/ContractDeployer.sol

231:             _deployment.callConstructor
File: /system-contracts/contracts/libraries/SystemContractHelper.sol

285:         meta.callerShardId = getCallerShardIdFromMeta(metaPacked);

[174] ,[193] ,[226] ,[231] ,[285] ,

[GAS-3] Use assembly to emit events

We can use assembly to emit events efficiently by utilizing scratch space and the free memory pointer. This will allow us to potentially avoid memory expansion costs. Note: In order to do this optimization safely, we will need to cache and restore the free memory pointer.

There are 71 instances of this issue:
File: /bridge/L1ERC20Bridge.sol

155:         emit DepositInitiated(l2TxHash, msg.sender, _l2Receiver, _l1Token, _amount);

199:         emit ClaimedFailedDeposit(_depositSender, _l1Token, amount);

225:         emit WithdrawalFinalized(l1Receiver, l1Token, amount);
File: /bridge/L1SharedBridge.sol

168:         emit BridgehubDepositBaseTokenInitiated(_chainId, _prevMsgSender, _l1Token, _amount);

227:         emit BridgehubDepositInitiated(_chainId, txDataHash, _prevMsgSender, _l2Receiver, _l1Token, amount);

239:         emit BridgehubDepositFinalized(_chainId, _txDataHash, _txHash);

367:         emit ClaimedFailedDepositSharedBridge(_chainId, _depositSender, _l1Token, _amount);

454:         emit WithdrawalFinalizedSharedBridge(_chainId, l1Receiver, l1Token, amount);

602:         emit LegacyDepositInitiated(ERA_CHAIN_ID, l2TxHash, _prevMsgSender, _l2Receiver, _l1Token, _amount);
File: /bridgehub/Bridgehub.sol

56:         emit NewPendingAdmin(oldPendingAdmin, _newPendingAdmin);

68:         emit NewPendingAdmin(currentPendingAdmin, address(0));

69:         emit NewAdmin(previousAdmin, pendingAdmin);

145:         emit NewChain(_chainId, _stateTransitionManager, _admin);
File: /governance/Governance.sol

47:         emit ChangeSecurityCouncil(address(0), _securityCouncil);

50:         emit ChangeMinDelay(0, _minDelay);

132:         emit TransparentOperationScheduled(id, _delay, _operation);

144:         emit ShadowOperationScheduled(_id, _delay);

157:         emit OperationCancelled(_id);

180:         emit OperationExecuted(id);

199:         emit OperationExecuted(id);

250:         emit ChangeMinDelay(minDelay, _newDelay);

257:         emit ChangeSecurityCouncil(securityCouncil, _newSecurityCouncil);
File: /state-transition/StateTransitionManager.sol

115:         emit NewPendingAdmin(oldPendingAdmin, _newPendingAdmin);

127:         emit NewPendingAdmin(currentPendingAdmin, address(0));

128:         emit NewAdmin(previousAdmin, pendingAdmin);

227:         emit SetChainIdUpgrade(_chainContract, l2ProtocolUpgradeTx, protocolVersion);

235:         emit StateTransitionNewChain(_chainId, _stateTransitionContract);

287:         emit StateTransitionNewChain(_chainId, stateTransitionAddress);
File: /state-transition/ValidatorTimelock.sol

83:         emit ValidatorAdded(_chainId, _newValidator);

92:         emit ValidatorRemoved(_chainId, _validator);

98:         emit NewExecutionDelay(_executionDelay);
File: /state-transition/chain-deps/facets/Admin.sol

28:         emit NewPendingAdmin(oldPendingAdmin, _newPendingAdmin);

40:         emit NewPendingAdmin(pendingAdmin, address(0));

41:         emit NewAdmin(previousAdmin, pendingAdmin);

47:         emit ValidatorStatusUpdate(_validator, _active);

54:         emit IsPorterAvailableStatusUpdate(_zkPorterIsAvailable);

63:         emit NewPriorityTxMaxGasLimit(oldPriorityTxMaxGasLimit, _newPriorityTxMaxGasLimit);

75:         emit NewFeeParams(oldFeeParams, _newFeeParams);

86:         emit NewBaseTokenMultiplier(oldNominator, oldDenominator, _nominator, _denominator);

92:         emit ValidiumModeStatusUpdate(_validiumMode);

115:         emit ExecuteUpgrade(_diamondCut);

125:         emit ExecuteUpgrade(_diamondCut);

139:         emit Freeze();

149:         emit Unfreeze();
File: /state-transition/chain-deps/facets/Executor.sol

135:         bytes memory emittedL2Logs = _newBatch.systemLogs;

142:         for (uint256 i = 0; i < emittedL2Logs.length; i = i.uncheckedAdd(L2_TO_L1_LOG_SERIALIZE_SIZE)) {

144:             (address logSender, ) = UnsafeBytes.readAddress(emittedL2Logs, i + L2_LOG_ADDRESS_OFFSET);

145:             (uint256 logKey, ) = UnsafeBytes.readUint256(emittedL2Logs, i + L2_LOG_KEY_OFFSET);

146:             (bytes32 logValue, ) = UnsafeBytes.readBytes32(emittedL2Logs, i + L2_LOG_VALUE_OFFSET);

261:             emit BlockCommit(

299:             emit BlockCommit(

353:             emit BlockExecution(_batchesData[i].batchNumber, _batchesData[i].batchHash, _batchesData[i].commitment);

436:         emit BlocksVerification(s.totalBatchesVerified, currentTotalBatchesVerified);

496:         emit BlocksRevert(s.totalBatchesCommitted, s.totalBatchesVerified, s.totalBatchesExecuted);
File: /state-transition/chain-deps/facets/Mailbox.sol

343:         emit NewPriorityRequest(
File: /state-transition/libraries/Diamond.sol

121:         emit DiamondCut(facetCuts, initAddress, initCalldata);
File: /system-contracts/contracts/ContractDeployer.sol

68:         emit AccountVersionUpdated(msg.sender, _version);

86:         emit AccountNonceOrderingUpdated(msg.sender, _nonceOrdering);

355:         emit ContractDeployed(_sender, _bytecodeHash, _newAddress);
File: /system-contracts/contracts/L1Messenger.sol

111:         emit L2ToL1LogSent(_l2ToL1Log);

156:         emit L1MessageSent(msg.sender, hash, _message);

181:         emit BytecodeL1PublicationRequested(_bytecodeHash);
File: /system-contracts/contracts/NonceHolder.sol

96:         emit ValueSetUnderNonce(msg.sender, _key, _value);
File: /upgrades/BaseZkSyncUpgrade.sol

87:         emit UpgradeComplete(_proposedUpgrade.newProtocolVersion, txHash, _proposedUpgrade);

104:         emit NewL2DefaultAccountBytecodeHash(previousDefaultAccountBytecodeHash, _l2DefaultAccountBytecodeHash);

121:         emit NewL2BootloaderBytecodeHash(previousBootloaderBytecodeHash, _l2BootloaderBytecodeHash);

137:         emit NewVerifier(address(oldVerifier), address(_newVerifier));

157:         emit NewVerifierParams(oldVerifierParams, _newVerifierParams);

256:         emit NewProtocolVersion(previousProtocolVersion, _newProtocolVersion);
File: /upgrades/BaseZkSyncUpgradeGenesis.sol

40:         emit NewProtocolVersion(previousProtocolVersion, _newProtocolVersion);

67:         emit UpgradeComplete(_proposedUpgrade.newProtocolVersion, txHash, _proposedUpgrade);

[155] ,[199] ,[225] ,[168] ,[227] ,[239] ,[367] ,[454] ,[602] ,[56] ,[68] ,[69] ,[145] ,[47] ,[50] ,[132] ,[144] ,[157] ,[180] ,[199] ,[250] ,[257] ,[115] ,[127] ,[128] ,[227] ,[235] ,[287] ,[83] ,[92] ,[98] ,[28] ,[40] ,[41] ,[47] ,[54] ,[63] ,[75] ,[86] ,[92] ,[115] ,[125] ,[139] ,[149] ,[135] ,[142] ,[144] ,[145] ,[146] ,[261] ,[299] ,[353] ,[436] ,[496] ,[343] ,[121] ,[68] ,[86] ,[355] ,[111] ,[156] ,[181] ,[96] ,[87] ,[104] ,[121] ,[137] ,[157] ,[256] ,[40] ,[67] ,

[GAS-4] Use assembly for small keccak256 hashes, in order to save gas

Use assembly for small keccak256 hashes, in order to save gas

There are 18 instances of this issue:
File: /bridge/L1ERC20Bridge.sol

76:         bytes32 constructorInputHash = keccak256(abi.encode(l2TokenBeacon, ""));
File: /bridge/L1SharedBridge.sol

210:         bytes32 txDataHash = keccak256(abi.encode(_prevMsgSender, _l1Token, amount));

341:                 bytes32 txDataHash = keccak256(abi.encode(_depositSender, _l1Token, _amount));

598:         bytes32 txDataHash = keccak256(abi.encode(_prevMsgSender, _l1Token, _amount));
File: /governance/Governance.sol

205:         return keccak256(abi.encode(_operation));
File: /state-transition/StateTransitionManager.sol

100:         storedBatchZero = keccak256(abi.encode(batchZero));

102:         initialCutHash = keccak256(abi.encode(_initializeData.diamondCut));

138:         initialCutHash = keccak256(abi.encode(_diamondCut));

147:         upgradeCutHash[_oldProtocolVersion] = keccak256(abi.encode(_cutData));

156:         upgradeCutHash[_oldProtocolVersion] = keccak256(abi.encode(_cutData));
File: /state-transition/chain-deps/facets/Admin.sol

104:         bytes32 cutHashInput = keccak256(abi.encode(_diamondCut));
File: /state-transition/chain-deps/facets/Executor.sol

313:             concatHash = keccak256(abi.encode(concatHash, priorityOp.canonicalTxHash));

588:         return keccak256(abi.encode(_storedBatchInfo));
File: /system-contracts/contracts/L1Messenger.sol

106:         chainedLogsHash = keccak256(abi.encode(chainedLogsHash, hashedLog));

122:         chainedMessagesHash = keccak256(abi.encode(chainedMessagesHash, hash));

212:             reconstructedChainedLogsHash = keccak256(abi.encode(reconstructedChainedLogsHash, hashedLog));
File: /system-contracts/contracts/SystemContext.sol

159:             hash = keccak256(abi.encode(_block));

403:         currentL2BlockTxsRollingHash = keccak256(abi.encode(currentL2BlockTxsRollingHash, _txHash));

[76] ,[210] ,[341] ,[598] ,[205] ,[100] ,[102] ,[138] ,[147] ,[156] ,[104] ,[313] ,[588] ,[106] ,[122] ,[212] ,[159] ,[403] ,

[GAS-5] Use uint256(1)/uint256(2) instead for true and false boolean states

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.

There are 8 instances of this issue:
File: /bridge/L1ERC20Bridge.sol

27:     mapping(uint256 l2BatchNumber => mapping(uint256 l2ToL1MessageNumber => bool isFinalized))
File: /bridge/L1SharedBridge.sol

57:     mapping(uint256 chainId => mapping(uint256 l2BatchNumber => mapping(uint256 l2ToL1MessageNumber => bool isFinalized)))

61:     mapping(uint256 chainId => bool enabled) internal hyperbridgingEnabled;
File: /bridgehub/Bridgehub.sol

21:     mapping(address _stateTransitionManager => bool) public stateTransitionManagerIsRegistered;

23:     mapping(address _token => bool) public tokenIsRegistered;
File: /state-transition/ValidatorTimelock.sol

50:     mapping(uint256 _chainId => mapping(address _validator => bool)) public validators;
File: /state-transition/chain-deps/ZkSyncStateTransitionStorage.sol

74:     mapping(address validatorAddress => bool isValidator) validators;

114:     mapping(uint256 l2BatchNumber => mapping(uint256 l2ToL1MessageNumber => bool isFinalized)) isEthWithdrawalFinalized;

[27] ,[57] ,[61] ,[21] ,[23] ,[50] ,[74] ,[114] ,

[GAS-6] .length should not be looked up in every loop of a for-loop

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).

There are 11 instances of this issue:
File: /governance/Governance.sol

225:         for (uint256 i = 0; i < _calls.length; ++i) {
File: /state-transition/ValidatorTimelock.sol

116:             for (uint256 i = 0; i < _newBatchesData.length; ++i) {

135:             for (uint256 i = 0; i < _newBatchesData.length; ++i) {

185:             for (uint256 i = 0; i < _newBatchesData.length; ++i) {

209:             for (uint256 i = 0; i < _newBatchesData.length; ++i) {
File: /state-transition/chain-deps/facets/Executor.sol

142:         for (uint256 i = 0; i < emittedL2Logs.length; i = i.uncheckedAdd(L2_TO_L1_LOG_SERIALIZE_SIZE)) {

257:         for (uint256 i = 0; i < _newBatchesData.length; i = i.uncheckedInc()) {

289:         for (uint256 i = 0; i < _newBatchesData.length; i = i.uncheckedInc()) {

636:         for (uint256 i = 0; i < _pubdataCommitments.length; i += PUBDATA_COMMITMENT_SIZE) {
File: /system-contracts/contracts/Compressor.sol

61:             for (uint256 encodedDataPointer = 0; encodedDataPointer < encodedData.length; encodedDataPointer += 2) {
File: /upgrades/BaseZkSyncUpgrade.sol

226:         for (uint256 i = 0; i < _factoryDeps.length; ++i) {

[225] ,[116] ,[135] ,[185] ,[209] ,[142] ,[257] ,[289] ,[636] ,[61] ,[226] ,

[GAS-7] For Operations that will not overflow, you could use unchecked

There are 77 instances of this issue:
File: /bridge/L1ERC20Bridge.sol

12: import {ReentrancyGuard} from "../common/ReentrancyGuard.sol";

76:         bytes32 constructorInputHash = keccak256(abi.encode(l2TokenBeacon, ""));

143:         require(amount == _amount, "3T"); // The token has non-standard transfer logic
File: /bridge/L1SharedBridge.sol

24: import {L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR} from "../common/L2ContractAddresses.sol";

121:             require(balanceAfter > balanceBefore, "ShB: 0 eth transferred");

161:             require(amount == _amount, "3T"); // The token has non-standard transfer logic

257:             bytes memory symbol = bytes("ETH");

349:             require(chainBalance[_chainId][_l1Token] >= _amount, "ShB n funds");

439:             require(chainBalance[_chainId][l1Token] >= amount, "ShB not enough funds 2"); // not enought funds //@auidt cache multiple error

564:         require(_l1Token != l1WethAddress, "ShB: WETH deposit not supported 2");
File: /bridge/interfaces/IL1SharedBridge.sol

7: import {IL1ERC20Bridge} from "./IL1ERC20Bridge.sol";
File: /state-transition/StateTransitionManager.sol

20: import {VerifierParams} from "./chain-interfaces/IVerifier.sol";
File: /state-transition/ValidatorTimelock.sol

9: import {ERA_CHAIN_ID} from "../common/Config.sol";
File: /state-transition/chain-deps/ZkSyncStateTransitionStorage.sol

6: import {PriorityQueue} from "../../state-transition/libraries/PriorityQueue.sol";
File: /state-transition/chain-deps/facets/Executor.sol

17: import {IZkSyncStateTransitionBase} from "../../chain-interfaces/IZkSyncStateTransitionBase.sol";

64:                 "wp"

78:         require(logOutput.numberOfLayer1Txs == _newBatch.numberOfLayer1Txs, "ta");

330:         require(priorityOperationsHash == _storedBatch.priorityOperationsHash, "x"); // priority operations hash does not match to expected

568:         require(_blobHashes.length == MAX_NUMBER_OF_BLOBS, "b11");

639:             require(blobVersionedHash != bytes32(0), "vh");
File: /state-transition/chain-deps/facets/Getters.sol

15: import {IZkSyncStateTransitionBase} from "../../chain-interfaces/IZkSyncStateTransitionBase.sol";
File: /state-transition/chain-deps/facets/Mailbox.sol

25: import {IZkSyncStateTransitionBase} from "../../chain-interfaces/IZkSyncStateTransitionBase.sol";

39:         require(s.chainId == ERA_CHAIN_ID, "transferEthToSharedBridge only available for Era on mailbox");

117:         require(hashedLog != L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH, "tw");

158:         require(s.baseTokenGasPriceMultiplierDenominator > 0, "Mailbox: baseTokenGasPriceDenominator not set");
File: /state-transition/chain-deps/facets/ZkSyncStateTransitionBase.sol

6: import {ReentrancyGuard} from "../../../common/ReentrancyGuard.sol";
File: /state-transition/chain-interfaces/IExecutor.sol

5: import {IZkSyncStateTransitionBase} from "./IZkSyncStateTransitionBase.sol";
File: /state-transition/chain-interfaces/IGetters.sol

8: import {IZkSyncStateTransitionBase} from "./IZkSyncStateTransitionBase.sol";
File: /state-transition/libraries/Diamond.sol

6: import {UncheckedMath} from "../../common/libraries/UncheckedMath.sol";

18:         0x33774e659306e47509050e97cb651e731180a42d458212294d30751925c551a2; // keccak256("diamond.zksync.init") - 1

22:         0xc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131b; // keccak256("diamond.standard.diamond.storage") - 1;

116:                 revert("C"); // undefined diamond cut action

141:             require(oldFacet.facetAddress == address(0), "J"); // facet for this selector already exists

161:             require(oldFacet.facetAddress != address(0), "L"); // it is impossible to replace the facet with zero address

181:             require(oldFacet.facetAddress != address(0), "a2"); // Can't delete a non-existent facet

215:             require(_isSelectorFreezable == ds.selectorToFacet[selector0].isFreezable, "J1");

280:             require(_calldata.length == 0, "H"); // Non-empty calldata for zero address
File: /state-transition/libraries/Merkle.sol

5: import {UncheckedMath} from "../../common/libraries/UncheckedMath.sol";
File: /state-transition/libraries/TransactionValidator.sol

8: import {TX_SLOT_OVERHEAD_L2_GAS, MEMORY_OVERHEAD_GAS, L1_TX_INTRINSIC_L2_GAS, L1_TX_DELTA_544_ENCODING_BYTES, L1_TX_DELTA_FACTORY_DEPS_L2_GAS, L1_TX_MIN_L2_GAS_BASE, L1_TX_INTRINSIC_PUBDATA, L1_TX_DELTA_FACTORY_DEPS_PUBDATA} from "../../common/Config.sol";

60:         require(_transaction.reservedDynamic.length == 0, "um");

115:         require(_totalGasLimit >= overhead, "my"); // provided gas limit doesn't cover transaction overhead
File: /system-contracts/contracts/AccountCodeStorage.sol

7: import {DEPLOYER_SYSTEM_CONTRACT, NONCE_HOLDER_SYSTEM_CONTRACT, CURRENT_MAX_PRECOMPILE_ADDRESS} from "./Constants.sol";
File: /system-contracts/contracts/BootloaderUtilities.sol

8: import {EfficientCall} from "./libraries/EfficientCall.sol";

37:             revert("Unsupported tx type");

92:             require(vInt == 27 || vInt == 28, "Invalid v value");

191:             require(vInt == 27 || vInt == 28, "Invalid v value");

286:             require(vInt == 27 || vInt == 28, "Invalid v value");
File: /system-contracts/contracts/Compressor.sol

10: import {L1_MESSENGER_CONTRACT, INITIAL_WRITE_STARTING_POSITION, COMPRESSED_INITIAL_WRITE_SIZE, STATE_DIFF_ENTRY_SIZE, STATE_DIFF_ENUM_INDEX_OFFSET, STATE_DIFF_FINAL_VALUE_OFFSET, STATE_DIFF_DERIVED_KEY_OFFSET, DERIVED_KEY_LENGTH, VALUE_LENGTH, ENUM_INDEX_LENGTH, KNOWN_CODE_STORAGE_CONTRACT} from "./Constants.sol";

187:         require(stateDiffPtr == _compressedStateDiffs.length, "Extra data in _compressedStateDiffs");

242:                 revert("unsupported operation");
File: /system-contracts/contracts/Constants.sol

16: import {IPubdataChunkPublisher} from "./interfaces/IPubdataChunkPublisher.sol";
File: /system-contracts/contracts/ContractDeployer.sol

12: import {ISystemContract} from "./interfaces/ISystemContract.sol";

29:         require(msg.sender == address(this), "Callable only by self");
File: /system-contracts/contracts/DefaultAccount.sol

9: import {BOOTLOADER_FORMAL_ADDRESS, NONCE_HOLDER_SYSTEM_CONTRACT, DEPLOYER_SYSTEM_CONTRACT, INonceHolder} from "./Constants.sol";

100:         require(totalRequiredBalance <= address(this).balance, "Not enough balance for fee + value");
File: /system-contracts/contracts/L1Messenger.sol

10: import {SystemLogKey, SYSTEM_CONTEXT_CONTRACT, KNOWN_CODE_STORAGE_CONTRACT, COMPRESSOR_CONTRACT, STATE_DIFF_ENTRY_SIZE, MAX_ALLOWED_PUBDATA_PER_BATCH, L2_TO_L1_LOGS_MERKLE_TREE_LEAVES, PUBDATA_CHUNK_PUBLISHER, COMPUTATIONAL_PRICE_FOR_PUBDATA} from "./Constants.sol";
File: /system-contracts/contracts/NonceHolder.sol

8: import {DEPLOYER_SYSTEM_CONTRACT} from "./Constants.sol";

66:         require(_value <= MAXIMAL_MIN_NONCE_INCREMENT, "The value for incrementing the nonce is too high");
File: /system-contracts/contracts/SystemContext.sol

9: import {BOOTLOADER_FORMAL_ADDRESS, SystemLogKey} from "./Constants.sol";

245:         require(_l2BlockNumber > 0, "L2 block number is never expected to be zero");

249:             require(correctPrevBlockHash == _expectedPrevL2BlockHash, "The previous L2 block hash is incorrect");

287:             require(_maxVirtualBlocksToCreate > 0, "Can't initialize the first virtual block");

373:             require(_maxVirtualBlocksToCreate == 0, "Can not create virtual blocks in the middle of the miniblock");

394:             revert("Invalid new L2 block number");
File: /system-contracts/contracts/libraries/EfficientCall.sol

7: import {SHA256_SYSTEM_CONTRACT, KECCAK256_SYSTEM_CONTRACT, MSG_VALUE_SYSTEM_CONTRACT} from "../Constants.sol";

47:         require(returnData.length == 32, "sha returned invalid data");
File: /system-contracts/contracts/libraries/SystemContractHelper.sol

7: import {SystemContractsCaller, CalldataForwardingMode, CALLFLAGS_CALL_ADDRESS, CODE_ADDRESS_CALL_ADDRESS, EVENT_WRITE_ADDRESS, EVENT_INITIALIZE_ADDRESS, GET_EXTRA_ABI_DATA_ADDRESS, LOAD_CALLDATA_INTO_ACTIVE_PTR_CALL_ADDRESS, META_CODE_SHARD_ID_OFFSET, META_CALLER_SHARD_ID_OFFSET, META_SHARD_ID_OFFSET, META_AUX_HEAP_SIZE_OFFSET, META_HEAP_SIZE_OFFSET, META_GAS_PER_PUBDATA_BYTE_OFFSET, MIMIC_CALL_BY_REF_CALL_ADDRESS, META_CALL_ADDRESS, MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT, PTR_CALLDATA_CALL_ADDRESS, PTR_ADD_INTO_ACTIVE_CALL_ADDRESS, PTR_SHRINK_INTO_ACTIVE_CALL_ADDRESS, PTR_PACK_INTO_ACTIVE_CALL_ADDRESS, RAW_FAR_CALL_BY_REF_CALL_ADDRESS, PRECOMPILE_CALL_ADDRESS, SET_CONTEXT_VALUE_CALL_ADDRESS, SYSTEM_CALL_BY_REF_CALL_ADDRESS, TO_L1_CALL_ADDRESS} from "./SystemContractsCaller.sol";

319:         require(index < 10, "There are only 10 accessible registers");
File: /system-contracts/contracts/libraries/SystemContractsCaller.sol

6: import "./Utils.sol";
File: /system-contracts/contracts/libraries/TransactionHelper.sol

12: import "./EfficientCall.sol";

112:             revert("Encoding unsupported tx");

142:         return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));

177:                 encodedDataLength = hex"81";
File: /upgrades/BaseZkSyncUpgrade.sol

12: import {L2CanonicalTransaction} from "../common/Messaging.sol";
File: /upgrades/BaseZkSyncUpgradeGenesis.sol

12: import {ProposedUpgrade, BaseZkSyncUpgrade} from "./BaseZkSyncUpgrade.sol";
File: /upgrades/DefaultUpgrade.sol

6: import {BaseZkSyncUpgrade, ProposedUpgrade} from "./BaseZkSyncUpgrade.sol";
File: /upgrades/GenesisUpgrade.sol

7: import "./IDefaultUpgrade.sol";

[12] ,[76] ,[143] ,[24] ,[121] ,[161] ,[257] ,[349] ,[439] ,[564] ,[7] ,[20] ,[9] ,[6] ,[17] ,[64] ,[78] ,[330] ,[568] ,[639] ,[15] ,[25] ,[39] ,[117] ,[158] ,[6] ,[5] ,[8] ,[6] ,[18] ,[22] ,[116] ,[141] ,[161] ,[181] ,[215] ,[280] ,[5] ,[8] ,[60] ,[115] ,[7] ,[8] ,[37] ,[92] ,[191] ,[286] ,[10] ,[187] ,[242] ,[16] ,[12] ,[29] ,[9] ,[100] ,[10] ,[8] ,[66] ,[9] ,[245] ,[249] ,[287] ,[373] ,[394] ,[7] ,[47] ,[7] ,[319] ,[6] ,[12] ,[112] ,[142] ,[177] ,[12] ,[12] ,[6] ,[7] ,

[GAS-8] Don't compare boolean expressions to boolean literals

true and false are constants and it is more expensive comparing a boolean against them than directly checking the returned boolean value. if (<x> == true) => if (<x>), if (<x> == false) => if (!<x>)

Instances of this issue:

File: /state-transition/ValidatorTimelock.sol

68:         require(validators[_chainId][msg.sender] == true, "ValidatorTimelock: only validator");

[68] ,

[GAS-10] Multiplication/division by two should use bit shifting

X * 2 is equivalent to X << 1 and X / 2 is the same as X >> 1. The MUL and DIV opcodes cost 5 gas, whereas SHL and SHR only cost 3 gas.

There are 27 instances of this issue:
File: /common/libraries/L2ContractHelper.sol

25:         uint256 bytecodeLenInWords = _bytecode.length / 32;

50:         codeLengthInWords = uint256(uint8(_bytecodeHash[2])) * 256 + uint256(uint8(_bytecodeHash[3]));
File: /state-transition/StateTransitionManager.sol

106:         assert(L2_TO_L1_LOG_SERIALIZE_SIZE != 2 * 32);
File: /state-transition/chain-deps/DiamondInit.sol

51:         assert(L2_TO_L1_LOG_SERIALIZE_SIZE != 2 * 32);
File: /state-transition/chain-deps/facets/Executor.sol

581:             blobAuxOutputWords[i * 2] = _blobHashes[i];

582:             blobAuxOutputWords[i * 2 + 1] = _blobCommitments[i];
File: /state-transition/libraries/LibMap.sol

23:             uint256 mapValue = _map.map[_index / 8];

27:             uint256 bitOffset = (_index & 7) * 32;

43:             uint256 mapIndex = _index / 8;

48:             uint256 bitOffset = (_index & 7) * 32;
File: /system-contracts/contracts/BootloaderUtilities.sol

97:                 vInt += 8 + block.chainid * 2;
File: /system-contracts/contracts/Compressor.sol

52:                 encodedData.length * 4 == _bytecode.length,

57:                 dictionary.length / 8 <= encodedData.length / 2,//@audit cache length

57:                 dictionary.length / 8 <= encodedData.length / 2,//@audit cache length

62:                 uint256 indexOfEncodedChunk = uint256(encodedData.readUint16(encodedDataPointer)) * 8;

66:                 uint64 realChunk = _bytecode.readUint64(encodedDataPointer * 4);

203:             dictionary = _rawCompressedData[2:2 + dictionaryLen * 8];

204:             encodedData = _rawCompressedData[2 + dictionaryLen * 8:];

253:         number >>= (256 - (_calldataSlice.length * 8));
File: /system-contracts/contracts/libraries/RLPEncoder.sol

37:                 uint256 shiftedVal = _val << (lbs * 8);

72:                 uint256 shiftedVal = uint256(_len) << (lbs * 8);
File: /system-contracts/contracts/libraries/SystemContractsCaller.sol

41: uint256 constant META_GAS_PER_PUBDATA_BYTE_OFFSET = 0 * 8;

42: uint256 constant META_HEAP_SIZE_OFFSET = 8 * 8;

43: uint256 constant META_AUX_HEAP_SIZE_OFFSET = 12 * 8;

44: uint256 constant META_SHARD_ID_OFFSET = 28 * 8;

45: uint256 constant META_CALLER_SHARD_ID_OFFSET = 29 * 8;

46: uint256 constant META_CODE_SHARD_ID_OFFSET = 30 * 8;

[25] ,[50] ,[106] ,[51] ,[581] ,[582] ,[23] ,[27] ,[43] ,[48] ,[97] ,[52] ,[57] ,[57] ,[62] ,[66] ,[203] ,[204] ,[253] ,[37] ,[72] ,[41] ,[42] ,[43] ,[44] ,[45] ,[46] ,

[GAS-11] >=/ <= costs less gas than >/<

The compiler uses opcodes GT and ISZERO for solidity code that uses >, but only requires LT for >=,which saves 3 gas

There are 70 instances of this issue:
File: /bridge/L1SharedBridge.sol

121:             require(balanceAfter > balanceBefore, "ShB: 0 eth transferred");

129:             require(amount > 0, "ShB: 0 amount to transfer");

158:             require(msg.value == 0, "ShB m.v > 0 b d.it");

202:             require(msg.value == 0, "ShB m.v > 0 for BH d.it 2");

327:         require(_amount > 0, "y1");

501:         require(_l2ToL1message.length >= 56, "ShB wrong msg len"); // wrong messsage length  //@audit cache lemgth 
File: /bridgehub/Bridgehub.sol

301:             _request.secondBridgeAddress > BRIDGEHUB_MIN_SECOND_BRIDGE_ADDRESS,

329:         } else if (_refundRecipient.code.length > 0) {
File: /governance/Governance.sol

111:         } else if (timestamp > block.timestamp) {

217:         require(_delay >= minDelay, "Proposed delay is less than minimum delay");
File: /state-transition/ValidatorTimelock.sol

195:                 require(block.timestamp >= commitBatchTimestamp + delay, "5c"); // The delay is not passed

217:                 require(block.timestamp >= commitBatchTimestamp + delay, "5c"); // The delay is not passed
File: /state-transition/chain-deps/DiamondProxy.sol

25:         require(msg.data.length >= 4 || msg.data.length == 0, "Ut");
File: /state-transition/chain-deps/facets/Admin.sol

70:         require(_newFeeParams.maxPubdataPerBatch >= _newFeeParams.priorityTxMaxPubdata, "n6");

117:             s.protocolVersion > _oldProtocolVersion,
File: /state-transition/chain-deps/facets/Executor.sol

109:         uint256 batchTimestamp = _packedBatchAndL2BlockTimestamp >> 128;

429:         if (_proof.serializedProof.length > 0) {

482:         require(s.totalBatchesCommitted > _newLastBatch, "v1"); // The last committed batch is less than new last batch

483:         require(_newLastBatch >= s.totalBatchesExecuted, "v2"); // Already executed batches cannot be reverted

492:         if (s.l2SystemContractsUpgradeBatchNumber > _newLastBatch) {

631:         require(_pubdataCommitments.length > 0, "pl");
File: /state-transition/chain-deps/facets/Mailbox.sol

158:         require(s.baseTokenGasPriceMultiplierDenominator > 0, "Mailbox: baseTokenGasPriceDenominator not set");

272:         require(_mintValue >= baseCost + _params.l2Value, "mv"); // The `msg.value` doesn't cover the transaction cost

277:         if (refundRecipient.code.length > 0) {
File: /state-transition/libraries/Diamond.sol

107:             require(selectors.length > 0, "B"); // no functions for diamond cut

132:         require(_facet.code.length > 0, "G");

155:         require(_facet.code.length > 0, "K");
File: /state-transition/libraries/LibMap.sol

30:             result = uint32(mapValue >> bitOffset);

54:             uint32 oldValue = uint32(mapValue >> bitOffset);
File: /state-transition/libraries/Merkle.sol

24:         require(pathLength > 0, "xc");
File: /state-transition/libraries/TransactionValidator.sol

115:         require(_totalGasLimit >= overhead, "my"); // provided gas limit doesn't cover transaction overhead
File: /system-contracts/contracts/ComplexUpgrader.sol

24:         require(_delegateTo.code.length > 0, "Delegatee is an EOA");
File: /system-contracts/contracts/Compressor.sol

146:             uint8 len = operation == 0 ? 32 : metadata >> LENGTH_BITS_OFFSET;

177:             uint8 len = operation == 0 ? 32 : metadata >> LENGTH_BITS_OFFSET;

253:         number >>= (256 - (_calldataSlice.length * 8));
File: /system-contracts/contracts/ContractDeployer.sol

48:             _address > address(MAX_SYSTEM_CONTRACT_ADDRESS) &&

303:         require(knownCodeMarker > 0, "The code hash is not known");

332:             if (value > 0) {

339:             if (value > 0) {
File: /system-contracts/contracts/DefaultAccount.sol

139:         if (to == address(DEPLOYER_SYSTEM_CONTRACT) && data.length >= 4) {
File: /system-contracts/contracts/L1Messenger.sol

222:         while (nodesOnCurrentLevel > 1) {
File: /system-contracts/contracts/SystemContext.sol

119:         return pubdataPublished > basePubdataSpent ? pubdataPublished - basePubdataSpent : 0; //@audit cache basePubdataSpent

144:         if (blockNumber <= _block || blockNumber - _block > 256) {

151:             _block >= currentVirtualBlockUpgradeInfo.virtualBlockFinishL2Block &&

152:             currentVirtualBlockUpgradeInfo.virtualBlockFinishL2Block > 0

245:         require(_l2BlockNumber > 0, "L2 block number is never expected to be zero");

287:             require(_maxVirtualBlocksToCreate > 0, "Can't initialize the first virtual block");

302:         if (virtualBlockInfo.number >= _l2BlockNumber) {

352:                 _l2BlockTimestamp >= currentBatchTimestamp,

355:             require(_maxVirtualBlocksToCreate > 0, "There must be a virtual block created at the start of the batch");

387:                 _l2BlockTimestamp > currentL2BlockTimestamp,

413:         require(currentBatchNumber > 0, "The current batch number must be greater than 0");

430:             _newTimestamp > currentBlockTimestamp,

451:         require(_newTimestamp > previousBatchTimestamp, "Timestamps should be incremental");
File: /system-contracts/contracts/libraries/RLPEncoder.sol

86:             if (_number > type(uint128).max) {

87:                 _number >>= 128;

90:             if (_number > type(uint64).max) {

91:                 _number >>= 64;

94:             if (_number > type(uint32).max) {

95:                 _number >>= 32;

98:             if (_number > type(uint16).max) {

99:                 _number >>= 16;

102:             if (_number > type(uint8).max) {
File: /system-contracts/contracts/libraries/SystemContractHelper.sol

219:         result = (shifted >> (256 - size));
File: /system-contracts/contracts/libraries/TransactionHelper.sol

363:         require(_transaction.paymasterInput.length >= 4, "The standard paymaster input must be at least 4 bytes long");

368:                 _transaction.paymasterInput.length >= 68,
File: /upgrades/BaseZkSyncUpgrade.sol

72:         require(block.timestamp >= _proposedUpgrade.upgradeTimestamp, "Upgrade is not ready yet");

239:             _newProtocolVersion > previousProtocolVersion,
File: /upgrades/BaseZkSyncUpgradeGenesis.sol

24:             _newProtocolVersion >= previousProtocolVersion,

52:         require(block.timestamp >= _proposedUpgrade.upgradeTimestamp, "Upgrade is not ready yet");

[121] ,[129] ,[158] ,[202] ,[327] ,[501] ,[301] ,[329] ,[111] ,[217] ,[195] ,[217] ,[25] ,[70] ,[117] ,[109] ,[429] ,[482] ,[483] ,[492] ,[631] ,[158] ,[272] ,[277] ,[107] ,[132] ,[155] ,[30] ,[54] ,[24] ,[115] ,[24] ,[146] ,[177] ,[253] ,[48] ,[303] ,[332] ,[339] ,[139] ,[222] ,[119] ,[144] ,[151] ,[152] ,[245] ,[287] ,[302] ,[352] ,[355] ,[387] ,[413] ,[430] ,[451] ,[86] ,[87] ,[90] ,[91] ,[94] ,[95] ,[98] ,[99] ,[102] ,[219] ,[363] ,[368] ,[72] ,[239] ,[24] ,[52] ,

[GAS-12] Use hardcode address instead of address(this)

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

There are 18 instances of this issue:
File: /bridge/L1ERC20Bridge.sol

65:         uint256 amount = IERC20(_token).balanceOf(address(this));
File: /bridge/L1SharedBridge.sol

118:             uint256 balanceBefore = address(this).balance;

120:             uint256 balanceAfter = address(this).balance;

127:             uint256 balanceBefore = IERC20(_token).balanceOf(address(this));

131:             uint256 balanceAfter = IERC20(_token).balanceOf(address(this));

174:         uint256 balanceBefore = _token.balanceOf(address(this));

175:         _token.safeTransferFrom(_from, address(this), _amount);

176:         uint256 balanceAfter = _token.balanceOf(address(this));
File: /governance/Governance.sol

59:         require(msg.sender == address(this), "Only governance contract itself is allowed to call this function");
File: /state-transition/StateTransitionManager.sol

265:             bytes32(uint256(uint160(address(this)))),
File: /state-transition/chain-deps/facets/Mailbox.sol

41:         uint256 amount = address(this).balance;
File: /system-contracts/contracts/ContractDeployer.sol

29:         require(msg.sender == address(this), "Callable only by self");

333:                 BASE_TOKEN_SYSTEM_CONTRACT.transferFromTo(address(this), _newAddress, value);
File: /system-contracts/contracts/DefaultAccount.sol

47:         if (codeAddress != address(this)) {

100:         require(totalRequiredBalance <= address(this).balance, "Not enough balance for fee + value");

188:         return recoveredAddress == address(this) && recoveredAddress != address(0);
File: /system-contracts/contracts/L1Messenger.sol

129:             sender: address(this),
File: /system-contracts/contracts/libraries/TransactionHelper.sol

377:             uint256 currentAllowance = IERC20(token).allowance(address(this), paymaster);

[65] ,[118] ,[120] ,[127] ,[131] ,[174] ,[175] ,[176] ,[59] ,[265] ,[41] ,[29] ,[333] ,[47] ,[100] ,[188] ,[129] ,[377] ,

[GAS-13] Don't initialize variables with default value

There are 35 instances of this issue:
File: /governance/Governance.sol

225:         for (uint256 i = 0; i < _calls.length; ++i) {
File: /state-transition/ValidatorTimelock.sol

116:             for (uint256 i = 0; i < _newBatchesData.length; ++i) {

135:             for (uint256 i = 0; i < _newBatchesData.length; ++i) {

185:             for (uint256 i = 0; i < _newBatchesData.length; ++i) {

209:             for (uint256 i = 0; i < _newBatchesData.length; ++i) {
File: /state-transition/chain-deps/facets/Executor.sol

142:         for (uint256 i = 0; i < emittedL2Logs.length; i = i.uncheckedAdd(L2_TO_L1_LOG_SERIALIZE_SIZE)) {

257:         for (uint256 i = 0; i < _newBatchesData.length; i = i.uncheckedInc()) {

289:         for (uint256 i = 0; i < _newBatchesData.length; i = i.uncheckedInc()) {

311:         for (uint256 i = 0; i < _nPriorityOps; i = i.uncheckedInc()) {

351:         for (uint256 i = 0; i < nBatches; i = i.uncheckedInc()) {

405:         for (uint256 i = 0; i < committedBatchesLength; i = i.uncheckedInc()) {

580:         for (uint i = 0; i < MAX_NUMBER_OF_BLOBS; i++) {

629:         uint256 versionedHashIndex = 0;

636:         for (uint256 i = 0; i < _pubdataCommitments.length; i += PUBDATA_COMMITMENT_SIZE) {

667:         for (uint256 i = 0; i < MAX_NUMBER_OF_BLOBS; i++) {
File: /state-transition/chain-deps/facets/Getters.sol

208:         for (uint256 i = 0; i < facetsLen; i = i.uncheckedInc()) {
File: /state-transition/chain-deps/facets/Mailbox.sol

356:         for (uint256 i = 0; i < factoryDepsLen; i = i.uncheckedInc()) {
File: /state-transition/libraries/Diamond.sol

101:         for (uint256 i = 0; i < facetCutsLength; i = i.uncheckedInc()) {

138:         for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {

158:         for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {

178:         for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
File: /state-transition/libraries/TransactionValidator.sol

92:         uint256 costForPubdata = 0;
File: /system-contracts/contracts/Compressor.sol

61:             for (uint256 encodedDataPointer = 0; encodedDataPointer < encodedData.length; encodedDataPointer += 2) {

124:         uint256 numInitialWritesProcessed = 0;

127:         for (uint256 i = 0; i < _numberOfStateDiffs * STATE_DIFF_ENTRY_SIZE; i += STATE_DIFF_ENTRY_SIZE) {

159:         for (uint256 i = 0; i < _numberOfStateDiffs * STATE_DIFF_ENTRY_SIZE; i += STATE_DIFF_ENTRY_SIZE) {
File: /system-contracts/contracts/ContractDeployer.sol

247:         uint256 sumOfValues = 0;

248:         for (uint256 i = 0; i < deploymentsLength; ++i) {

253:         for (uint256 i = 0; i < deploymentsLength; ++i) {
File: /system-contracts/contracts/L1Messenger.sol

197:         uint256 calldataPtr = 0;

206:         for (uint256 i = 0; i < numberOfL2ToL1Logs; ++i) {

224:             for (uint256 i = 0; i < nodesOnCurrentLevel; ++i) {

236:         for (uint256 i = 0; i < numberOfMessages; ++i) {

254:         for (uint256 i = 0; i < numberOfBytecodes; ++i) {
File: /upgrades/BaseZkSyncUpgrade.sol

226:         for (uint256 i = 0; i < _factoryDeps.length; ++i) {

[225] ,[116] ,[135] ,[185] ,[209] ,[142] ,[257] ,[289] ,[311] ,[351] ,[405] ,[580] ,[629] ,[636] ,[667] ,[208] ,[356] ,[101] ,[138] ,[158] ,[178] ,[92] ,[61] ,[124] ,[127] ,[159] ,[247] ,[248] ,[253] ,[197] ,[206] ,[224] ,[236] ,[254] ,[226] ,

[GAS-14] Long revert strings

There are 63 instances of this issue:
File: /bridge/L1SharedBridge.sol

155:             require(msg.value == _amount, "L1SharedBridge: msg.value not equal to amount");

195:         require(bridgehub.baseToken(_chainId) != _l1Token, "ShB: baseToken deposit not supported");

427:             require(!alreadyFinalized, "Withdrawal is already finalized 2");

564:         require(_l1Token != l1WethAddress, "ShB: WETH deposit not supported 2");
File: /bridgehub/Bridgehub.sol

102:         require(!tokenIsRegistered[_token], "Bridgehub: token already registered");

132:         require(stateTransitionManager[_chainId] == address(0), "Bridgehub: chainId already registered");

225:                 require(msg.value == 0, "Bridgehub: non-eth bridge with msg.value");
File: /governance/Governance.sol

59:         require(msg.sender == address(this), "Only governance contract itself is allowed to call this function");

65:         require(msg.sender == securityCouncil, "Only security council is allowed to call this function");

172:         require(isOperationReady(id), "Operation must be ready before execution");

177:         require(isOperationReady(id), "Operation must be ready after execution");

191:         require(isOperationPending(id), "Operation must be pending before execution");

196:         require(isOperationPending(id), "Operation must be pending after execution");

216:         require(!isOperation(_id), "Operation with this proposal id already exists");

217:         require(_delay >= minDelay, "Proposed delay is less than minimum delay");

240:         require(_predecessorId == bytes32(0) || isOperationDone(_predecessorId), "Predecessor operation not completed");
File: /state-transition/StateTransitionManager.sol

256:         require(cutHashInput == initialCutHash, "StateTransition: initial cutHash mismatch");
File: /state-transition/ValidatorTimelock.sol

62:         require(msg.sender == stateTransitionManager.getChainAdmin(_chainId), "ValidatorTimelock: only chain admin");

68:         require(validators[_chainId][msg.sender] == true, "ValidatorTimelock: only validator");
File: /state-transition/chain-deps/facets/Admin.sol

90:         require(s.totalBatchesCommitted == 0, "AdminFacet: set validium only after genesis"); // Validium mode can be set only before the first batch is committed
File: /state-transition/chain-deps/facets/Executor.sol

616:         require(success, "failed to call point evaluation precompile");
File: /state-transition/chain-deps/facets/Mailbox.sol

39:         require(s.chainId == ERA_CHAIN_ID, "transferEthToSharedBridge only available for Era on mailbox");

158:         require(s.baseTokenGasPriceMultiplierDenominator > 0, "Mailbox: baseTokenGasPriceDenominator not set");

185:         require(s.chainId == ERA_CHAIN_ID, "finalizeEthWithdrawal only available for Era on mailbox");

206:         require(s.chainId == ERA_CHAIN_ID, "legacy interface only available for era token");
File: /state-transition/chain-deps/facets/ZkSyncStateTransitionBase.sol

22:         require(s.validators[msg.sender], "StateTransition Chain: not validator");

27:         require(msg.sender == s.stateTransitionManager, "StateTransition Chain: not state transition manager");

32:         require(msg.sender == s.bridgehub, "StateTransition Chain: not bridgehub");

53:         require(msg.sender == s.baseTokenBridge, "Only shared bridge can call this function");
File: /system-contracts/contracts/AccountCodeStorage.sol

26:         require(msg.sender == address(DEPLOYER_SYSTEM_CONTRACT), "Callable only by the deployer system contract");

37:         require(Utils.isContractConstructing(_hash), "Code hash is not for a contract on constructor");

48:         require(Utils.isContractConstructed(_hash), "Code hash is not for a constructed contract");

57:         require(Utils.isContractConstructing(codeHash), "Code hash is not for a contract on constructor");
File: /system-contracts/contracts/ComplexUpgrader.sol

22:         require(msg.sender == FORCE_DEPLOYER, "Can only be called by FORCE_DEPLOYER");
File: /system-contracts/contracts/Compressor.sol

63:                 require(indexOfEncodedChunk < dictionary.length, "Encoded chunk index is out of bounds");

68:                 require(encodedChunk == realChunk, "Encoded chunk does not match the original bytecode");

119:         require(_enumerationIndexSize <= MAX_ENUMERATION_INDEX_SIZE, "enumeration index size is too large");

156:         require(numInitialWritesProcessed == numberOfInitialWrites, "Incorrect number of initial storage diffs");

187:         require(stateDiffPtr == _compressedStateDiffs.length, "Extra data in _compressedStateDiffs");

230:                 require(convertedValue == _finalValue, "transform or no compression: compressed and final mismatch");
File: /system-contracts/contracts/ContractDeployer.sol

251:         require(msg.value == sumOfValues, "`value` provided is not equal to the combined `value`s of deployments");

265:         require(uint160(_newAddress) > MAX_SYSTEM_CONTRACT_ADDRESS, "Can not deploy contracts in kernel space");

350:             require(value == 0, "The value must be zero if we do not call the constructor");
File: /system-contracts/contracts/DefaultAccount.sol

100:         require(totalRequiredBalance <= address(this).balance, "Not enough balance for fee + value");

202:         require(success, "Failed to pay the fee to the operator");
File: /system-contracts/contracts/L1Messenger.sol

315:         require(calldataPtr == _totalL2ToL1PubdataAndStateDiffs.length, "Extra data in the totalL2ToL1Pubdata array");
File: /system-contracts/contracts/NonceHolder.sol

66:         require(_value <= MAXIMAL_MIN_NONCE_INCREMENT, "The value for incrementing the nonce is too high");
File: /system-contracts/contracts/SystemContext.sol

242:         require(_isFirstInBatch, "Upgrade transaction must be first");

245:         require(_l2BlockNumber > 0, "L2 block number is never expected to be zero");

249:             require(correctPrevBlockHash == _expectedPrevL2BlockHash, "The previous L2 block hash is incorrect");

287:             require(_maxVirtualBlocksToCreate > 0, "Can't initialize the first virtual block");

355:             require(_maxVirtualBlocksToCreate > 0, "There must be a virtual block created at the start of the batch");

367:             require(!_isFirstInBatch, "Can not reuse L2 block number from the previous batch");

368:             require(currentL2BlockTimestamp == _l2BlockTimestamp, "The timestamp of the same L2 block must be same");

373:             require(_maxVirtualBlocksToCreate == 0, "Can not create virtual blocks in the middle of the miniblock");

385:             require(_expectedPrevL2BlockHash == pendingL2BlockHash, "The current L2 block hash is incorrect");

413:         require(currentBatchNumber > 0, "The current batch number must be greater than 0");

452:         require(previousBatchNumber + 1 == _expectedNewNumber, "The provided block number is not correct");
File: /system-contracts/contracts/libraries/SystemContractHelper.sol

319:         require(index < 10, "There are only 10 accessible registers");
File: /system-contracts/contracts/libraries/TransactionHelper.sol

363:         require(_transaction.paymasterInput.length >= 4, "The standard paymaster input must be at least 4 bytes long");
File: /upgrades/BaseZkSyncUpgrade.sol

190:         require(_l2ProtocolUpgradeTx.txType == SYSTEM_UPGRADE_L2_TX_TYPE, "L2 system upgrade tx type is wrong");

249:         require(s.l2SystemContractsUpgradeTxHash == bytes32(0), "Previous upgrade has not been finalized");
File: /upgrades/BaseZkSyncUpgradeGenesis.sol

33:         require(s.l2SystemContractsUpgradeTxHash == bytes32(0), "Previous upgrade has not been finalized");

[155] ,[195] ,[427] ,[564] ,[102] ,[132] ,[225] ,[59] ,[65] ,[172] ,[177] ,[191] ,[196] ,[216] ,[217] ,[240] ,[256] ,[62] ,[68] ,[90] ,[616] ,[39] ,[158] ,[185] ,[206] ,[22] ,[27] ,[32] ,[53] ,[26] ,[37] ,[48] ,[57] ,[22] ,[63] ,[68] ,[119] ,[156] ,[187] ,[230] ,[251] ,[265] ,[350] ,[100] ,[202] ,[315] ,[66] ,[242] ,[245] ,[249] ,[287] ,[355] ,[367] ,[368] ,[373] ,[385] ,[413] ,[452] ,[319] ,[363] ,[190] ,[249] ,[33] ,

[GAS-15] Constructors can be marked payable

Payable functions cost less gas to execute, since the compiler does not have to add extra checks to ensure that a payment was not provided. A constructor can safely be marked as payable, since only the deployer would be able to pass funds, and the project itself would not pass any funds.

There are 17 instances of this issue:
File: /bridge/L1ERC20Bridge.sol

55:     constructor(IL1SharedBridge _sharedBridge) reentrancyGuardInitializer {

76:         bytes32 constructorInputHash = keccak256(abi.encode(l2TokenBeacon, ""));

79:         return L2ContractHelper.computeCreate2Address(l2Bridge, salt, l2TokenProxyBytecodeHash, constructorInputHash);
File: /bridge/L1SharedBridge.sol

90:     constructor(
File: /bridgehub/Bridgehub.sol

38:     constructor() reentrancyGuardInitializer {}
File: /common/libraries/L2ContractHelper.sol

64:         bytes32 _constructorInputHash

68:             bytes.concat(CREATE2_PREFIX, senderBytes, _salt, _bytecodeHash, _constructorInputHash)
File: /governance/Governance.sol

41:     constructor(address _admin, address _securityCouncil, uint256 _minDelay) {
File: /state-transition/StateTransitionManager.sol

58:     constructor(address _bridgehub) reentrancyGuardInitializer {
File: /state-transition/ValidatorTimelock.sol

55:     constructor(address _initialOwner, uint32 _executionDelay) {
File: /state-transition/chain-deps/DiamondInit.sol

19:     constructor() reentrancyGuardInitializer {}
File: /state-transition/chain-deps/DiamondProxy.sol

11:     constructor(uint256 _chainId, Diamond.DiamondCutData memory _diamondCut) {
File: /system-contracts/contracts/AccountCodeStorage.sol

37:         require(Utils.isContractConstructing(_hash), "Code hash is not for a contract on constructor");

57:         require(Utils.isContractConstructing(codeHash), "Code hash is not for a contract on constructor");
File: /system-contracts/contracts/ContractDeployer.sol

103:         bytes32 constructorInputHash = EfficientCall.keccak(_input);

106:             bytes.concat(CREATE2_PREFIX, bytes32(uint256(uint160(_sender))), _salt, _bytecodeHash, constructorInputHash)

350:             require(value == 0, "The value must be zero if we do not call the constructor");

[55] ,[76] ,[79] ,[90] ,[38] ,[64] ,[68] ,[41] ,[58] ,[55] ,[19] ,[11] ,[37] ,[57] ,[103] ,[106] ,[350] ,

If needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that returns a tuple of the values of all currently-public constants. Saves 3406-3606 gas in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it's used, and not adding another entry to the method ID table

Instances of this issue:

File: /state-transition/ValidatorTimelock.sol

26:     string public constant override getName = "ValidatorTimelock";
File: /state-transition/chain-deps/facets/Admin.sol

20:     string public constant override getName = "AdminFacet";
File: /state-transition/chain-deps/facets/Executor.sol

27:     string public constant override getName = "ExecutorFacet";
File: /state-transition/chain-deps/facets/Getters.sol

25:     string public constant override getName = "GettersFacet";
File: /state-transition/chain-deps/facets/Mailbox.sol

35:     string public constant override getName = "MailboxFacet";

[26] ,[20] ,[27] ,[25] ,[35] ,

[GAS-19] Use shift Right/Left instead of division/multiplication if possible

Instances of this issue:

File: /state-transition/StateTransitionManager.sol

11: import {IStateTransitionManager, StateTransitionManagerInitializeData} from "./IStateTransitionManager.sol";
File: /state-transition/chain-deps/DiamondInit.sol

11: 
File: /system-contracts/contracts/Compressor.sol

56:             require(

[11] ,[11] ,[56] ,

Instances of this issue:

File: /common/libraries/L2ContractHelper.sol

41:         require(version == 1 && _bytecodeHash[1] == bytes1(0), "zf"); // Incorrectly formatted bytecodeHash

[41] ,

[GAS-22] Using this to access functions results in an external call, wasting gas

External calls have an overhead of 100 gas, which can be avoided by not referencing the function using this. Contracts are allowed to override their parents' functions and change the visibility from external to public, so make this change if it's required in order to call the function internally.

Instances of this issue:

File: /system-contracts/contracts/ContractDeployer.sol

254:             this.forceDeployOnAddress{value: _deployments[i].value}(_deployments[i], msg.sender); //@audit cache deployment[i]

[254] ,

The unchecked keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas per loop

Instances of this issue:

File: /state-transition/chain-deps/facets/Executor.sol

580:         for (uint i = 0; i < MAX_NUMBER_OF_BLOBS; i++) {

667:         for (uint256 i = 0; i < MAX_NUMBER_OF_BLOBS; i++) {
File: /system-contracts/contracts/Compressor.sol

135:             numInitialWritesProcessed++;

144:             stateDiffPtr++;
File: /system-contracts/contracts/L1Messenger.sol

109:         numberOfLogsToProcess++;

284:         calldataPtr++;

290:         calldataPtr++;

[580] ,[667] ,[135] ,[144] ,[109] ,[284] ,[290] ,

[GAS-24] Use != 0 instead of > 0 for unsigned integer comparison

There are 25 instances of this issue:
File: /bridge/L1SharedBridge.sol

129:             require(amount > 0, "ShB: 0 amount to transfer");

158:             require(msg.value == 0, "ShB m.v > 0 b d.it");

202:             require(msg.value == 0, "ShB m.v > 0 for BH d.it 2");

327:         require(_amount > 0, "y1");
File: /bridgehub/Bridgehub.sol

329:         } else if (_refundRecipient.code.length > 0) {
File: /state-transition/chain-deps/facets/Executor.sol

429:         if (_proof.serializedProof.length > 0) {

593:         return (_bitMap & (1 << _index)) > 0;

631:         require(_pubdataCommitments.length > 0, "pl");
File: /state-transition/chain-deps/facets/Mailbox.sol

158:         require(s.baseTokenGasPriceMultiplierDenominator > 0, "Mailbox: baseTokenGasPriceDenominator not set");

277:         if (refundRecipient.code.length > 0) {
File: /state-transition/libraries/Diamond.sol

107:             require(selectors.length > 0, "B"); // no functions for diamond cut

132:         require(_facet.code.length > 0, "G");

155:         require(_facet.code.length > 0, "K");
File: /state-transition/libraries/Merkle.sol

24:         require(pathLength > 0, "xc");
File: /system-contracts/contracts/AccountCodeStorage.sol

102:         if (codeHash == 0x00 && NONCE_HOLDER_SYSTEM_CONTRACT.getRawNonce(account) > 0) {
File: /system-contracts/contracts/ComplexUpgrader.sol

24:         require(_delegateTo.code.length > 0, "Delegatee is an EOA");
File: /system-contracts/contracts/ContractDeployer.sol

303:         require(knownCodeMarker > 0, "The code hash is not known");

332:             if (value > 0) {

339:             if (value > 0) {
File: /system-contracts/contracts/NonceHolder.sol

156:         return (_nonce < getMinNonce(_address) || nonceValues[addressAsKey][_nonce] > 0);
File: /system-contracts/contracts/SystemContext.sol

152:             currentVirtualBlockUpgradeInfo.virtualBlockFinishL2Block > 0

245:         require(_l2BlockNumber > 0, "L2 block number is never expected to be zero");

287:             require(_maxVirtualBlocksToCreate > 0, "Can't initialize the first virtual block");

355:             require(_maxVirtualBlocksToCreate > 0, "There must be a virtual block created at the start of the batch");

413:         require(currentBatchNumber > 0, "The current batch number must be greater than 0");

[129] ,[158] ,[202] ,[327] ,[329] ,[429] ,[593] ,[631] ,[158] ,[277] ,[107] ,[132] ,[155] ,[24] ,[102] ,[24] ,[303] ,[332] ,[339] ,[156] ,[152] ,[245] ,[287] ,[355] ,[413] ,