Solidity does not recognize null as a value, so uint variables are initialized to zero. Setting a uint variable to zero is redundant and can waste gas.
Remove the redundant zero initialization
uint256 i; instead of uint256 i = 0;
[G-02] Split up require statements instead of &&
Combining require statement conditions with && logic uses unnecessary gas. It is better to split up each part of the logical statement into a separate require statements
Use separate require statements instead of concatenating with &&
[G-03] Cache array length before loop
Caching the array length outside a loop saves reading it on each iteration, as long as the array's length is not changed during the loop. This saves gas.
Shorten all require strings to less than 32 characters
[G-06] Use prefix not postfix in loops
Using a prefix increment (++i) instead of a postfix increment (i++) saves gas for each loop cycle and so can have a big gas impact when the loop executes on a large number of elements.
For loops that use i++ do not need to use safemath for this operation because the loop would run out of gas long before this point. Making this addition operation unsafe using unchecked saves gas.
Sample code to make the for loop increment unsafe
for (uint i = 0; i < length; i = unchecked_inc(i)) {
// do something that doesn't change the value of i
}
function unchecked_inc(uint i) returns (uint) {
unchecked {
return i + 1;
}
}
Use the assembly iszero evm opcode to compare values to zero
[G-09] Use uint not bool
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.
A solidity version before 0.8.X is used. The latest release of solidity includes changes that can provide gas savings. The improvements include:
Safemath by default from 0.8.0 (can be more gas efficient than some library based safemath).
Low level inliner from 0.8.2, leads to cheaper runtime gas. Especially relevant when the contract has small functions. For example, OpenZeppelin libraries typically have a lot of small helper functions and if they are not inlined, they cost an additional 20 to 40 gas because of 2 extra jump instructions and additional stack operations needed for function calls.
Optimizer improvements in packed structs: Before 0.8.3, storing packed structs, in some cases used an additional storage read operation. After EIP-2929, if the slot was already cold, this means unnecessary stack operations and extra deploy time costs. However, if the slot was already warm, this means additional cost of 100 gas alongside the same unnecessary stack operations and extra deploy time costs.
Custom errors from 0.8.4, leads to cheaper deploy time cost and run time cost. Note: the run time cost is only relevant when the revert condition is met. In short, replace revert strings by custom errors.
Solidity version 0.8.13 can save more gas with Yul IR pipeline
Write some or all of the contracts in vyper to save gas
[G-13] Use abi.encodePacked() not abi.encode()
Changing abi.encode to abi.encodePacked can save gas. abi.encode pads extra null bytes at the end of the call data which is normally unnecessary. In general, abi.encodePacked is more gas-efficient.
[G-01] Redundant zero initialization
Solidity does not recognize null as a value, so uint variables are initialized to zero. Setting a uint variable to zero is redundant and can waste gas.
There were many places where an int is initialized to zero https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L118 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L300 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L317
Recommended Mitigation Steps
Remove the redundant zero initialization
uint256 i;
instead ofuint256 i = 0;
[G-02] Split up require statements instead of &&
Combining require statement conditions with && logic uses unnecessary gas. It is better to split up each part of the logical statement into a separate require statements
https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L185
Recommended Mitigation Steps
Use separate require statements instead of concatenating with &&
[G-03] Cache array length before loop
Caching the array length outside a loop saves reading it on each iteration, as long as the array's length is not changed during the loop. This saves gas.
This was found in many places https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L299 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L300 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L317
Recommended Mitigation Steps
Cache the array length before the for loop
[G-04] Use != 0 instead of > 0
Using
> 0
uses slightly more gas than using!= 0
. Use!= 0
when comparing uint variables to zero, which cannot hold values below zeroLocations where this was found include https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L230 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L279 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L323 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L330 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L387
Recommended Mitigation Steps
Replace
> 0
with!= 0
to save gas[G-05] Short require strings save gas
Strings in solidity are handled in 32 byte chunks. A require string longer than 32 bytes uses more gas. Shortening these strings will save gas.
Locations where this was found include https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L186
Recommended Mitigation Steps
Shorten all require strings to less than 32 characters
[G-06] Use prefix not postfix in loops
Using a prefix increment (++i) instead of a postfix increment (i++) saves gas for each loop cycle and so can have a big gas impact when the loop executes on a large number of elements.
There are many examples of this in for loops https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L118 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L153 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L300 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L317
Recommended Mitigation Steps
Use prefix not postfix to increment in a loop
[G-07] For loop incrementing can be unsafe
For loops that use i++ do not need to use safemath for this operation because the loop would run out of gas long before this point. Making this addition operation unsafe using unchecked saves gas.
Sample code to make the for loop increment unsafe
Idea borrowed from https://gist.github.com/hrkrshnn/ee8fabd532058307229d65dcd5836ddc#the-increment-in-for-loop-post-condition-can-be-made-unchecked
There are many for loops and that can use this change https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L118 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L153 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L300 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L317
Recommended Mitigation Steps
Make the increment in for loops unsafe to save gas
[G-08] Use iszero assembly for zero checks
Comparing a value to zero can be done using the
iszero
EVM opcode. This can save gasSource from t11s https://twitter.com/transmissions11/status/1474465495243898885
There are many places where a value is compared to zero https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L185
Recommended Mitigation Steps
Use the assembly
iszero
evm opcode to compare values to zero[G-09] Use uint not bool
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.
Locations where this was found include https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L24 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L26 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L28 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L86 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L92 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L314 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L385
Recommended Mitigation Steps
Replace bool variables with uints
[G-10] Use newer solidity version
A solidity version before 0.8.X is used. The latest release of solidity includes changes that can provide gas savings. The improvements include:
0.8.0
(can be more gas efficient than some library based safemath).0.8.2
, leads to cheaper runtime gas. Especially relevant when the contract has small functions. For example, OpenZeppelin libraries typically have a lot of small helper functions and if they are not inlined, they cost an additional 20 to 40 gas because of 2 extrajump
instructions and additional stack operations needed for function calls.0.8.3
, storing packed structs, in some cases used an additional storage read operation. After EIP-2929, if the slot was already cold, this means unnecessary stack operations and extra deploy time costs. However, if the slot was already warm, this means additional cost of100
gas alongside the same unnecessary stack operations and extra deploy time costs.0.8.4
, leads to cheaper deploy time cost and run time cost. Note: the run time cost is only relevant when the revert condition is met. In short, replace revert strings by custom errors.Source https://gist.github.com/hrkrshnn/ee8fabd532058307229d65dcd5836ddc#upgrade-to-at-least-084
Recommended Mitigation Steps
Use solidity release 0.8.13 with Yul IR pipeline and other improvements for gas savings
[G-11] Non-public variables save gas
Many constant variables are public, but changing the visibility of these variables to private or internal can save gas. https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L32 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L34 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L35 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L37 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L39 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L40 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L41 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L42 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L43 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L45 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L46 https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L47
Recommended Mitigation Steps
Declare some public variables as private or internal to save gas
[G-12] Write contracts in vyper
The contracts are all written entirely in solidity. Writing contracts with vyper instead of solidity can save gas.
Source https://twitter.com/eiber_david/status/1515737811881807876 doggo demonstrates https://twitter.com/fubuloubu/status/1528179581974417414?t=-hcq_26JFDaHdAQZ-wYxCA&s=19
Recommended Mitigation Steps
Write some or all of the contracts in vyper to save gas
[G-13] Use
abi.encodePacked()
notabi.encode()
Changing
abi.encode
toabi.encodePacked
can save gas.abi.encode
pads extra null bytes at the end of the call data which is normally unnecessary. In general,abi.encodePacked
is more gas-efficient.There are many places where this change can be made: https://github.com/Badger-Finance/vested-aura/blob/v0.0.2/contracts/MyStrategy.sol#L260
Recommended Mitigation Steps
Change
abi.encode
toabi.encodePacked