Platform: Code4rena
Start Date: 16/02/2023
Pot Size: $144,750 USDC
Total HM: 17
Participants: 154
Period: 19 days
Judge: Trust
Total Solo HM: 5
Id: 216
League: ETH
Rank: 149/154
Findings: 1
Award: $42.07
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: c3phas
Also found by: 0x3b, 0x6980, 0x73696d616f, 0xSmartContract, 0xackermann, 0xhacksmithh, 0xsomeone, Bnke0x0, Bough, Budaghyan, Darshan, DeFiHackLabs, Deivitto, GalloDaSballo, JCN, LethL, Madalad, MiniGlome, Morraez, P-384, PaludoX0, Phantasmagoria, Praise, RHaO-sec, Rageur, RaymondFam, ReyAdmirado, Rickard, Rolezn, SaeedAlipoor01988, Saintcode_, Sathish9098, TheSavageTeddy, Tomio, Viktor_Cortess, abiih, arialblack14, atharvasama, banky, codeislight, cryptonue, ddimitrov22, dec3ntraliz3d, descharre, dharma09, emmac002, favelanky, hl_, hunter_w3b, kaden, kodyvim, matrix_0wl, oyc_109, pavankv, scokaf, seeu, yamapyblack
42.0697 USDC - $42.07
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: 2
<br>payable
If a function modifier such as onlyOwner
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 (2400 per instance).
Instances: 14
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: 12
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: 13
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: 25
calldata
instead of memory
for function arguments that are read onlyInstances: 11
Instances: 10
require
/revert
checks should be refactored to a modifier or function.Instances: 6
require
/revert
strings longer than 32 bytes cost extra gasShortening revert strings to fit in 32 bytes will decrease gas costs for deployment and gas costs when the revert condition has been met. If the contract(s) in scope allow using Solidity >=0.8.4, consider using Custom Errors as they are more gas efficient while allowing developers to describe the error in detail using NatSpec.
Instances: 35
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: 113
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: 1
<br>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: 45
keccak256
should use immutable
rather than constant
See this issue for a detail description of the issue.
Instances: 8
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: 15
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: 4
Use a Solidity version of at least 0.8.2 to get simple compiler automatic inlining.
Use a Solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads.
Use a Solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()
/require()
strings.
Use a Solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value.
Use a Solidity version of at least 0.8.12 to get string.concat() to be used instead of abi.encodePacked(<str>,<str>).
Use a solidity version of at least 0.8.13 to get the ability to use using for with a list of free functions.
Instances: 12
return
keyword wastes gasInstances: 18
require
statements using &&
Replacing with two separate require statements saves 16 gas per instance.
Instances: 1
<br>x += y
costs more gas than x = x + y
for state variablesInstances: 9
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: 6
++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: 17
#0 - c4-judge
2023-03-09T18:05:52Z
trust1995 marked the issue as grade-b