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: 95/133
Findings: 2
Award: $62.34
π Selected for report: 0
π Solo Findings: 0
π Selected for report: Lambda
Also found by: 0x1f8b, 0x52, 0xA5DF, 0xNazgul, 0xNineDec, 0xSmartContract, 0xSolus, 0xf15ers, 0xkatana, 0xsolstars, 8olidity, Aymen0909, Bahurum, Bnke0x0, CertoraInc, Chom, CodingNameKiki, Deivitto, Dravee, ElKu, Extropy, Funen, GalloDaSballo, Guardian, IllIllI, JC, Jujic, MEP, Noah3o6, ReyAdmirado, Rohan16, Rolezn, Ruhum, Sm4rty, SooYa, Soosh, Throne6g, TomJ, Tomio, TrungOre, Waze, Yiko, _Adam, __141345__, a12jmx, ajtra, ak1, arcoun, asutorufos, ayeslick, benbaessler, berndartmueller, bin2chen, bobirichman, brgltd, bulej93, byndooa, c3phas, codexploder, cryptonue, cryptphi, defsec, delfin454000, dipp, djxploit, erictee, exd0tpy, fatherOfBlocks, gogo, hake, hansfriese, horsefacts, hyh, ignacio, indijanc, joestakey, kaden, mics, minhquanym, neumo, obront, oyc_109, p_crypt0, pfapostol, poirots, rbserver, robee, rokinot, rotcivegaf, sach1r0, saian, samruna, saneryee, scaraven, sikorico, simon135, sseefried, supernova
40.621 USDC - $40.62
The code is using the version 0.8.6 and there are libraries like openzepelling that use a more recent version 0.8.9.
Update the version of solidity to a more recent one at least 0.8.9.
DebtToken.sol#L3 ProjectFactory.sol#L3 HomeFiProxy.sol#L3 Disputes.sol#L3 HomeFi.sol#L3 Project.sol#L3 Community.sol#L3 SignatureDecoder.sol#L3 Tasks.sol#L3
Detect missing zero address validation
Include check that the address is not zero
π 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
21.7232 USDC - $21.72
++var (--var) cost less gas than var++ (var--)
HomeFiProxy.sol#L87 HomeFiProxy.sol#L136 Disputes.sol#L121 Project.sol#L248 Project.sol#L311 Project.sol#L322 Project.sol#L368 Project.sol#L603 Project.sol#L625 Project.sol#L650 Project.sol#L672 Project.sol#L710 Community.sol#L140 Community.sol#L624 Tasks.sol#L181
Storage array length checks incur an extra Gwarmaccess (100 gas) per loop. Store the array length in a variable and use it in the for loop helps to save gas.
Split of conditions of an require sentence in different requires sentences can save gas
Disputes.sol#L61 Disputes.sol#L105 Disputes.sol#L106 Community.sol#L352 Community.sol#L353
Change all <= / >= operators for < / > and remember to increse / decrese in consecuence to maintain the logic (example, a <= b for a < b + 1)
Disputes.sol#L107 Project.sol#L200 Project.sol#L368 Project.sol#L438 Project.sol#L608 Project.sol#L614 Project.sol#L650 Project.sol#L655 Project.sol#L661 Project.sol#L710 Community.sol#L354 Community.sol#L355 Community.sol#L401 Community.sol#L792
Replace all > 0 for != 0 to save gas.
Disputes.sol#L107 HomeFi.sol#L245 Project.sol#L195 Project.sol#L380 Project.sol#L601 Project.sol#L691 Community.sol#L261 Community.sol#L427 Community.sol#L764 Community.sol#L840
Replace all sentences in the following lines to save gas.
HomeFi.sol#L289 Project.sol#L179 Project.sol#L250 Project.sol#L290 Project.sol#L431 Project.sol#L440 Project.sol#L456 Project.sol#L616 Project.sol#L663 Project.sol#L711 Project.sol#L772 Community.sol#L423 Community.sol#L435 Community.sol#L798 SignatureDecoder.sol#L83
Use bytes32 instead of string when it's possible to save some gas. Probably, in the following places, the token's name and symbol is not going to be longer than 32 bytes so it's possible to change it to save some gas.
DebtToken.sol#L45 DebtToken.sol#L46
Custom errors are available from solidity version 0.8.4. The instances below match or exceed that version
DebtToken.sol#L30 DebtToken.sol#L31 DebtToken.sol#L50 DebtToken.sol#L96 DebtToken.sol#L104 ProjectFactory.sol#L36 ProjectFactory.sol#L63 ProjectFactory.sol#L64 ProjectFactory.sol#L84 HomeFiProxy.sol#L41 HomeFiProxy.sol#L81 HomeFiProxy.sol#L105 HomeFiProxy.sol#L133 Disputes.sol#L39 Disputes.sol#L46 Disputes.sol#L52 Disputes.sol#L61 Disputes.sol#L106 Disputes.sol#L183 HomeFi.sol#L73 HomeFi.sol#L78 HomeFi.sol#L84 HomeFi.sol#L142 HomeFi.sol#L191 HomeFi.sol#L255 Project.sol#L123 Project.sol#L132 Project.sol#L135 Project.sol#L150 Project.sol#L153 Project.sol#L176 Project.sol#L189 Project.sol#L195 Project.sol#L199 Project.sol#L238 Project.sol#L241 Project.sol#L245 Project.sol#L277 Project.sol#L301 Project.sol#L308 Project.sol#L341 Project.sol#L369 Project.sol#L406 Project.sol#L511 Project.sol#L515 Project.sol#L521 Project.sol#L530 Project.sol#L753 Project.sol#L886 Project.sol#L906 Community.sol#L69 Community.sol#L75 Community.sol#L81 Community.sol#L90 Community.sol#L131 Community.sol#L159 Community.sol#L191 Community.sol#L235 Community.sol#L241 Community.sol#L248 Community.sol#L251 Community.sol#L312 Community.sol#L347 Community.sol#L353 Community.sol#L384 Community.sol#L400 Community.sol#L491 Community.sol#L536 Community.sol#L539 Community.sol#L557 Community.sol#L568 Community.sol#L764 Community.sol#L792 Community.sol#L886 Tasks.sol#L44 Tasks.sol#L50 Tasks.sol#L56 Tasks.sol#L124
If needed, the value can be read from the verified contract source code. Savings are due to the compiler not having to create non-payable getter functions for deployment calldata, and not adding another entry to the method ID table
Project.sol#L60 uint256 public constant override VERSION = 25000;
When 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. Use a larger size then downcast where needed
DebtToken.sol#L16 DebtToken.sol#L47 DebtToken.sol#L82 Disputes.sol#L100 Disputes.sol#L107 Project.sol#L507 SignatureDecoder.sol#L29 SignatureDecoder.sol#L65
Use a solidity version of at least 0.8.8 to have user defined value types as a major feature, improves overriding interface functions and reading from immutables. Use a solidity version of at least 0.8.9 to have user defined value type with the fix storage layout of user defined value types for underlying types shorter than 32 bytes. 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.11 to have new builtin function abi.encodeCall(functionPointer, (arg1, arg2, ...)) that type-checks the arguments and returns the ABI-encoded function call data. Use a solidity version of at least 0.8.12 to have Yul Optimizer: Remove mstore and sstore operations if the slot already contains the same value. Use a solidity version of at least 0.8.13 to have Allow annotating inline assembly as memory-safe to allow optimizations and stack limit evasion that rely on respecting Solidity's memory model.
DebtToken.sol#L3 ProjectFactory.sol#L3 HomeFiProxy.sol#L3 Disputes.sol#L3 HomeFi.sol#L3 Project.sol#L3 Community.sol#L3 SignatureDecoder.sol#L3 Tasks.sol#L3
Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas), and to avoid Gsset (20000 gas) when changing from 'false' to 'true', after having been 'true' in the past
DebtToken.sol#L95 DebtToken.sol#L103 ProjectFactory.sol#L102 HomeFiProxy.sol#L30 HomeFiProxy.sol#L168 Disputes.sol#L144 Disputes.sol#L180 Disputes.sol#L191 HomeFi.sol#L50 HomeFi.sol#L243 HomeFi.sol#L268 Project.sol#L68 Project.sol#L78 Project.sol#L84 Project.sol#L148 Project.sol#L412 Project.sol#L582 Project.sol#L720 Project.sol#L730 Project.sol#L750 Community.sol#L55 Community.sol#L61 Community.sol#L642 Community.sol#L713 Tasks.sol#L16 Tasks.sol#L178
Use calldata instead of memory in a function parameter when you are only to read the data can save gas by storing it in calldata
The instances below point to the second access of a state variable within a function. Caching will replace each Gwarmaccess (100 gas) with a much cheaper stack read. Less obvious optimizations include having local storage variables of mappings within state variable mappings or mappings within state variable structs, having local storage variables of structs within mappings, or having local caches of state variable contracts/addresses.
Community.lendToProject accesing to _communities variable Community.sol#L385 Community.sol#L402 Community.sol#L405 Community.sol#L412 Community.sol#L427
Community.members accesing to _communities variable. Community.sol#L620 Community.sol#L624 Community.sol#L625
Community.returnToLender accesing to _communities when can use _communityProject Community.sol#L692
The declare of variables are before an if and those variables not used in other places than inside the if. Move the variables inside to save gas when the condition is false.
Community.claimInterest declare _lender and _communityProject Community.sol#L836 Community.sol#L837
The default βcheckedβ behavior costs more gas when adding/diving/multiplying, because under-the-hood those checks are implemented as a series of opcodes that, prior to performing the actual arithmetic, check for under/overflow and revert if it is detected. if it can statically be determined there is no possible way for your arithmetic to under/overflow (such as a condition in an if statement), surrounding the arithmetic in an unchecked block will save gas.
For all for-loops in the code it is possible to change as the following example.
for (uint256 i;i < X;){ -- code -- unchecked { ++i; } }
HomeFiProxy.sol#L87 HomeFiProxy.sol#L136 Project.sol#L248 Project.sol#L311 Project.sol#L322 Project.sol#L368 Project.sol#L603 Project.sol#L650 Project.sol#L710 Community.sol#L624 Tasks.sol#L181
If a variable is not set/initialized, it is assumed to have the default value (0 for uint, false for bool, address(0) for address,...). Explicitly initializing it with its default value is an anti-pattern and wastes gas.
HomeFiProxy.sol#L87 HomeFiProxy.sol#L136 Project.sol#L248 Project.sol#L311 Project.sol#L322 Community.sol#L624 Tasks.sol#L181
In the following places, require another change to not initialize the variables. Modifify the condition for _taskID < _length + 1 and use inside the loop the variable as _taskID + 1 to access to the array.
Project.sol#L368 Project.sol#L710
public functions that are never called by the contract should be declared external to save gas.
DebtToken.sol#L82 DebtToken.sol#L91 DebtToken.sol#L100
Reorder the variables declaration in the code to save gas. It's important than variables are together until full a slot.
Move contractorDelegated after contractorConfirmed to store in the same slot and save 1 slot. Project.sol#L78 Move restrictedToAdmin after tokenCurrency3 to store in the same slot and save 1 slot. Community.sol#L55
Dead code is not used in the contract, and make the code's review more difficult and waste gas. Remove unused functions.
SignatureDecoder.sol#L20 SignatureDecoder.sol#L43 SignatureDecoder.sol#L61 Community.sol#L910 Tasks.sol#L119 Tasks.sol#L138 Tasks.sol#L175 Tasks.sol#L191 Tasks.sol#L106 Tasks.sol#L88 Tasks.sol#L148 Tasks.sol#L160
#0 - jack-the-pug
2022-08-28T09:14:07Z
"20. Dead code" wut?