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: 60/133
Findings: 2
Award: $66.01
🌟 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
Emmiting events is recommended each time when a state variable's value is being changed or just some critical event for the contract has occurred. It also helps off-chain monitoring of the contract's state.
There are 10 instances of this issue:
File: contracts/Community.sol 102: function initialize(address _homeFi)
File: contracts/DebtToken.sol 43: function initialize(
File: contracts/Disputes.sol 74: function initialize(address _homeFi)
File: contracts/HomeFi.sol 92: function initialize( 200: function setTrustedForwarder(address _newForwarder)
File: contracts/HomeFiProxy.sol 58: function initiateHomeFi(address[] calldata _implementations)
File: contracts/Project.sol 94: function initialize( 543: function getTask(uint256 id)
File: contracts/ProjectFactory.sol 45: function initialize(address _underlying, address _homeFi) 58: function changeProjectImplementation(address _underlying)
public
functions not called by the contract should be declared external
insteadThere are 5 instances of this issue:
File: contracts/DebtToken.sol 82: function decimals() public view virtual override returns (uint8) { 91: function transferFrom( 100: function transfer(
File: contracts/HomeFi.sol 264: function isTrustedForwarder(address _forwarder)
File: contracts/libraries/Tasks.sol 75: function initialize(Task storage _self, uint256 _cost) public {
🌟 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
25.3906 USDC - $25.39
++i
will cost less gas than i++
. The same change can be applied to i--
as well.This change would save up to 6 gas per instance/loop.
There are 13 instances of this issue:
File: contracts/Community.sol 140: communityCount++; 624: for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) {
File: contracts/HomeFiProxy.sol 87: for (uint256 i = 0; i < _length; i++) { 136: for (uint256 i = 0; i < _length; i++) {
File: contracts/libraries/Tasks.sol 181: for (uint256 i = 0; i < _length; i++) _alerts[i] = _self.alerts[i];
File: contracts/Project.sol 248: for (uint256 i = 0; i < _length; i++) { 311: for (uint256 i = 0; i < _length; i++) { 322: for (uint256 i = 0; i < _length; i++) { 368: for (uint256 _taskID = 1; _taskID <= _length; _taskID++) { 603: for (; i < _changeOrderedTask.length; i++) { 625: _loopCount++; 672: _loopCount++; 710: for (uint256 _taskID = 1; _taskID <= _length; _taskID++) {
The instances below point to the second+ access of a state variable within a function. Caching of a state variable replace each Gwarmaccess (100 gas) with a much cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.
There are 28* instances of this issue:
File: contracts/Community.sol /// @audit Cache `_communities[_communityID]`. Used 8 times in `lendToProject` 385: _sender == _communities[_communityID].owner, 402: _communities[_communityID] 405: _communities[_communityID] 412: IDebtToken _currency = _communities[_communityID].currency; 421: _communities[_communityID] 427: _communities[_communityID].projectDetails[_project].lentAmount > 0 433: _communities[_communityID] 438: _communities[_communityID] /// @audit Cache `_communities[_communityID]`. Used 2 times in `repayLender` 471: address _lender = _communities[_communityID].owner; 474: _communities[_communityID].currency.safeTransferFrom( /// @audit Cache `_communities[_communityID]`. Used 3 times in `members` 620: _communities[_communityID].memberCount 624: for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) { 625: _members[i] = _communities[_communityID].members[i]; /// @audit Cache `_communities[_communityID]`. Used 2 times in `returnToLender` 680: ProjectDetails storage _communityProject = _communities[_communityID] 692: _communities[_communityID].projectDetails[_project].apr * /// @audit Cache `_communities[_communityID]`. Used 2 times in `claimInterest` 836: address _lender = _communities[_communityID].owner; 837: ProjectDetails storage _communityProject = _communities[_communityID] /// @audit Cache `homeFi`. Used 3 times in `initialize` 113: tokenCurrency1 = homeFi.tokenCurrency1(); 114: tokenCurrency2 = homeFi.tokenCurrency2(); 115: tokenCurrency3 = homeFi.tokenCurrency3(); /// @audit Cache `homeFi`. Used 2 times in `createCommunity` 132: !restrictedToAdmin || _sender == homeFi.admin(), 137: homeFi.validCurrency(_currency); /// @audit Cache `homeFi`. Used 2 times in `lendToProject` 414: homeFi.wrappedToken(address(_currency)) 443: _currency.safeTransferFrom(_msgSender(), homeFi.treasury(), _lenderFee);
File: contracts/HomeFi.sol /// @audit Cache `projectCount`. Used 3 times in `createProject` 228: projects[projectCount] = _project; 229: projectTokenId[_project] = projectCount; 231: emit ProjectAdded(projectCount, _project, _sender, _currency, _hash); /// @audit Cache `projectCount`. Used 4 times in `mintNFT` 292: _mint(_to, projectCount); 293: _setTokenURI(projectCount, _tokenURI); 295: emit NftCreated(projectCount, _to); 296: return projectCount;
File: contracts/HomeFiProxy.sol /// @audit Cache `allContractNames`. Used 9 times in `initiateHomeFi` 69: allContractNames.push("HF"); 70: allContractNames.push("CN"); 71: allContractNames.push("DP"); 72: allContractNames.push("PF"); 73: allContractNames.push("DA"); 74: allContractNames.push("US"); 75: allContractNames.push("NT"); 78: uint256 _length = allContractNames.length; 88: _generateProxy(allContractNames[i], _implementations[i]);
File: contracts/Project.sol /// @audit Cache `tasks[_taskID]`. Used 3 times in `setComplete` 350: tasks[_taskID].setComplete(); 354: tasks[_taskID].subcontractor, 355: tasks[_taskID].cost /// @audit Cache `tasks[_taskID]`. Used 6 times in `changeOrder` 409: uint256 _taskCost = tasks[_taskID].cost; 423: if (tasks[_taskID].alerts[1]) { 449: tasks[_taskID].unApprove(); 452: tasks[_taskID].unAllocateFunds(); 470: if (_newSC != tasks[_taskID].subcontractor) { 474: tasks[_taskID].unApprove(); /// @audit Cache `tasks[_task]`. Used 2 times in `raiseDispute` 524: signer == tasks[_task].subcontractor, 528: if (signer == tasks[_task].subcontractor) { /// @audit Cache `tasks[id]`. Used 3 times in `getTask` 553: cost = tasks[id].cost; 554: subcontractor = tasks[id].subcontractor; 555: state = tasks[id].state; /// @audit Cache `tasks[_changeOrderedTask[i]]`. Used 4 times in `allocateFunds` 605: uint256 _taskCost = tasks[_changeOrderedTask[i]].cost; 619: tasks[_changeOrderedTask[i]].fundTask(); /// @audit Cache `tasks[j]`. Used 4 times in `allocateFunds` 652: uint256 _taskCost = tasks[j].cost; 666: tasks[j].fundTask(); /// @audit Cache `_changeOrderedTask`. Used 8 times in `allocateFunds` 592: taskCount - j + _changeOrderedTask.length - i 601: if (_changeOrderedTask.length > 0) { 603: for (; i < _changeOrderedTask.length; i++) { 605: uint256 _taskCost = tasks[_changeOrderedTask[i]].cost; 619: tasks[_changeOrderedTask[i]].fundTask(); 622: _tasksAllocated[_loopCount] = _changeOrderedTask[i]; 635: if (i == _changeOrderedTask.length) { 637: delete _changeOrderedTask; /// @audit Cache `homeFi`. Used 2 times in `initialize` 101: disputes = homeFi.disputesContract(); 102: lenderFee = homeFi.lenderFee(); /// @audit Cache `builder`. Used 2 times in `lendToProject` 190: _sender == builder || _sender == homeFi.communityContract(), 204: if (_sender == builder) { /// @audit Cache `builder`. Used 2 times in `checkSignature` 800: checkSignatureValidity(builder, _hash, _signature, 0); 812: checkSignatureValidity(builder, _hash, _signature, 0); /// @audit Cache `builder`. Used 2 times in `checkSignatureTask` 844: checkSignatureValidity(builder, _hash, _signature, 0); 858: checkSignatureValidity(builder, _hash, _signature, 0); /// @audit Cache `contractor`. Used 2 times in `raiseDispute` 516: signer == builder || signer == contractor, 523: signer == contractor || /// @audit Cache `contractor`. Used 2 times in `checkSignature` 798: if (contractor == address(0)) { 807: checkSignatureValidity(contractor, _hash, _signature, 0); 813: checkSignatureValidity(contractor, _hash, _signature, 1); /// @audit Cache `contractor`. Used 2 times in `checkSignatureTask` 842: if (contractor == address(0)) { 852: checkSignatureValidity(contractor, _hash, _signature, 0); 859: checkSignatureValidity(contractor, _hash, _signature, 1); /// @audit Cache `totalLent`. Used 2 times in `allocateFunds` 579: uint256 _costToAllocate = totalLent - totalAllocated; 697: totalAllocated = totalLent - _costToAllocate; /// @audit Cache `taskCount`. Used 5 times in `allocateFunds` 592: taskCount - j + _changeOrderedTask.length - i 648: if (j < taskCount) { 650: for (++j; j <= taskCount; j++) { 681: if (j > taskCount) { 682: lastAllocatedTask = taskCount;
File: contracts/ProjectFactory.sol /// @audit Cache `homeFi`. Used 2 times in `createProject` 84: require(_msgSender() == homeFi, "PF::!HomeFiContract"); 90: Project(_clone).initialize(_currency, _sender, homeFi);
constant
/non-immutable
variables to zero than to let the default of zero be appliedNot overwriting the default for stack variables saves 8 gas. Storage and memory variables have larger savings
There are 9 instances of this issue:
File: contracts/Community.sol 624: for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) { 793: _interest = 0;
File: contracts/HomeFiProxy.sol 87: for (uint256 i = 0; i < _length; i++) { 136: for (uint256 i = 0; i < _length; i++) {
File: contracts/libraries/Tasks.sol 181: for (uint256 i = 0; i < _length; i++) _alerts[i] = _self.alerts[i];
File: contracts/Project.sol 248: for (uint256 i = 0; i < _length; i++) { 311: for (uint256 i = 0; i < _length; i++) { 322: for (uint256 i = 0; i < _length; i++) { 412: bool _unapproved = false;
private
rather than public
for constants, saves gasIf needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that returns a tuple of the values of all currently-public constants. Saves 3406-3606 gas in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it's used, and not adding another entry to the method ID table
There are 1 instances of this issue:
File: contracts/Project.sol 60: uint256 public constant override VERSION = 25000;
<array>.length
should not be looked up in every loop of a for
-loopThe overheads outlined below are PER LOOP, excluding the first loop \ - storage arrays incur a Gwarmaccess (100 gas) \ - memory arrays use MLOAD
(3 gas) \ - calldata arrays use CALLDATALOAD
(3 gas)
Caching the length changes each of these to a DUP<N> (3 gas), and gets rid of the extra DUP<N> needed to store the stack offset
There are 1 instances of this issue:
File: contracts/Project.sol 603: for (; i < _changeOrderedTask.length; i++) {
File: contracts/Community.sol /// @audit Cache _communities[_communityID].memberCount 624: for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) {
++i
/i++
should be unchecked{++I}
/unchecked{I++}
in for
-loopsWhen an increment or any arithmetic operation is not possible to overflow it should be placed in unchecked{}
block. \This is because of the default compiler overflow and underflow safety checks since Solidity version 0.8.0. \In for-loops it saves around 30-40 gas per loop
There are 11 instances of this issue:
File: contracts/Community.sol 624: for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) {
File: contracts/HomeFiProxy.sol 87: for (uint256 i = 0; i < _length; i++) { 136: for (uint256 i = 0; i < _length; i++) {
File: contracts/libraries/Tasks.sol 181: for (uint256 i = 0; i < _length; i++) _alerts[i] = _self.alerts[i];
File: contracts/Project.sol 248: for (uint256 i = 0; i < _length; i++) { 311: for (uint256 i = 0; i < _length; i++) { 322: for (uint256 i = 0; i < _length; i++) { 368: for (uint256 _taskID = 1; _taskID <= _length; _taskID++) { 603: for (; i < _changeOrderedTask.length; i++) { /// @audit both ++j and j++ 650: for (++j; j <= taskCount; j++) { 710: for (uint256 _taskID = 1; _taskID <= _length; _taskID++) {
<x> += <y>
costs more gas than <x> = <x> + <y>
for state variablesThere are 8 instances of this issue:
File: contracts/HomeFi.sol 289: projectCount += 1;
File: contracts/Project.sol 179: hashChangeNonce += 1; 290: hashChangeNonce += 1; 772: totalLent -= _amount; 431: totalAllocated -= _withdrawDifference; 440: totalAllocated += _newCost - _taskCost; 456: totalAllocated -= _taskCost; 250: _taskCount += 1;
uint
s/int
s smaller than 32 bytes (256 bits) incurs overhead'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.' \ https://docs.soliditylang.org/en/v0.8.15/internals/layout_in_storage.html \ Use a larger size then downcast where needed
There are 5 instances of this issue:
File: contracts/DebtToken.sol 16: uint8 internal _decimals; 47: uint8 decimals_
File: contracts/Disputes.sol 100: uint8 _actionType,
File: contracts/libraries/SignatureDecoder.sol 29: uint8 v; 65: uint8 v,
require()
statements that use &&
saves gasInstead of using &&
on single require
check using two require
checks can save gas
There are 4 instances of this issue:
File: contracts/Community.sol 353: require( 354: _lendingNeeded >= _communityProject.totalLent && 355: _lendingNeeded <= IProject(_project).projectCost(), 356: "Community::invalid lending" 357: );
File: contracts/Disputes.sol 61: require( 62: _disputeID < disputeCount && 63: disputes[_disputeID].status == Status.Active, 64: "Disputes::!Resolvable" 65: ); 106: require( 107: _actionType > 0 && _actionType <= uint8(ActionType.TaskPay), 108: "Disputes::!ActionType" 109: );
calldata
instead of memory
for function parametersIf a reference type function parameter is read-only, it is cheaper in gas to use calldata instead of memory. Calldata is a non-modifiable, non-persistent area where function arguments are stored, and behaves mostly like memory. Try to use calldata as a data location because it will avoid copies and also makes sure that the data cannot be modified.
There are 13 instances of this issue:
File: contracts/Community.sol 488: bytes memory _details 761: bytes memory _details 874: bytes memory _signature,
File: contracts/DebtToken.sol 45: string memory name_, 46: string memory symbol_,
File: contracts/Disputes.sol 236: function executeTaskAdd(address _project, bytes memory _actionData) 254: function executeTaskChange(address _project, bytes memory _actionData) 268: function executeTaskPay(address _project, bytes memory _actionData)
File: contracts/HomeFi.sol 210: function createProject(bytes memory _hash, address _currency) 284: function mintNFT(address _to, string memory _tokenURI)
File: contracts/libraries/SignatureDecoder.sol 22: bytes memory messageSignatures, 61: function signatureSplit(bytes memory signatures, uint256 pos)
File: contracts/Project.sol 878: bytes memory _signature,
x <= y
with x < y + 1
, and x >= y
with x > y - 1
In the EVM, there is no opcode for >=
or <=
. When using greater than or equal, two operations are performed: >
and =
. Using strict comparison operators hence saves gas
There are 14 instances of this issue:
File: contracts/Community.sol 354: _lendingNeeded >= _communityProject.totalLent && 355: _lendingNeeded <= IProject(_project).projectCost(), 401: _amountToProject <= 792: require(_lentAndInterest >= _repayAmount, "Community::!Liquid");
File: contracts/Disputes.sol 107: _actionType > 0 && _actionType <= uint8(ActionType.TaskPay),
File: contracts/Project.sol 200: projectCost() >= uint256(_newTotalLent), 368: for (uint256 _taskID = 1; _taskID <= _length; _taskID++) { 438: else if (totalLent - _totalAllocated >= _newCost - _taskCost) { 608: if (_loopCount >= _maxLoop) { 614: if (_costToAllocate >= _taskCost) { 650: for (++j; j <= taskCount; j++) { 655: if (_loopCount >= _maxLoop) { 661: if (_costToAllocate >= _taskCost) { 710: for (uint256 _taskID = 1; _taskID <= _length; _taskID++) {
Solidity contracts have contiguous 32 bytes (256 bits) slots used in storage. By arranging the variables, it is possible to minimize the number of slots used within a contract’s storage and therefore reduce deployment costs.
There are 2 instances of this issue:
File: contracts/Community.sol 33: /// @audit Currently storage variables are packed in 9 slots but could fit in 8 bt moving the restrictedToAdmin variable
File: contracts/Project.sol 40: /// @audit Currently storage variables are packed in 16 slots but could fit in 15 by moving the contractorDelegated variable
immutable
& constant
for state variables that do not change their valueThere are 6 instances of this issue:
File: contracts/Disputes.sol 29: uint256 public override disputeCount;
File: contracts/Project.sol 40: address internal disputes; 52: IHomeFi public override homeFi; 54: IDebtToken public override currency; 56: uint256 public override lenderFee; 58: address public override builder;
revert()
/require()
strings to save gasCustom errors are available from solidity version 0.8.4. Custom errors save ~50 gas each time they are hit by avoiding having to allocate and store the revert string. Not defining the strings also save deployment gas
There are 76 instances of this issue:
File: contracts/Community.sol 69: require(_address != address(0), "Community::0 address"); 75: require(_msgSender() == homeFi.admin(), "Community::!admin"); 81: require( 82: projectPublished[_project] == _communityID, 83: "Community::!published" 84: ); 90: require( 91: _msgSender() == IProject(_project).builder(), 92: "Community::!Builder" 93: ); 131: require( 132: !restrictedToAdmin || _sender == homeFi.admin(), 133: "Community::!admin" 134: ); 159: require( 160: _communities[_communityID].owner == _msgSender(), 161: "Community::!owner" 162: ); 191: require( 192: !_community.isMember[_newMemberAddr], 193: "Community::Member Exists" 194: ); 235: require( 236: _publishNonce == _community.publishNonce, 237: "Community::invalid publishNonce" 238: ); 241: require(homeFi.isProjectExist(_project), "Community::Project !Exists"); 248: require(_community.isMember[_builder], "Community::!Member"); 251: require( 252: _projectInstance.currency() == _community.currency, 253: "Community::!Currency" 254: ); 312: require( 313: !_communityProject.publishFeePaid, 314: "Community::publish fee paid" 315: ); 347: require( 348: _communityProject.publishFeePaid, 349: "Community::publish fee !paid" 350: ); 353: require( 354: _lendingNeeded >= _communityProject.totalLent && 355: _lendingNeeded <= IProject(_project).projectCost(), 356: "Community::invalid lending" 357: ); 384: require( 385: _sender == _communities[_communityID].owner, 386: "Community::!owner" 387: ); 400: require( 401: _amountToProject <= 402: _communities[_communityID] 403: .projectDetails[_project] 404: .lendingNeeded - 405: _communities[_communityID] 406: .projectDetails[_project] 407: .totalLent, 408: "Community::lending>needed" 409: ); 491: require( 492: _msgSender() == _communities[_communityID].owner, 493: "Community::!Owner" 494: ); 536: require(_builder == _projectInstance.builder(), "Community::!Builder"); 539: require( 540: _lender == _communities[_communityID].owner, 541: "Community::!Owner" 542: ); 557: require(!restrictedToAdmin, "Community::restricted"); 568: require(restrictedToAdmin, "Community::!restricted"); 764: require(_repayAmount > 0, "Community::!repay"); 792: require(_lentAndInterest >= _repayAmount, "Community::!Liquid"); 886: require( 887: _recoveredSignature == _address || approvedHashes[_address][_hash], 888: "Community::invalid signature" 889: );
File: contracts/DebtToken.sol 31: require( 32: communityContract == _msgSender(), 33: "DebtToken::!CommunityContract" 34: ); 50: require(_communityContract != address(0), "DebtToken::0 address"); 96: revert("DebtToken::blocked"); 104: revert("DebtToken::blocked");
File: contracts/Disputes.sol 39: require(_address != address(0), "Disputes::0 address"); 46: require(homeFi.admin() == _msgSender(), "Disputes::!Admin"); 52: require(homeFi.isProjectExist(_msgSender()), "Disputes::!Project"); 61: require( 62: _disputeID < disputeCount && 63: disputes[_disputeID].status == Status.Active, 64: "Disputes::!Resolvable" 65: ); 106: require( 107: _actionType > 0 && _actionType <= uint8(ActionType.TaskPay), 108: "Disputes::!ActionType" 109: ); 183: require(_result, "Disputes::!Member");
File: contracts/HomeFi.sol 73: require(admin == _msgSender(), "HomeFi::!Admin"); 78: require(_address != address(0), "HomeFi::0 address"); 84: require(_oldAddress != _newAddress, "HomeFi::!Change"); 142: require(!addrSet, "HomeFi::Set"); 191: require(lenderFee != _newLenderFee, "HomeFi::!Change"); 255: require( 256: _currency == tokenCurrency1 || 257: _currency == tokenCurrency2 || 258: _currency == tokenCurrency3, 259: "HomeFi::!Currency" 260: );
File: contracts/HomeFiProxy.sol 41: require(_address != address(0), "Proxy::0 address"); 81: require(_length == _implementations.length, "Proxy::Lengths !match"); 105: require( 106: contractAddress[_contractName] == address(0), 107: "Proxy::Name !OK" 108: ); 133: require(_length == _contractAddresses.length, "Proxy::Lengths !match");
File: contracts/libraries/Tasks.sol 44: require(_self.state == TaskStatus.Inactive, "Task::active"); 50: require(_self.state == TaskStatus.Active, "Task::!Active"); 56: require( 57: _self.alerts[uint256(Lifecycle.TaskAllocated)], 58: "Task::!funded" 59: ); 124: require(_self.subcontractor == _sc, "Task::!SC");
File: contracts/Project.sol 123: require(!contractorConfirmed, "Project::GC accepted"); 132: require(_projectAddress == address(this), "Project::!projectAddress"); 135: require(_contractor != address(0), "Project::0 address"); 150: require(_msgSender() == builder, "Project::!B"); 153: require(contractor != address(0), "Project::0 address"); 176: require(_nonce == hashChangeNonce, "Project::!Nonce"); 189: require( 190: _sender == builder || _sender == homeFi.communityContract(), 191: "Project::!Builder&&!Community" 192: ); 195: require(_cost > 0, "Project::!value>0"); 199: require( 200: projectCost() >= uint256(_newTotalLent), 201: "Project::value>required" 202: ); 238: require(_taskCount == taskCount, "Project::!taskCount"); 241: require(_projectAddress == address(this), "Project::!projectAddress"); 245: require(_length == _taskCosts.length, "Project::Lengths !match"); 277: require(_nonce == hashChangeNonce, "Project::!Nonce"); 301: require( 302: _msgSender() == builder || _msgSender() == contractor, 303: "Project::!Builder||!GC" 304: ); 308: require(_length == _scList.length, "Project::Lengths !match"); 341: require(_projectAddress == address(this), "Project::!Project"); 369: require(tasks[_taskID].getState() == 3, "Project::!Complete"); 406: require(_project == address(this), "Project::!projectAddress"); 511: require(_project == address(this), "Project::!projectAddress"); 515: require( 516: signer == builder || signer == contractor, 517: "Project::!(GC||Builder)" 518: ); 521: require( 522: signer == builder || 523: signer == contractor || 524: signer == tasks[_task].subcontractor, 525: "Project::!(GC||Builder||SC)" 526: ); 530: require(getAlerts(_task)[2], "Project::!SCConfirmed"); 753: require(_sc != address(0), "Project::0 address"); 886: require( 887: _recoveredSignature == _address || approvedHashes[_address][_hash], 888: "Project::invalid signature" 889: ); 906: require( 907: ((_amount / 1000) * 1000) == _amount, 908: "Project::Precision>=1000" 909: );
File: contracts/ProjectFactory.sol 36: require(_address != address(0), "PF::0 address"); 64: require( 65: _msgSender() == IHomeFi(homeFi).admin(), 66: "ProjectFactory::!Owner" 67: ); 84: require(_msgSender() == homeFi, "PF::!HomeFiContract");
Use uint256(1)
and uint256(2)
for true
/false
to avoid a Gwarmaccess (100 gas) for the extra SLOAD, and to avoid Gsset (20000 gas) when changing from 'false' to 'true', after having been 'true' in the past
There are 4 instances of this issue:
File: contracts/Community.sol 55: bool public override restrictedToAdmin;
File: contracts/HomeFi.sol 50: bool public override addrSet;
File: contracts/Project.sol 68: bool public override contractorConfirmed; 78: bool public override contractorDelegated;