Platform: Code4rena
Start Date: 01/08/2022
Pot Size: $50,000 USDC
Total HM: 26
Participants: 133
Period: 5 days
Judge: Jack the Pug
Total Solo HM: 6
Id: 151
League: ETH
Rank: 113/133
Findings: 1
Award: $22.03
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: c3phas
Also found by: 0x040, 0x1f8b, 0xA5DF, 0xNazgul, 0xSmartContract, 0xSolus, 0xc0ffEE, 0xkatana, 0xsam, 8olidity, Aymen0909, Bnke0x0, CertoraInc, Chinmay, Chom, CodingNameKiki, Deivitto, Dravee, ElKu, Extropy, Fitraldys, Funen, GalloDaSballo, Guardian, IllIllI, JC, Lambda, MEP, Metatron, MiloTruck, Noah3o6, NoamYakov, PaludoX0, ReyAdmirado, Rohan16, Rolezn, Ruhum, Sm4rty, SooYa, TomJ, Tomio, Waze, _Adam, __141345__, a12jmx, ajtra, ak1, apostle0x01, asutorufos, ballx, benbaessler, bharg4v, bobirichman, brgltd, cryptonue, defsec, delfin454000, dharma09, djxploit, durianSausage, eierina, erictee, fatherOfBlocks, gerdusx, gogo, hake, hyh, ignacio, jag, kaden, kyteg, lucacez, mics, minhquanym, oyc_109, pfapostol, rbserver, ret2basic, robee, rokinot, sach1r0, saian, samruna, scaraven, sikorico, simon135, supernova, teddav, tofunmi, zeesaw
22.0296 USDC - $22.03
Declaring functions as public costs more gas. Replace them with external wherever possible.
Instances of this issue :
DebtToken.sol#L82 DebtToken.sol#L95 DebtToken.sol#L103 Homefi.sol#L264
Instances of this issue :
DebtToken.sol#L95 DebtToken.sol#L103
Here, the function declaration defines that a bool value is to be returned, but there is no use of any bool value in function body definition.
Using i++ involves storing a temporary value of i. This operation is avoidable by using pre-increment operator. You might have to tweak the logic a little bit.
Instances of this issue :
HomeFiProxy.sol#L87 HomeFiProxy.sol#L136 Disputes.sol#L121 Homefi.sol#L289 Project.sol#L179 Project.sol#L248
This optimization has many more instances throughout the contraacts.
Functions that are guaranteed to revert when called by normal users, because they use onlyOwner / onlyAdmin etc. modifiers, can be marked payable to save gas. This skips some checks of whether payment was provided.
Instances of this issue :
HomeFiProxy.sol#L102 HomeFiProxy.sol#L128 HomeFiProxy.sol#L152 Disputes.sol#L87 Disputes.sol#L145 Homefi.sol#L133 Homefi.sol#L160 Homefi.sol#L174 Homefi.sol#L188 Homefi.sol#L203
Since there is a direct opcode for this operation, implementing this saves gas.
Instances of this issue :
HomeFiProxy.sol#L106 Project.sol#L513 Project.sol#L798
Function declarations are expensive. Add to that a function call. An internal function is not called by any external contract, and if only used once, it is better to just implement the functionality directly.
Instances of this issue : HomeFiProxy.sol#L200 Disputes.sol#L236 Disputes.sol#L254 Disputes.sol#L268
Modifiers that are neither inherited nor used multiple times in the contract should be removed and replaced by simple require statements. This saves deployment gas.
Instances of this issue :
Disputes.sol#L37 Disputes.sol#L43 Disputes.sol#L50
If a require statement checks multiple conditions using the && operator, it is more gas efficient to split it into multiple require statements.
Instances of this issue :
Disputes.sol#L62 Disputes.sol#L106
Functions are expensive. So, if possible, simpler function definitions should be remodified into direct use operations wherever needed.
Instances of this issue :
If you have a local variable with the same value as of a state variable within a scope, use it in place of state variable while emitting events. Or create a local variable for the same purpose.
Instances of this issue :
Disputes.sol#L121 Homefi.sol#L231 Homefi.sol#L295 Project.sol#L144
We shall use assembly wherever possible, it saves gas.
Instances of this issue :
Disputes.sol#L147 Disputes.sol#L212 Homefi.sol#L256 Project.sol#L190 Project.sol#L281 Project.sol#L301
This is because any operation first reads the content of the boolean storage slot before changing it.
Take this example : Disputes.sol#L180
Use a simpler construct like if-else or assembly switch statements and then store the boolean value at the end, or write multiple require statements directly.
The [ContextUpgradeable] component has been imported but doesn't seem to be used in the contract. We shall remove unnecessary import statements to save deployment gas.
If a state variable is read/accessed multiple times within a scope, it is better to cache it as a local variable for the scope. Reading local variable involves cheaper stack reads and avoids SLOADs.
Instances of this issue :
Homefi.sol#L296 Project.sol#L176 Project.sol#L210 Project.sol#L681 Project.sol#L431
EVM has storage slots of 32 Bytes for variables.
Take the example : Project.sol#L78
The bool at L78 should be shifted to L67 so that address (20B) , bool (1B) and bool (1B) make up a storage slot.
Whereas at L78, the bool is bounded by two uint256 variables which use 1 full storage slot. So, the bool is using a storage slot extra. Moving it to L68 saves a storage slot.
The statement X += Y goes through the creation of a temporary variable in the compiler memory, which can be avoided. Same goes for X -= Y.
Instances of this issue :
Project.sol#L179 Project.sol#L772 Project.sol#L431
This small change saves some gas, but only for uint in a require statement.
Instances of this issue :
Take this example : Project.sol#L200
A variable which is declared as uint256, is calculated from two uint256 variables, is being casted into uint256. This variable is already uint256 and hence the casting is unnecessary.
There is no opcode in EVM for the >= or <= operation. They translate into two different operations, > and =. If we convert them into strict equality, they will require only one opcode ie. < or >. We also need to change the equation logic to incorporate these operator changes. For example, we might need to add 1 to the RHS or subtract 1 in some cases.
Instances of this issue :
When you need to check the same condition within multiple functions, you should define it as a modifier and use it with functions. This will save gas of repeated require statements.
Instances of this issue :
Project.sol#L400 Project.sol#L406
Array length lookup is a call to the memory and we should avoid calling it repeatedly such as in a loop.
Instances of this issue :
SLOAD and SSTORE of state variables cost a lot of gas. Avoid using them inside loops because of repeated lookup.
Instances of this issue :
This process saves significant amount of gas compared to the proxy implementation.
Here is more information about it : Youtube Link for Clone Deployment
Example : Use 0.8.10 to have external calls skip contract existence checks if external call has a return value. This is a default check by compiler before 0.8.10
Prioritise most called functions in the method ID table by renaming them. This saves gas for the most called functions.