Rigor Protocol contest - gogo's results

Community lending and instant payments for new home construction.

General Information

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

Rigor Protocol

Findings Distribution

Researcher Performance

Rank: 60/133

Findings: 2

Award: $66.01

🌟 Selected for report: 0

🚀 Solo Findings: 0

2022-08-RIGOR

Low Risk and Non-Critical Issues

Events not emmited on important state changes

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)

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Community.sol

File: contracts/DebtToken.sol

43:   function initialize(

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/DebtToken.sol

File: contracts/Disputes.sol

74:   function initialize(address _homeFi)

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Disputes.sol

File: contracts/HomeFi.sol

92:   function initialize(

200:  function setTrustedForwarder(address _newForwarder)

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/HomeFi.sol

File: contracts/HomeFiProxy.sol

58:   function initiateHomeFi(address[] calldata _implementations)

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/HomeFiProxy.sol

File: contracts/Project.sol

94:   function initialize(

543:  function getTask(uint256 id)

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

File: contracts/ProjectFactory.sol

45:   function initialize(address _underlying, address _homeFi)

58:   function changeProjectImplementation(address _underlying)

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/ProjectFactory.sol

public functions not called by the contract should be declared external instead

There 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(

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/DebtToken.sol

File: contracts/HomeFi.sol

264:  function isTrustedForwarder(address _forwarder)

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/HomeFi.sol

File: contracts/libraries/Tasks.sol

75:   function initialize(Task storage _self, uint256 _cost) public {

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/libraries/Tasks.sol

2022-08-RIGOR

Gas Optimizations Report

The usage of ++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++) {

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Community.sol

File: contracts/HomeFiProxy.sol

87:   for (uint256 i = 0; i < _length; i++) {

136:  for (uint256 i = 0; i < _length; i++) {

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/HomeFiProxy.sol

File: contracts/libraries/Tasks.sol

181:  for (uint256 i = 0; i < _length; i++) _alerts[i] = _self.alerts[i];

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/libraries/Tasks.sol

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++) {

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

State variables should be cached in stack variables rather than re-reading them.

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);

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Community.sol

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;

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/HomeFi.sol

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]);

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/HomeFiProxy.sol

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;

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

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);

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/ProjectFactory.sol

It costs more gas to initialize non-constant/non-immutable variables to zero than to let the default of zero be applied

Not 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;

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Community.sol

File: contracts/HomeFiProxy.sol

87:   for (uint256 i = 0; i < _length; i++) {

136:  for (uint256 i = 0; i < _length; i++) {

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/HomeFiProxy.sol

File: contracts/libraries/Tasks.sol

181:  for (uint256 i = 0; i < _length; i++) _alerts[i] = _self.alerts[i];

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/libraries/Tasks.sol

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;

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

Using private rather than public for constants, saves gas

If 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;

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

<array>.length should not be looked up in every loop of a for-loop

The 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++) {

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

File: contracts/Community.sol
      
      /// @audit Cache _communities[_communityID].memberCount
624:  for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) {

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Community.sol

++i/i++ should be unchecked{++I}/unchecked{I++} in for-loops

When 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++) {

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Community.sol

File: contracts/HomeFiProxy.sol

87:   for (uint256 i = 0; i < _length; i++) {

136:  for (uint256 i = 0; i < _length; i++) {

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/HomeFiProxy.sol

File: contracts/libraries/Tasks.sol

181:  for (uint256 i = 0; i < _length; i++) _alerts[i] = _self.alerts[i];

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/libraries/Tasks.sol

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++) {

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

<x> += <y> costs more gas than <x> = <x> + <y> for state variables

There are 8 instances of this issue:

File: contracts/HomeFi.sol

289:  projectCount += 1;

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/HomeFi.sol

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;

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

Usage of uints/ints 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_

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/DebtToken.sol

File: contracts/Disputes.sol

100:  uint8 _actionType,

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Disputes.sol

File: contracts/libraries/SignatureDecoder.sol

29:   uint8 v;

65:   uint8 v,

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/libraries/SignatureDecoder.sol

Splitting require() statements that use && saves gas

Instead 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:  );

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Community.sol

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:  );

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Disputes.sol

Use calldata instead of memory for function parameters

If 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,

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Community.sol

File: contracts/DebtToken.sol

45:   string memory name_,

46:   string memory symbol_,

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/DebtToken.sol

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)

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Disputes.sol

File: contracts/HomeFi.sol

210:  function createProject(bytes memory _hash, address _currency)

284:  function mintNFT(address _to, string memory _tokenURI)

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/HomeFi.sol

File: contracts/libraries/SignatureDecoder.sol

22:   bytes memory messageSignatures,

61:   function signatureSplit(bytes memory signatures, uint256 pos)

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/libraries/SignatureDecoder.sol

File: contracts/Project.sol

878:  bytes memory _signature,

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

Replace 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");

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Community.sol

File: contracts/Disputes.sol

107:  _actionType > 0 && _actionType <= uint8(ActionType.TaskPay),

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Disputes.sol

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++) {

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

Tight variable packing

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

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Community.sol

File: contracts/Project.sol

40:        /// @audit Currently storage variables are packed in 16 slots but could fit in 15 by moving the contractorDelegated variable

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

Use immutable & constant for state variables that do not change their value

There are 6 instances of this issue:

File: contracts/Disputes.sol

29:   uint256 public override disputeCount;

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Disputes.sol

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;

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

Use custom errors rather than revert()/require() strings to save gas

Custom 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:  );

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Community.sol

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");

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/DebtToken.sol

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");

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Disputes.sol

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:  );

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/HomeFi.sol

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");

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/HomeFiProxy.sol

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");

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/libraries/Tasks.sol

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:  );

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

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");

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/ProjectFactory.sol

Using bools for storage variables incurs overhead

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;

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Community.sol

File: contracts/HomeFi.sol

50:   bool public override addrSet;

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/HomeFi.sol

File: contracts/Project.sol

68:   bool public override contractorConfirmed;

78:   bool public override contractorDelegated;

https://github.com/code-423n4/2022-08-rigor/blob/b17b2a11d04289f9e927c71703b42771dd7b86a4/contracts/Project.sol

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter