Issue | Contexts | Estimated Gas Saved | |
---|---|---|---|
GAS‑1 | abi.encode() is less efficient than abi.encodepacked() |
3 | 159 |
GAS‑2 | Consider activating via-ir for deploying |
1 | 250 |
GAS‑3 | <array>.length Should Not Be Looked Up In Every Loop Of A For-loop |
6 | 582 |
GAS‑4 | Use assembly to emit events | 9 | 342 |
GAS‑5 | Avoid emitting event on every iteration | 4 | 1500 |
GAS‑6 | Setting the constructor to payable |
5 | 65 |
GAS‑7 | Counting down in for statements is more gas efficient |
6 | 1542 |
GAS‑8 | Using delete statement can save gas |
3 | 24 |
GAS‑9 | ++i Costs Less Gas Than i++ , Especially When It’s Used In For-loops (--i /i-- Too) |
6 | 36 |
GAS‑10 | Functions guaranteed to revert when called by normal users can be marked payable |
5 | 105 |
GAS‑11 | It Costs More Gas To Initialize Variables To Zero Than To Let The Default Of Zero Be Applied | 6 | 36 |
GAS‑12 | Multiple accesses of a mapping/array should use a local variable cache | 30 | 2400 |
GAS‑13 | Multiple Address Mappings Can Be Combined Into A Single Mapping Of An Address To A Struct, Where Appropriate | 3 | 1500 |
GAS‑14 | Optimize names to save gas | 5 | 110 |
GAS‑15 | <x> += <y> Costs More Gas Than <x> = <x> + <y> For State Variables |
14 | 84 |
GAS‑16 | Using private rather than public for constants, saves gas |
3 | 10200 |
GAS‑17 | Help The Optimizer By Saving A Storage Variable’s Reference Instead Of Repeatedly Fetching It | 41 | 2214 |
GAS‑18 | Superfluous event fields | 2 | 68 |
GAS‑19 | Usage of uints /ints smaller than 32 bytes (256 bits) incurs overhead |
4 | 24 |
GAS‑20 | ++i /i++ Should Be unchecked{++i} /unchecked{i++} When It Is Not Possible For Them To Overflow, As Is The Case When Used In For- And While-loops |
6 | 210 |
GAS‑21 | Use assembly to check for address(0) | 2 | 52 |
GAS‑22 | Use do while loops instead of for loops | 6 | 24 |
GAS‑23 | Use of Custom Errors Instead of String | 2 | 24 |
GAS‑24 | Using XOR (^) and AND (&) bitwise equivalents | 11 | 143 |
Total: 321 contexts over 24 issues
abi.encode()
is less efficient than abi.encodepacked()
See for more information: https://github.com/ConnorBlockchain/Solidity-Encode-Gas-Comparison
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L113
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L571
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L596
contract GasTest is DSTest {
Contract0 c0;
Contract1 c1;
function setUp() public {
c0 = new Contract0();
c1 = new Contract1();
}
function testGas() public {
c0.not_optimized();
c1.optimized();
}
}
contract Contract0 {
string a = "Code4rena";
function not_optimized() public returns(bytes32){
return keccak256(abi.encode(a));
}
}
contract Contract1 {
string a = "Code4rena";
function optimized() public returns(bytes32){
return keccak256(abi.encodePacked(a));
}
}
Contract0 contract | |||||
---|---|---|---|---|---|
Deployment Cost | Deployment Size | ||||
101871 | 683 | ||||
Function Name | min | avg | median | max | # calls |
not_optimized | 2661 | 2661 | 2661 | 2661 | 1 |
Contract1 contract | |||||
---|---|---|---|---|---|
Deployment Cost | Deployment Size | ||||
99465 | 671 | ||||
Function Name | min | avg | median | max | # calls |
optimized | 2608 | 2608 | 2608 | 2608 | 1 |
via-ir
for deployingThe IR-based code generator was introduced with an aim to not only allow code generation to be more transparent and auditable but also to enable more powerful optimization passes that span across functions.
You can enable it on the command line using --via-ir
or with the option {"viaIR": true}
.
This will take longer to compile, but you can just simple test it before deploying and if you got a better benchmark then you can add --via-ir to your deploy command
More on: https://docs.soliditylang.org/en/v0.8.17/ir-breaking-changes.html
<array>.length
Should Not Be Looked Up In Every Loop Of A For-loopThe overheads outlined below are PER LOOP, excluding the first loop
storage arrays incur a Gwarmaccess (100 gas)
memory arrays use MLOAD (3 gas)
calldata arrays use CALLDATALOAD (3 gas)
Caching the length changes each of these to a DUP
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L233
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L293
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L359
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L438
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L549
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L592
We can use assembly to emit events efficiently by utilizing scratch space
and the free memory pointer
. This will allow us to potentially avoid memory expansion costs.
Note: In order to do this optimization safely, we will need to cache and restore the free memory pointer.
For example, for a generic emit
event for eventSentAmountExample
:
We can use the following assembly emit events:
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L165
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L169
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L172
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L214
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L225
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L533
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L708
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L734
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Ownable.sol#L21
Expensive operations should always try to be avoided within loops. Such operations include: reading/writing to storage, heavy calculations, external calls, and emitting events. In this instance, an event is being emitted every iteration. Events have a base cost of Glog (375 gas)
per emit and Glogdata (8 gas) * number of bytes in event
. We can avoid incurring those costs each iteration by emitting the event outside of the loop.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L293
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L359
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L438
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L549
constructor
to payable
Saves ~13 gas per instance
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Beedle.sol#L11
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Fees.sol#L19
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L73
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L31
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Ownable.sol#L14
for
statements is more gas efficientCounting down is more gas efficient than counting up because neither we are making zero variable to non-zero variable and also we will get gas refund in the last transaction when making non-zero to zero variable.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L233
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L293
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L359
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L438
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L549
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L592
contract GasTest is DSTest {
Contract0 c0;
Contract1 c1;
function setUp() public {
c0 = new Contract0();
c1 = new Contract1();
}
function testGas() public {
c0.AddNum();
c1.AddNum();
}
}
contract Contract0 {
uint256 num = 3;
function AddNum() public {
uint256 _num = num;
for(uint i=0;i<=9;i++){
_num = _num +1;
}
num = _num;
}
}
contract Contract1 {
uint256 num = 3;
function AddNum() public {
uint256 _num = num;
for(uint i=9;i>=0;i--){
_num = _num +1;
}
num = _num;
}
}
Contract0 contract | |||||
---|---|---|---|---|---|
Deployment Cost | Deployment Size | ||||
77011 | 311 | ||||
Function Name | min | avg | median | max | # calls |
AddNum | 7040 | 7040 | 7040 | 7040 | 1 |
Contract1 contract | |||||
---|---|---|---|---|---|
Deployment Cost | Deployment Size | ||||
73811 | 295 | ||||
Function Name | min | avg | median | max | # calls |
AddNum | 3819 | 3819 | 3819 | 3819 | 1 |
delete
statement can save gashttps://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L14
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L16
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L56
++i
Costs Less Gas Than i++
, Especially When It's Used In For-loops (--i
/i--
Too)Saves 6 gas per loop
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L233
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L293
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L359
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L438
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L549
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L592
For example, use ++i
instead of i++
payable
If a function modifier or require such as onlyOwner/onlyX 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. The extra opcodes avoided are CALLVALUE(2), DUP1(3), ISZERO(3), PUSH2(3), JUMPI(10), PUSH1(3), DUP1(3), REVERT(0), JUMPDEST(1), POP(2) which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Beedle.sol#L36
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L84
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L92
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L100
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Ownable.sol#L19
Functions guaranteed to revert when called by normal users can be marked payable.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L233
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L293
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L359
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L438
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L549
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L592
Caching a mapping's value in a local storage or calldata variable when the value is accessed multiple times saves ~42 gas per access due to not having to perform the same offset calculation every time. Help the Optimizer by saving a storage variable's reference instead of repeatedly fetching it
To help the optimizer,declare a storage type variable and use it instead of repeatedly fetching the reference in a map or an array. As an example, instead of repeatedly calling someMap[someIndex]
, save its reference like this: SomeStruct storage someStruct = someMap[someIndex]
and use it.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L145
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L148
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L167
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L175
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L183
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L199
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L211
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L222
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L185
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L187
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L234
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L235
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L236
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L238
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L367
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L611
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L262
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L636
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L263
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L637
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L312
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L314
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L575
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L55-L56
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L84
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L85
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L92
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L85
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L92
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.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L19
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L22
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L24
Contracts most called functions could simply save gas by function ordering via Method ID. Calling a function at runtime will be cheaper if the function is positioned earlier in the order (has a relatively lower Method ID) because 22 gas are added to the cost of a function for every position that came before it. The caller can save on gas if you prioritize most called functions.
See more here
All in-scope contracts
Find a lower method ID name for the most called functions for example Call() vs. Call1() is cheaper by 22 gas
For example, the function IDs in the Gauge.sol contract will be the most used; A lower method ID may be given.
<x> += <y>
Costs More Gas Than <x> = <x> + <y>
For State Variableshttps://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L263
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L314
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L388
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L400
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L490
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L502
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L575
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L633
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L637
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L698
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L726
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L41
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L48
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L89
private
rather than public
for constants, saves gasIf needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that returns a tuple of the values of all currently-public constants. Saves 3406-3606 gas in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it's used, and not adding another entry to the method ID table
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Fees.sol#L16
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L59
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L61
Set variable to private.
To help the optimizer, declare a storage type variable and use it instead of repeatedly fetching the reference in a map or an array.
The effect can be quite significant.
As an example, instead of repeatedly calling someMap[someIndex], save its reference like this: SomeStruct storage someStruct = someMap[someIndex] and use it.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L238
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L262
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L263
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L296
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L312
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L314
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L343
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L363
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L367
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L388
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L398
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L400
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L416
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L417
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L418
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L419
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L420
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L426
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L427
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L441
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L448
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L552
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L575
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L584
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L597
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L598
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L599
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L606
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L611
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L631
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L633
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L636
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L637
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L659
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L686
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L688
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L690
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L692
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L694
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L696
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L698
block.number
and block.timestamp
are added to the event information by default, so adding them manually will waste additional gas.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L22
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L31
uints
/ints
smaller than 32 bytes (256 bits) incurs overheadWhen 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.
https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html
Each operation involving a uint8
costs an extra 22-28 gas (depending on whether the other operand is also a variable of type uint8
) as compared to ones involving uint256
, due to the compiler having to clear the higher bits of the memory word before operating on the uint8
, as well as the associated stack operations of doing so. Use a larger size then downcast where needed
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L724
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L726
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/interfaces/ISwapRouter.sol#L8
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/interfaces/ISwapRouter.sol#L13
++i
/i++
Should Be unchecked{++i}
/unchecked{i++}
When It Is Not Possible For Them To Overflow, As Is The Case When Used In For- And While-loopsThe unchecked keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas PER LOOP
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L233
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L293
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L359
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L438
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L549
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L592
address(0)
Save 6 gas per instance if using assembly to check for address(0)
e.g.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L167
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L240
A do while loop will cost less gas since the condition is not being checked for the first iteration.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L232
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L292
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L356
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L437
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L548
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L591
To save some gas the use of custom errors leads to cheaper deploy time cost and run time cost. The run time cost is only relevant when the revert condition is met.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Fees.sol#L27
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Ownable.sol#L11
Use Custom Errors instead of strings.
Given 4 variables a, b, c and d represented as such:
0 0 0 0 0 1 1 0 <- a
0 1 1 0 0 1 1 0 <- b
0 0 0 0 0 0 0 0 <- c
1 1 1 1 1 1 1 1 <- d
To have a == b means that every 0 and 1 match on both variables. Meaning that a XOR (operator ^) would evaluate to 0 ((a ^ b) == 0), as it excludes by definition any equalities.Now, if a != b, this means that there’s at least somewhere a 1 and a 0 not matching between a and b, making (a ^ b) != 0.Both formulas are logically equivalent and using the XOR bitwise operator costs actually the same amount of gas.However, it is much cheaper to use the bitwise OR operator (|) than comparing the truthy or falsy values.These are logically equivalent too, as the OR bitwise operator (|) would result in a 1 somewhere if any value is not 0 between the XOR (^) statements, meaning if any XOR (^) statement verifies that its arguments are different.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L134
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L135
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L136
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L167
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L184
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L200
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L212
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L240
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L244
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L469
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L554
contract GasTest is DSTest {
Contract0 c0;
Contract1 c1;
function setUp() public {
c0 = new Contract0();
c1 = new Contract1();
}
function testGas() public {
c0.not_optimized(1,2);
c1.optimized(1,2);
}
}
contract Contract0 {
function not_optimized(uint8 a,uint8 b) public returns(bool){
return ((a==1) || (b==1));
}
}
contract Contract1 {
function optimized(uint8 a,uint8 b) public returns(bool){
return ((a ^ 1) & (b ^ 1)) == 0;
}
}
Contract0 contract | |||||
---|---|---|---|---|---|
Deployment Cost | Deployment Size | ||||
46099 | 261 | ||||
Function Name | min | avg | median | max | # calls |
not_optimized | 456 | 456 | 456 | 456 | 1 |
Contract1 contract | |||||
---|---|---|---|---|---|
Deployment Cost | Deployment Size | ||||
42493 | 243 | ||||
Function Name | min | avg | median | max | # calls |
optimized | 430 | 430 | 430 | 430 | 1 |
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.