require(
hasRole(MINTER_ROLE, _msgSender()),
"JPEG: must have minter role to mint"
);
Use a more recent version of solidity
Use a solidity version of at least 0.8.2 to get compiler automatic inlining
Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads
Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require() strings
Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
State variables should be cached in stack variables rather than re-reading them from storage
The instances below point to the second access of a state variable within a function.
Less obvious optimizations include having local storage variables of mappings within state variable mappings or mappings within state variable structs, having local storage variables of structs within mappings, or having local caches of state variable contracts/addresses.
require(
_creditLimitRate.denominator > 0 &&
//denominator can be equal to the numerator in some cases (stablecoins used as collateral)
_creditLimitRate.denominator >= _creditLimitRate.numerator,
"invalid_rate"
);
Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead
When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.
Functions guaranteed to revert when called by normal users can be marked payable
If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided.
Not using the named return variables when a function returns, wastes deployment gas
require()
/revert()
strings longer than 32 bytes cost extra gasUse a more recent version of solidity
Use a solidity version of at least 0.8.2 to get compiler automatic inlining Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than
revert()/require()
strings Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return valueUsing
bool
s for storage incurs overheadhttps://github.com/OpenZeppelin/openzeppelin-contracts/blob/58f635312aa21f947cae5f8578638a85aa2519f5/contracts/security/ReentrancyGuard.sol#L23-L27
Use
delete
rather than assigning zero to a mapping to get a gas refundUsing
> 0
costs more gas than!= 0
when used on auint
in arequire()
statement<array>.length
should not be looked up in every loop of afor
-loopEven memory arrays incur the overhead of bit tests and bit shifts to calculate the array length
It costs more gas to initialize variables to zero than to let the default of zero be applied
State variables should be cached in stack variables rather than re-reading them from storage
The instances below point to the second access of a state variable within a function. Less obvious optimizations include having local storage variables of mappings within state variable mappings or mappings within state variable structs, having local storage variables of structs within mappings, or having local caches of state variable contracts/addresses.
Using
calldata
instead ofmemory
for read-only arguments inexternal
functions saves gas++i
/i++
should beunchecked{++i}
/unchecked{++i}
when it is not possible for them to overflow, as is the case when used infor
- andwhile
-loops++i
costs less gas than++i
, especially when it's used infor
-loops (--i
/i--
too)Splitting
require()
statements that use&&
saves gasSee this issue for an example
Usage of
uints
/ints
smaller than 32 bytes (256 bits) incurs overheadhttps://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Use a larger size then downcast where needed
abi.encode()
is less efficient thanabi.encodePacked()
Expressions for constant values such as a call to
keccak256()
, should useimmutable
rather thanconstant
See this issue for a detail description of the issue
Using
private
rather thanpublic
for constants, saves gasIf needed, the value can be read from the verified contract source code
Don't compare boolean expressions to boolean literals
if (<x> == true)
=>if (<x>)
,if (<x> == false)
=>if (!<x>)
Duplicated
require()
/revert()
checks should be refactored to a modifier or functionStack variable used as a cheaper cache for a state variable is only used once
If the variable is only accessed once, it's cheaper to use the state variable directly that one time
State variables only set in the constructor should be declared
immutable
require()
orrevert()
statements that check input arguments should be at the top of the functionChecks that involve constants should come before checks that involve state variables
Functions guaranteed to revert when called by normal users can be marked
payable
If a function modifier such as
onlyOwner
is used, the function will revert if a normal user tries to pay the function. Marking the function aspayable
will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided.