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: 80/133
Findings: 2
Award: $62.35
🌟 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.6216 USDC - $40.62
Description: In the function createCommunity communities.members[i] is set with i being the 0. In addMember communities.members[i] is set using the variable memberCount after it has been updated. As memberCount will already equal 1 the first time the function addMember will be called index 2 will be the first position a new member will be added.
LOC: Community.sol#L146-L147 Community.sol#L198-L199
Recommendation: Switch line 118 and 117 so that members is added before the increment of memberCount.
Description Critical changes such as replacing the admin should be a 2 step process to protect against human error. While the errors are unlikely important parts of the contract would become unusable if they occured.
LOC: HomeFi.sol#L157-L168
Recommendation: Consider changing the replaceAdmin function to be a 2 step procedure where the new admin must accept the admin role before the previous admin loses their privileges.
Description: As per openZepplin safeMint() should be used instead of mint() to prevent the loss of NFT's if the receiver is a contract account that hasn't implemented ERC721Receiver.
LOC: HomeFi.sol#L292
Recommendation: Replace mint() with safeMint().
LOC: Project.sol#L514 - Change Revet to Revert Project.sol#L520 - Change Revet to Revert Community.sol#L849 - Change Burn to Mint
🌟 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.7291 USDC - $21.73
Description: The state variable projectCount is referenced 3 times without ever being modified. 3 SLOAD's can be saved by saving the return value of mintNFT() on L225 to a local variable and using that instead.
LOC: HomeFi.sol#L225-L231
Description: The state variable contractorDelegated can be moved up to line 70 to be packed into 1 storage slot with contractor & contractorConfirmed. This will save 1 storage slot (~20,000 gas).
LOC: Project.sol#L78
Description: As your using a solidity version > 0.8.4 you can replace revert strings with custom errors. This will save in deployment costs and runtime costs. Based on a test in remix, replacing a single revert string with a custom error saved 12,404 gas in deployment cost and 86 gas on each function call.
contract Test { uint256 a; function check() external { require(a != 0, "check failed"); } } (Deployment cost: 114,703, Cost on Function call: 23,392) vs contract Test { uint256 a; error checkFailed(); function check() external { if (a != 0) revert checkFailed(); } } (Deployment cost: 102,299, Cost on Function call: 23,306)
LOC: Their are 74 instances of revert strings throughout the Rigor contracts that can be replaced with custom errors.
Description: When incrementing i in for loops there is no chance of overflow so unchecked can be used to save gas. I ran a simple test in remix and found deployment savings of 31,653 gas and on each function call saved ~141 gas per iteration.
contract Test { function loopTest() external { for (uint256 i; i < 1; ++i) { Deployment Cost: 125,637, Cost on function call: 24,601 vs for (uint256 i; i < 1; ) { // for loop body unchecked { ++i; } Deployment Cost: 93,984, Cost on function call: 24,460 } } }
In for loops pre increments can also be used to save a small amount of gas per iteration. I ran a test in remix using a for loop and found the deployment savings of 497 gas and ~5 gas per iteration.
contract Test { function loopTest() external { for (uint256 i; i < 1; i++) { (Deployment cost: 118,408, Cost on function call: 24,532) vs for (uint256 i; i < 1; ++i) { (Deployment cost: 117,911, Cost on function call: 24,527) } } }
It is also recommended not to loop over state variables as an SLOAD will need to be done every loop. Recommend caching to memory and looping over that instead.
LOC: Community.sol#L624-L626 HomeFiProxy.sol#L87-L89 HomeFiProxy.sol#L136-L138 Project.sol#L248-L257 Project.sol#L311-L313 Project.sol#L322-L324 Project.sol#L368-L370 Project.sol#L603-L631 Project.sol#L650-L678 Project.sol#L710-L712 Tasks.sol#L181
Description: Based on test in remix you can save ~1,007 gas on deployment and ~15 gas on execution cost if you use x = x + y over x += y. (Is only true for storage variables)
contract Test { uint256 x = 1; function test() external { x += 3; (Deployment Cost: 153,124, Execution Cost: 30,369) vs x = x + 1; (Deployment Cost: 152,117, Execution Cost: 30,354) } }
LOC: Community.sol#L423 Community.sol#L433 HomeFi.sol#L289 Project.sol#L179 Project.sol#L290 Project.sol#L440