Platform: Code4rena
Start Date: 03/03/2023
Pot Size: $90,500 USDC
Total HM: 4
Participants: 42
Period: 7 days
Judge: 0xean
Total Solo HM: 2
Id: 219
League: ETH
Rank: 36/42
Findings: 1
Award: $53.96
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: JCN
Also found by: 0x6980, 0xSmartContract, 0xnev, Madalad, Phantasmagoria, Rageur, RaymondFam, ReyAdmirado, Rolezn, Sathish9098, atharvasama, descharre, hunter_w3b, matrix_0wl, saneryee, volodya, yongskiws
53.963 USDC - $53.96
Issue | Instances | |
---|---|---|
[G-01] | abi.encodePacked is more gas efficient than abi.encode | 6 |
[G-02] | Use assembly to check for address(0) | 18 |
[G-03] | Use assembly to calculate hashes | 12 |
[G-04] | Cache storage variables rather than re-reading from storage | 9 |
[G-05] | Use calldata instead of memory for function arguments that are read only | 18 |
[G-06] | Duplicated require /revert checks should be refactored to a modifier or function. | 2 |
[G-07] | Use indexed to save gas | 18 |
[G-08] | Use constant , immutable where applicable | 7 |
[G-09] | Inline internal functions that are only called once | 4 |
[G-10] | Expressions for constant values such as a call to keccak256 should use immutable rather than constant | 13 |
[G-11] | Using storage instead of memory for structs/arrays saves gas | 2 |
[G-12] | Use unchecked for operations that cannot overflow/underflow | 2 |
[G-13] | Use private rather than public for constants | 27 |
[G-14] | Change public functions to external | 25 |
[G-15] | Naming a return variable and still calling the return keyword wastes gas | 6 |
[G-16] | Usage of uint smaller than 32 bytes (256 bits) incurs overhead | 2 |
[G-17] | ++i costs less gas than i++ | 1 |
Total issues: 17
Total instances: 172
Â
abi.encodePacked
is more gas efficient than abi.encode
abi.encode
pads all elementary types to 32 bytes, whereas abi.encodePacked
will only use the minimal required memory to encode the data. See here for more info.
Instances: 6
Â
address(0)
Saves 16000 deployment gas per instance and 6 runtime gas per instance.
assembly { if iszero(_addr) { mstore(0x00, "zero address") revert(0x00, 0x20) } }
Instances: 18
Â
Saves 5000 deployment gas per instance and 80 runtime gas per instance.
function solidityHash(uint256 a, uint256 b) public view { //unoptimized keccak256(abi.encodePacked(a, b)); }
function assemblyHash(uint256 a, uint256 b) public view { //optimized assembly { mstore(0x00, a) mstore(0x20, b) let hashedVal := keccak256(0x00, 0x40) } }
Instances: 12
Â
Caching of a state variable replaces each Gwarmaccess (100 gas) with a much cheaper stack read.
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 recalculate the key’s keccak256 hash (Gkeccak256 - 30 gas) and that calculation’s associated stack operations. Caching an array’s struct avoids recalculating the array offsets into memory/calldata.
Instances: 9
Â
calldata
instead of memory
for function arguments that are read onlyInstances: 18
Â
require
/revert
checks should be refactored to a modifier or function.Instances: 2
Â
indexed
to save gasUsing indexed
for value type event parameters (address, uint, bool) saves at least 80 gas in emitting the event (https://gist.github.com/Tomosuke0930/9bf61e01a8c3e214d95a9b84dcb41d97).
Note that for other types however (string, bytes), it is more expensive.
Instances: 18
Â
constant
, immutable
where applicableUse immutable if you want to assign a permanent value at construction. Use constants if you already know the permanent value. Both get directly embedded in bytecode, saving SLOAD. Variables only set in the constructor and never edited afterwards should be marked as immutable, as it would avoid the expensive storage-writing operation in the constructor (around 20 000 gas per variable) and replace the expensive storage-reading operations (around 2100 gas per reading) to a less expensive value reading (3 gas).
Instances: 7
Â
internal
functions that are only called onceSaves 20-40 gas per instance. See https://blog.soliditylang.org/2021/03/02/saving-gas-with-simple-inliner/ for more details.
Instances: 4
Â
keccak256
should use immutable
rather than constant
See this issue for a detailed description of the issue.
Instances: 13
Â
storage
instead of memory
for structs/arrays saves gasWhen fetching data from a storage location, assigning the data to a memory
variable causes all fields of the struct/array to be read from storage, which incurs a Gcoldsload (2100 gas) for each field of the struct/array. If the fields are read from the new memory variable, they incur an additional MLOAD
rather than a cheap stack read.
Instead of declaring the variable with the memory
keyword, declaring the variable with the storage
keyword and caching any fields that need to be re-read in stack variables, will be much cheaper, only incuring the Gcoldsload for the fields actually read. The only time it makes sense to read the whole struct/array into a memory
variable, is if the full struct/array is being returned by the function, is being passed to a function that requires memory
, or if the array/struct is being read from another memory
array/struct.
Instances: 2
Â
unchecked
for operations that cannot overflow/underflowBy bypassing Solidity's built in overflow/underflow checks using unchecked
, we can save gas. This is especially beneficial for the index variable within for loops (saves 120 gas per iteration).
Instances: 2
Â
private
rather than public
for constantsSaves 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. If needed to be viewed externally, the values can be read from the verified contract source code.
Instances: 27
Â
public
functions to external
Functions marked as public
that are not called internally should be set to external
to save gas and improve code quality. External call cost is less expensive than of public functions.
Instances: 25
Â
return
keyword wastes gasInstances: 6
Â
uint
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.
Consider using a larger size then downcasting where needed.
https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html
Instances: 2
Â
++i
costs less gas than i++
True for --i
/i--
as well, and is especially important in for loops. Saves 5 gas per iteration.
Instances: 1
Â
#0 - c4-judge
2023-03-12T18:11:14Z
0xean marked the issue as grade-b
#1 - c4-sponsor
2023-03-22T09:46:42Z
novaknole20 marked the issue as sponsor acknowledged