Platform: Code4rena
Start Date: 27/04/2022
Pot Size: $50,000 MIM
Total HM: 6
Participants: 59
Period: 5 days
Judge: 0xean
Id: 113
League: ETH
Rank: 51/59
Findings: 1
Award: $52.09
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: BowTiedWardens
Also found by: 0x1f8b, 0xNazgul, 0xf15ers, 0xkatana, CertoraInc, Funen, GimelSec, Hawkeye, IllIllI, Kulk0, NoamYakov, Tadashi, Tomio, TrungOre, antonttc, catchup, defsec, delfin454000, fatherOfBlocks, gzeon, horsefacts, joestakey, kenta, oyc_109, pauliax, reassor, robee, samruna, simon135, slywaters, sorrynotsorry, z3s
52.092 MIM - $52.09
Uninitialized variables by default contain a value equivalent to 0: uint
s are initialized to 0; bool
s to false; address
es to address(0)
.
Explicitly assigning these values to variables when they are declared increases gas costs while providing no funciton.
e.g. change this code:
uint256 var = 0;
to
uint256 var;
For more information, please consult the following resources:
Tips and Tricks to Save Gas and Reduce Bytecode Size
The following lines of code are affected:
code4rena/2022-04-abranft/contracts/NFTPair.sol:641: for (uint256 i = 0; i < actions.length; i++) { code4rena/2022-04-abranft/contracts/NFTPair.sol:96: uint8 private constant LOAN_INITIAL = 0; code4rena/2022-04-abranft/contracts/NFTPairWithOracle.sol:113: uint8 private constant LOAN_INITIAL = 0; code4rena/2022-04-abranft/contracts/NFTPairWithOracle.sol:674: for (uint256 i = 0; i < actions.length; i++) {
Newer versions of the Solidity compiler will check for integer overflows and underflows automatically. This provides safety but increases gas costs.
When an unsigned integer is guaranteed to never overflow, the unchecked
feature of Solidity can be used to save gas costs.
A common case for this is for-loops using a strictly-less-than comparision in their conditional statement, e.g.:
uint256 length = someArray.length; for (uint256 i; i < length; ++i) { }
In cases like this, the maximum value for length
is 2**256 - 1
. Therefore, the maximum value of i
is 2**256 - 2
as it will always be strictly less than length
.
This example can be replaced with the following construction to reduce gas costs:
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; } }
For more information, consult the following resources:
Solidity docs: underflows, overflows, and unchecked
The following lines of code are affected:
code4rena/2022-04-abranft/contracts/NFTPair.sol:494: for (uint256 k = 2; k <= COMPOUND_INTEREST_TERMS; k++) { code4rena/2022-04-abranft/contracts/NFTPair.sol:641: for (uint256 i = 0; i < actions.length; i++) { code4rena/2022-04-abranft/contracts/NFTPairWithOracle.sol:527: for (uint256 k = 2; k <= COMPOUND_INTEREST_TERMS; k++) { code4rena/2022-04-abranft/contracts/NFTPairWithOracle.sol:674: for (uint256 i = 0; i < actions.length; i++) {
Using ++i
costs less gas than using i++
. In the context of a for-loop, gas is saved on each iteration.
The following lines of code are affected:
code4rena/2022-04-abranft/contracts/NFTPair.sol:494: for (uint256 k = 2; k <= COMPOUND_INTEREST_TERMS; k++) { code4rena/2022-04-abranft/contracts/NFTPair.sol:641: for (uint256 i = 0; i < actions.length; i++) { code4rena/2022-04-abranft/contracts/NFTPairWithOracle.sol:527: for (uint256 k = 2; k <= COMPOUND_INTEREST_TERMS; k++) { code4rena/2022-04-abranft/contracts/NFTPairWithOracle.sol:674: for (uint256 i = 0; i < actions.length; i++) {
In the context of a for-loop that iterates over an array, it costs less gas to cache the array's length in a variable and read from this variable rather than use the arrays .length
property. Reading the .length
property for on the array will cause a recalculation of the array's length on each iteration of the loop which is a more expensive operation than reading from a stack variable.
For example, the following code:
for (uint i; i < arr.length; ++i) { // ... }
should be changed to:
uint length = arr.length; for (uint i; i < length; ++i) { // ... }
Note that in the second case, the length of the array must not change during the loop's execution.
For more information, see the following resource:
The following lines of code are affected:
code4rena/2022-04-abranft/contracts/NFTPair.sol:641: for (uint256 i = 0; i < actions.length; i++) { code4rena/2022-04-abranft/contracts/NFTPairWithOracle.sol:674: for (uint256 i = 0; i < actions.length; i++) {
#0 - cryptolyndon
2022-05-13T23:00:56Z
We do use unchecked increment. Check the compiler version.
Zero assignments are to improve clarity. If that actually costs more gas than leaving it out, then the compiler is broken. Ditto for pre- vs post-increment in for
; if the most common thing by a mile that programmers put there is needlessly expensive, then the compiler needs to be fixed.
I suppose array length is more dicey; I expect it to be caught as well but have not checked rigorously.