Platform: Code4rena
Start Date: 08/03/2023
Pot Size: $60,500 USDC
Total HM: 2
Participants: 123
Period: 7 days
Judge: hansfriese
Id: 220
League: ETH
Rank: 110/123
Findings: 1
Award: $19.30
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: JCN
Also found by: 0x1f8b, 0xSmartContract, 0xSolus, 0xhacksmithh, 0xnev, Angry_Mustache_Man, Aymen0909, Diana, Flora, Inspex, Madalad, MatricksDeCoder, MiniGlome, R-Nemes, RaymondFam, ReyAdmirado, Rolezn, SAAJ, Sathish9098, Shubham, Udsen, Viktor_Cortess, arialblack14, atharvasama, ayden, c3phas, carlitox477, descharre, dharma09, durianSausage, fatherOfBlocks, ginlee, glcanvas, hunter_w3b, leopoldjoy, matrix_0wl, mrpathfindr, nadin, oyc_109, pipoca, schrodinger, slvDev, ulqiorra, volodya
19.3029 USDC - $19.30
Issue | Instances | |
---|---|---|
1 | Using storage instead of memory for struct/array saves gas | 2 |
2 | storage variable should be cached into memory variables instead of re-reading them | 5 |
3 | x += y/x -= y costs more gas than x = x + y/x = x - y for state variables | 16 |
storage
instead of memory
for struct/array saves gas :When 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 declearing 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.
There are 2 instances of this issue :
File: NeoTokyoStaker.sol
StakedS1Citizen memory s1Citizen = stakedS1[_recipient][citizenId];
StakedS2Citizen memory s2Citizen = stakedS2[_recipient][citizenId];
storage
variable should be cached into memory
variables instead of re-reading them :The instances below point to the second+ access of a state variable within a function, the caching of a state variable replaces each Gwarmaccess (100 gas) with a much cheaper stack read, thus saves 100gas for each instance.
There are 8 instances of this issue in NeoTokyoStaker.sol
:
In the code linked above the value of stakedCitizen.timelockEndTime
is read multiple times (3) from storage and it's value does not change so it should be cached into a memory variable in order to save gas by avoiding multiple reads from storage.
In the code linked above the value of stakedCitizen.stakedBytes
is read multiple times (2) from storage and it's value does not change so it should be cached into a memory variable in order to save gas by avoiding multiple reads from storage.
In the code linked above the value of stakedCitizen.stakedVaultId
is read multiple times (2) from storage and it's value does not change so it should be cached into a memory variable in order to save gas by avoiding multiple reads from storage.
In the code linked above the value of stakedCitizen.timelockEndTime
is read multiple times (3) from storage and it's value does not change so it should be cached into a memory variable in order to save gas by avoiding multiple reads from storage.
In the code linked above the value of stakedCitizen.stakedBytes
is read multiple times (2) from storage and it's value does not change so it should be cached into a memory variable in order to save gas by avoiding multiple reads from storage.
x += y/x -= y
costs more gas than x = x + y/x = x - y
for state variables :Using the addition operator instead of plus-equals saves 113 gas as explained here
There are 16 instance of this issue:
File: NeoTokyoStaker.sol 977 pool.totalPoints += citizenStatus.points; 1029 pool.totalPoints += citizenStatus.points; 1078 citizenStatus.stakedBytes += amount; 1079 citizenStatus.points += bonusPoints; 1080 pool.totalPoints += bonusPoints; 1099 citizenStatus.stakedBytes += amount; 1100 citizenStatus.points += bonusPoints; 1101 pool.totalPoints += bonusPoints; 1160 stakerLPPosition[msg.sender].amount += amount; 1161 stakerLPPosition[msg.sender].points += points; 1164 pool.totalPoints += points; 1515 pool.totalPoints -= stakedCitizen.points; 1580 pool.totalPoints -= stakedCitizen.points; 1626 lpPosition.amount -= amount; 1627 lpPosition.points -= points; 1630 pool.totalPoints -= points;
#0 - c4-judge
2023-03-17T03:42:18Z
hansfriese marked the issue as grade-b
#1 - c4-sponsor
2023-03-21T01:09:02Z
TimTinkers marked the issue as sponsor confirmed