Switching from non-zero to non-zero is more efficient
By switching from non-zero to non-zero value, expensive SSTORE from 0/false to non-zero can be avoided.
and when boolean is used, writing to storage costs more than uint256 as each write operation has to perform extra read operation to correctly place the boolean value in the slot.
So switching from 0/false to 1/true can be replaced by 1 and 2
Revert strings that are longer than 32 bytes requires at least one additional mstore, along with additional overhead for computing memory offset, etc.
Shortening revert strings to fit in 32 bytes will decrease deployment time gas and will decrease runtime gas when the revert condition is met.
require(contracts[msg.sender], "Contract is not approved to make transfers");
Comparison with bool literal
Comparison to boolean literal is more expensive than directly checking the value.
Comparison with false can be replaced by using the ! operator with the value
Marking constants as private/internal saves gas on deployment as compiler does not have to create a getter function for these variables, these variables can still be read from the verfied source code or the bytecode.
If data can fit into 32 bytes, then using bytes32 instead of string is cheaper, as string is a dynamically sized data structures and therefore consumes more gas.
If an expression cannnot overflow/underflow it can be placed in a unchecked block to avoid the implicit overflow/underflow checks introduced in 0.8.0 and save gas
require(totalFee <= price, "Total amount of fees are more than the price");
/* Amount that will be received by seller. */
uint256 receiveAmount = price - totalFee;
Variables less than 32 bytes
Due to how the EVM natively works on 256 bit numbers, using a 8 bit number in for-loops introduces additional costs as the EVM has to properly enforce the limits of this smaller type.
When variables are not set, it is assumed to have it's default value(0 for uint, false for bool, address(0) for address). Explicitly initializing it with its default value is an anti-pattern and wastes gas.
Switching from non-zero to non-zero is more efficient
By switching from non-zero to non-zero value, expensive SSTORE from 0/false to non-zero can be avoided. and when boolean is used, writing to storage costs more than uint256 as each write operation has to perform extra read operation to correctly place the boolean value in the slot. So switching from 0/false to 1/true can be replaced by 1 and 2
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/86bd4d73896afcb35a205456e361436701823c7a/contracts/security/ReentrancyGuard.sol#L29-L33
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/lib/ReentrancyGuarded.sol#L13
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L43
Reduce size of revert string
Revert strings that are longer than 32 bytes requires at least one additional mstore, along with additional overhead for computing memory offset, etc. Shortening revert strings to fit in 32 bytes will decrease deployment time gas and will decrease runtime gas when the revert condition is met.
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/ExecutionDelegate.sol#L22
Comparison with bool literal
Comparison to boolean literal is more expensive than directly checking the value. Comparison with
false
can be replaced by using the!
operator with the valuehttps://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/ExecutionDelegate.sol#L77
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/ExecutionDelegate.sol#L92
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/ExecutionDelegate.sol#L108
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/ExecutionDelegate.sol#L124
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L267
constants can be internal/private
Marking constants as private/internal saves gas on deployment as compiler does not have to create a getter function for these variables, these variables can still be read from the verfied source code or the bytecode.
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/lib/EIP712.sol#L20-L33
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L57
Cache array length
Array length can be cached in a variable and used in the loop instead of read from storage in every iteration
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/lib/EIP712.sol#L77
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/lib/MerkleVerifier.sol#L38
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L199
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L476
Function used once can be inlined
Functions used once can be inlined to save gas on performing JUMP between the functions.
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L548
bytes32 instead of string
If data can fit into 32 bytes, then using bytes32 instead of string is cheaper, as string is a dynamically sized data structures and therefore consumes more gas.
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L57
Custom errors
Custom error from solidity 0.8.4 are cheaper than revert strings with cheaper deployment cost and runtime cost when the revert condition is met.
https://blog.soliditylang.org/2021/04/21/custom-errors/
Use
unchecked
to save gasIf an expression cannnot overflow/underflow it can be placed in a unchecked block to avoid the implicit overflow/underflow checks introduced in 0.8.0 and save gas
https://docs.soliditylang.org/en/v0.8.10/control-structures.html#checked-or-unchecked-arithmetic
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L485
Variables less than 32 bytes
Due to how the EVM natively works on 256 bit numbers, using a 8 bit number in for-loops introduces additional costs as the EVM has to properly enforce the limits of this smaller type.
https://docs.soliditylang.org/en/v0.8.0/internals/layout_in_storage.html#layout-of-state-variables-in-storage
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L199
Avoid initialization with default values
When variables are not set, it is assumed to have it's default value(0 for uint, false for bool, address(0) for address). Explicitly initializing it with its default value is an anti-pattern and wastes gas.
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/lib/ReentrancyGuarded.sol#L10
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L475
Use
++x
instead ofx += 1
Pre-increment
++x
costs less when compared tox += 1
orx++
for unsigned integershttps://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L208
Use function arguments instead of storage variables in event emits
In event emits using local variables or function arguments instead of storage variable can avoid storage read and save gas
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L221
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L230
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L239
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L247
Unnecessary variables
Variables
_v
,_r
and_s
are unnecessary and the values can be directly assigned to the variabeslv
,r
ands
https://github.com/code-423n4/2022-10-blur/blob/2fdaa6e13b544c8c11d1c022a575f16c3a72e3bf/contracts/BlurExchange.sol#L388
can be replaced with