Use uint256(1)and uint256(2)for true/false to avoid a Gwarmaccess (100 gas) for the extra SLOAD, and to avoid Gsset (20000 gas) when changing from falseto true, after having been truein the past
Multiple address mappings can be combined into a single mapping of an address to a struct, where appropriate
Saves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot
Splitting require() statements that use && saves gas
Instead of using the && operator in a single require statement to check multiple conditions, I suggest using multiple require statements with 1 condition per require statement (saving 3 gas per &):
Use custom errors rather than revert()/require() strings to save deployment gas
Custom errors are available from solidity version 0.8.4.
Custom errors from Solidity 0.8.4 are cheaper than revert strings (cheaper deployment cost and runtime cost when the revert condition is met).
Custom errors save ~50 gas each time they’re hit by avoiding having to allocate and store the revert string. Not defining the strings also save
For example: File: contracts/governance/Governed.sol
24 require(msg.sender == governor, "Only Governor can call");
Using
bool
s for storage incurs overheadUse
uint256(1)
anduint256(2)
for true/false to avoid a Gwarmaccess (100 gas) for the extra SLOAD, and to avoid Gsset (20000 gas) when changing fromfalse
totrue
, after having beentrue
in the pasthttps://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/governance/Pausable.sol#L8
File: contracts/governance/Pausable.sol #2 10 bool internal _paused;
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/governance/Pausable.sol#L10
File: contracts/gateway/L1GraphTokenGateway.sol #3 35 mapping(address => bool) public callhookWhitelist;
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/gateway/L1GraphTokenGateway.sol#L35
Multiple
address
mappings can be combined into a single mapping of anaddress
to astruct
, where appropriateSaves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot
REQUIRE()
STATEMENTS SHOULD HAVE DESCRIPTIVE REASON STRINGShttps://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/upgrades/GraphProxyAdmin.sol#L47
File: contracts/upgrades/GraphProxyAdmin.sol #2 34 require(success);
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/upgrades/GraphProxyAdmin.sol#L34
Using
> 0
costs more gas than!= 0
when used on auint
in arequire()
statementThis change saves 6 gas per instance
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/l2/gateway/L2GraphTokenGateway.sol#L146
File: contracts/gateway/L1GraphTokenGateway.sol #2 201 require(_amount > 0, "INVALID_ZERO_AMOUNT");
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/gateway/L1GraphTokenGateway.sol#L201
File: contracts/gateway/L1GraphTokenGateway.sol #3 201 require(maxSubmissionCost > 0, "NO_SUBMISSION_COST");
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/gateway/L1GraphTokenGateway.sol#L217
Splitting
require()
statements that use&&
saves gasInstead of using the
&&
operator in a single require statement to check multiple conditions, I suggest using multiple require statements with 1 condition per require statement (saving 3 gas per&
):https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/governance/Governed.sol#L55
File: contracts/upgrades/GraphProxy.sol #2 143 _pendingImplementation != address(0) && msg.sender == _pendingImplementation,
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/upgrades/GraphProxy.sol#L143
File: contracts/gateway/L1GraphTokenGateway.sol #3 142 require(_escrow != address(0) && Address.isContract(_escrow), "INVALID_ESCROW");
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/gateway/L1GraphTokenGateway.sol#L142
abi.encode()
is less efficient thanabi.encodePacked()
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/l2/token/GraphTokenUpgradeable.sol#L88
File: contracts/l2/token/GraphTokenUpgradeable.sol #2 162 abi.encode(
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/l2/token/GraphTokenUpgradeable.sol#L162
File: contracts/l2/gateway/L2GraphTokenGateway.sol #3 174 return abi.encode(id);
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/l2/gateway/L2GraphTokenGateway.sol#L174
Inline
a modifier that's only used onceAs
onlyGovernor()
is only used once in this contract (infunction transferOwnership()
), it should get inlined to save gas without losing readability:As
onlyMinter()
is only used once in this contract (infunction mint()
), it should get inlined to save gas without losing readability:Use custom errors rather than
revert()
/require()
strings to save deployment gasCustom errors are available from solidity version 0.8.4. Custom errors from Solidity 0.8.4 are cheaper than revert strings (cheaper deployment cost and runtime cost when the revert condition is met).
Custom errors save ~50 gas each time they’re hit by avoiding having to allocate and store the revert string. Not defining the strings also save
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/governance/Governed.sol#L24
Below instances are also affected :
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/governance/Governed.sol#L41
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/governance/Governed.sol#L56
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/l2/token/L2GraphToken.sol#L36
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/l2/token/L2GraphToken.sol#L49
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/l2/token/L2GraphToken.sol#L60
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/l2/token/L2GraphToken.sol#L70
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/upgrades/GraphProxyStorage.sol#L62
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/upgrades/GraphProxy.sol#L141
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/l2/token/GraphTokenUpgradeable.sol#L106
https://github.com/code-423n4/2022-10-thegraph/blob/main/contracts/l2/token/GraphTokenUpgradeable.sol#L115