Gas Optimizations #121
Labels
bug
Something isn't working
G (Gas Optimization)
sponsor acknowledged
Technically the issue is correct, but we're not going to resolve it for XYZ reasons
valid
Gas Report
Table of Contents
Comparison Operators
IMPACT
In the EVM, there is no opcode for
>=
or<=
.When using greater than or equal, two operations are performed:
>
and=
.Using strict comparison operators hence saves gas, approximately
20
gas per comparison.PROOF OF CONCEPT
Instances include:
MyStrategy.sol
max >= _amount.mul(9_980).div(MAX_BPS)
TOOLS USED
Manual Analysis
MITIGATION
Replace
>=
with>
. In this case1
is negligible compared to the value compared, we can omit the increment.Custom Errors
IMPACT
Custom errors from Solidity 0.8.4 are cheaper than revert strings (cheaper deployment cost and runtime cost when the revert condition is met) while providing the same amount of information, as explained here
Custom errors are defined using the error statement.
It not only saves gas upon deployment -
~5500
gas saved per custom error instead of a require statement, but it is also cheaper in a function call,22
gas saved per require statement replaced with a custom error.PROOF OF CONCEPT
Instances include:
MyStrategy.sol
TOOLS USED
Manual Analysis
MITIGATION
Replace require and revert statements with custom errors.
For instance:
Replace
with
and define the custom error in the contract
Default value initialization
IMPACT
If a variable is not set/initialized, it is assumed to have the default value (0, false, 0x0 etc depending on the data type).
Explicitly initializing it with its default value is an anti-pattern and wastes
22
gas per variable initialized.PROOF OF CONCEPT
Instances include:
MyStrategy.sol
uint i = 0
uint i = 0
uint i = 0
TOOLS USED
Manual Analysis
MITIGATION
Remove explicit initialization for default values.
Inline functions
PROBLEM
When we define internal functions to perform computation:
When it does not affect readability, it is recommended to inline functions in order to save gas. It saves ~
3,000
gas per inlined function upon deployment, and30
gas per function call.PROOF OF CONCEPT
Instances include:
MyStrategy.sol
function _deposit(uint256 _amount)
function _getBalance()
function _getPricePerFullShare())
function _notifyBribesProcessor()
TOOLS USED
Manual Analysis
MITIGATION
Inline these functions where they are called
Prefix increments
IMPACT
Prefix increments are cheaper than postfix increments: it returns the incremented variable instead of returning a temporary variable storing the initial value of the variable. It saves
5
gas per iterationPROOF OF CONCEPT
Instances include:
MyStrategy.sol
i++
i++
i++
TOOLS USED
Manual Analysis
MITIGATION
change
variable++
to++variable
.Require instead of AND
IMPACT
Require statements including conditions with the
&&
operator can be broken down in multiple require statements to save gas. It saves50
gas per require statement broken down.PROOF OF CONCEPT
Instances include:
MyStrategy.sol
require(balanceOfPool() == 0 && LOCKER.balanceOf(address(this)) == 0,"You have to wait for unlock or have to manually rebalance out of it")
TOOLS USED
Manual Analysis
MITIGATION
Break down the statements in multiple require statements.
You can also improve gas savings by using custom errors
Revert strings length
IMPACT
Revert strings larger than 32-bytes will incur an extra cost upon deployment. It costs ~
9,500
extra gas per extra 32-byte upon deployment.PROOF OF CONCEPT
Instances include:
MyStrategy.sol
require(balanceOfPool() == 0 && LOCKER.balanceOf(address(this)) == 0,"You have to wait for unlock or have to manually rebalance out of it")
TOOLS USED
Manual Analysis
MITIGATION
Reduce the string message to something smaller than 32-byte to save approximately
19,000
gas upon deploymentTight Variable Packing
PROBLEM
Solidity contracts have contiguous 32 bytes (256 bits) slots used in storage.
By arranging the variables, it is possible to minimize the number of slots used within a contract's storage and therefore reduce deployment costs.
address type variables are each of 20 bytes size (way less than 32 bytes). However, they here take up a whole 32 bytes slot (they are contiguous).
As bool type variables are of size 1 byte, there's a slot here that can get saved by moving one address closer to a bool. This saves a gsset -
20,000
gas.PROOF OF CONCEPT
Instances include:
MyStrategy.sol
TOOLS USED
Manual Analysis
MITIGATION
Place
BADGER
beforewithdrawalSafetyCheck
to save one storage slotUse a more recent version of Solidity
PROBLEM
Use a more recent version of solidity. The advantages here are: built-in overflow/underflow checks (>= 0.8.0) Low level inliner (>= 0.8.2) Cheaper runtime gas (especially relevant when the contract has small functions) Optimizer improvements in packed structs (>= 0.8.3) custom errors (>= 0.8.4), external calls skipping contract existence (>= 0.8.10).
PROOF OF CONCEPT
Instances include:
MyStrategy.sol
TOOLS USED
Manual Analysis
MITIGATION
Update the solidity version.
The text was updated successfully, but these errors were encountered: