Explicitly unchecking the arithmetic operation that does not overflow by wrapping it in unchecked {}
costs less gas than implicitly checking it. Please consider changing the following ++i
to i = i.uncheckedInc()
, where uncheckedInc
is from ethereum\contracts\common\libraries\UncheckedMath.sol
.
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) {
x = x + y costs less gas than x += y. s.diamondCutStorage.currentProposalId += 1
can be changed to s.diamondCutStorage.currentProposalId = s.diamondCutStorage.currentProposalId + 1
in the following proposeDiamondCut
function.
function proposeDiamondCut(Diamond.FacetCut[] calldata _facetCuts, address _initAddress) external onlyGovernor {
require(s.diamondCutStorage.proposedDiamondCutTimestamp == 0, "a3"); // proposal already exists
// NOTE: governor commits only to the `facetCuts` and `initAddress`, but not to the calldata on `initAddress` call.
// That means the governor can call `initAddress` with ANY calldata while executing the upgrade.
s.diamondCutStorage.proposedDiamondCutHash = keccak256(abi.encode(_facetCuts, _initAddress));
s.diamondCutStorage.proposedDiamondCutTimestamp = block.timestamp;
s.diamondCutStorage.currentProposalId += 1;
emit DiamondCutProposal(_facetCuts, _initAddress);
}
When a function has unused named return, unnecessary deployment gas is used. Please consider removing storedNewBlock
that is not used in the following _commitOneBlock
function
function _commitOneBlock(StoredBlockInfo memory _previousBlock, CommitBlockInfo calldata _newBlock)
internal
view
returns (StoredBlockInfo memory storedNewBlock)
{
...
return
StoredBlockInfo(
_newBlock.blockNumber,
_newBlock.newStateRoot,
_newBlock.indexRepeatedStorageChanges,
_newBlock.numberOfLayer1Txs,
_newBlock.priorityOperationsHash,
_newBlock.l2LogsTreeRoot,
_newBlock.timestamp,
commitment
);
}
Converting a variable type when not needed costs more unnecessary gas. In the following l2TokenAddress
function, l2TokenFactory
is already an address
so executing address(l2TokenFactory)
is not necessary and wastes run-time gas if this function is called by another non-view function. If this function will not be called by another non-view function, unnecessary deployment gas is still used.
function l2TokenAddress(address _l1Token) public view returns (address) {
bytes32 constructorInputHash = keccak256(abi.encode(address(l2TokenFactory), ""));
bytes32 salt = bytes32(uint256(uint160(_l1Token)));
return L2ContractHelper.computeCreate2Address(l2Bridge, salt, l2ProxyTokenBytecodeHash, constructorInputHash);
}