Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gas Optimizations #390

Open
code423n4 opened this issue Aug 6, 2022 · 0 comments
Open

Gas Optimizations #390

code423n4 opened this issue Aug 6, 2022 · 0 comments
Labels

Comments

@code423n4
Copy link
Contributor

[G-01] memory KEYWORD CAN BE USED INSTEAD OF storage KEYWORD

When there is no need to make a reference to a state value, the memory keyword can be used instead of the storage keyword to save gas. Accessing storage using sload is more expensive than accessing memory using mload. The memory keyword can be used for _communityProject below.

contracts\Community.sol
    679-698:
        // Local instance of variables. For saving gas.
        ProjectDetails storage _communityProject = _communities[_communityID]
            .projectDetails[_project];
        uint256 _lentAmount = _communityProject.lentAmount;

        // Calculate number of days difference current and last timestamp
        uint256 _noOfDays = (block.timestamp -
            _communityProject.lastTimestamp) / 86400; // 24*60*60

        /// Interest formula = (principal * APR * days) / (365 * 1000)
        // prettier-ignore
        uint256 _unclaimedInterest =
                _lentAmount *
                _communities[_communityID].projectDetails[_project].apr *
                _noOfDays /
                365000;

        // Old (already rTokens claimed) + new interest
        uint256 _totalInterest = _unclaimedInterest +
            _communityProject.interest;

[G-02] VARIABLE DOES NOT NEED TO BE INITIALIZED TO ITS DEFAULT VALUE

Explicitly initializing a variable with its default value costs more gas than uninitializing it. For example, uint256 i can be used instead of uint256 i = 0 in the following code.

contracts\Community.sol
  624: for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) {

contracts\HomeFiProxy.sol
  87: for (uint256 i = 0; i < _length; i++) {
  136: for (uint256 i = 0; i < _length; i++) {

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

contracts\libraries\Tasks.sol
  181: for (uint256 i = 0; i < _length; i++) _alerts[i] = _self.alerts[i];

[G-03] ARRAY LENGTH CAN BE CACHED OUTSIDE OF LOOP

Caching the array length outside of the loop and using the cached length in the loop costs less gas than reading the array length for each iteration. For example, _changeOrderedTask.length in the following code can be cached outside of the loop like uint256 _changeOrderedTaskLength = _changeOrderedTask.length, and i < _changeOrderedTaskLength can be used for each iteration.

contracts\Community.sol
  624: for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) {

contracts\Project.sol
  603: for (; i < _changeOrderedTask.length; i++) {

[G-04] ++VARIABLE CAN BE USED INSTEAD OF VARIABLE++

++variable costs less gas than variable++. For example, i++ can be changed to ++i in the following code.

contracts\Community.sol
  624: for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) {

contracts\HomeFiProxy.sol
  87: for (uint256 i = 0; i < _length; i++) {
  136: for (uint256 i = 0; i < _length; i++) {

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++) {
  650: for (++j; j <= taskCount; j++) {
  710: for (uint256 _taskID = 1; _taskID <= _length; _taskID++) {

contracts\libraries\Tasks.sol
  181: for (uint256 i = 0; i < _length; i++) _alerts[i] = _self.alerts[i];

[G-05] X = X + Y OR X = X - Y CAN BE USED INSTEAD OF X += Y OR X -= Y

x = x + y or x = x - y costs less gas than x += y or x -= y. For example, _interest -= _repayAmount can be changed to _interest = _interest - _repayAmount in the following code.

contracts\Community.sol
  423: .totalLent += _amountToProject;
  435: .lentAmount += _lendingAmount;
  798: _interest -= _repayAmount;

contracts\HomeFi.sol
  289: projectCount += 1;

contracts\Project.sol
  179: hashChangeNonce += 1;
  250: _taskCount += 1;
  290: hashChangeNonce += 1;
  431: totalAllocated -= _withdrawDifference;
  440: totalAllocated += _newCost - _taskCost;
  456: totalAllocated -= _taskCost;
  616: _costToAllocate -= _taskCost;
  663: _costToAllocate -= _taskCost;
  711: _cost += tasks[_taskID].cost;
  772: totalLent -= _amount;

contracts\libraries\SignatureDecoder.sol
  83: v += 27;

[G-06] ARITHMETIC OPERATIONS THAT DO NOT OVERFLOW CAN BE UNCHECKED

Explicitly unchecking arithmetic operations that do not overflow by wrapping these in unchecked {} costs less gas than implicitly checking these.

For the following loops, if increasing the counter variable is very unlikely to overflow, then unchecked {++i} at the end of the loop block can be used, where i is the counter variable.

contracts\Community.sol
  624: for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) {

contracts\HomeFiProxy.sol
  87: for (uint256 i = 0; i < _length; i++) {
  136: for (uint256 i = 0; i < _length; i++) {

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++) {
  650: for (++j; j <= taskCount; j++) {
  710: for (uint256 _taskID = 1; _taskID <= _length; _taskID++) {

contracts\libraries\Tasks.sol
  181: for (uint256 i = 0; i < _length; i++) _alerts[i] = _self.alerts[i];

[G-07] REVERT WITH CUSTOM ERROR CAN BE USED INSTEAD OF REQUIRE() OR REVERT() WITH REASON STRING

revert with custom error can cost less gas than require() or revert() with reason string. Please consider using revert with custom error to replace the following require() and revert().

contracts\Community.sol
  69: require(_address != address(0), "Community::0 address");
  75: require(_msgSender() == homeFi.admin(), "Community::!admin");
  81: require(
  90: require(
  131: require(
  159: require(
  191: require(
  235: require(
  241: require(homeFi.isProjectExist(_project), "Community::Project !Exists");
  248: require(_community.isMember[_builder], "Community::!Member");
  251: require(
  312: require(
  347: require(
  353: require(
  384: require(
  400: require(
  491: require(
  536: require(_builder == _projectInstance.builder(), "Community::!Builder");
  539: require(
  557: require(!restrictedToAdmin, "Community::restricted");
  568: require(restrictedToAdmin, "Community::!restricted");
  764: require(_repayAmount > 0, "Community::!repay");
  792: require(_lentAndInterest >= _repayAmount, "Community::!Liquid");
  886: require(

contracts\DebtToken.sol
  31: require(
  50: require(_communityContract != address(0), "DebtToken::0 address");
  96: revert("DebtToken::blocked");
  104: revert("DebtToken::blocked");

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(
  106: require(
  183: require(_result, "Disputes::!Member");

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(

contracts\HomeFiProxy.sol
  41: require(_address != address(0), "Proxy::0 address");
  81: require(_length == _implementations.length, "Proxy::Lengths !match");
  105: require(
  133: require(_length == _contractAddresses.length, "Proxy::Lengths !match");

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(
  195: require(_cost > 0, "Project::!value>0");
  199: require(
  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(
  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(
  521: require(
  530: require(getAlerts(_task)[2], "Project::!SCConfirmed");
  753: require(_sc != address(0), "Project::0 address");
  886: require(
  906: require(

contracts\ProjectFactory.sol
  36: require(_address != address(0), "PF::0 address");
  64: require(
  84: require(_msgSender() == homeFi, "PF::!HomeFiContract");

contracts\libraries\Tasks.sol
  44: require(_self.state == TaskStatus.Inactive, "Task::active");
  50: require(_self.state == TaskStatus.Active, "Task::!Active");
  56: require(
  124: require(_self.subcontractor == _sc, "Task::!SC");

[G-08] NEWER VERSION OF SOLIDITY CAN BE USED

The protocol can benefit from more gas-efficient features and fixes by using a newer version of Solidity. Changes for newer Solidity versions can be viewed here.

contracts\Community.sol
  3: pragma solidity 0.8.6;

contracts\DebtToken.sol
  3: pragma solidity 0.8.6;

contracts\Disputes.sol
  3: pragma solidity 0.8.6;

contracts\HomeFi.sol
  3: pragma solidity 0.8.6;

contracts\HomeFiProxy.sol
  3: pragma solidity 0.8.6;

contracts\Project.sol
  3: pragma solidity 0.8.6;

contracts\ProjectFactory.sol
  3: pragma solidity 0.8.6;

contracts\interfaces\ICommunity.sol
  3: pragma solidity 0.8.6;

contracts\interfaces\IDebtToken.sol
  3: pragma solidity 0.8.6;

contracts\interfaces\IDisputes.sol
  3: pragma solidity 0.8.6;

contracts\interfaces\IHomeFi.sol
  3: pragma solidity 0.8.6;

contracts\interfaces\IProject.sol
  3: pragma solidity 0.8.6;

contracts\interfaces\IProjectFactory.sol
  3: pragma solidity 0.8.6;

contracts\libraries\SignatureDecoder.sol
  3: pragma solidity 0.8.6;

contracts\libraries\Tasks.sol
  3: pragma solidity 0.8.6;
@code423n4 code423n4 added bug Something isn't working G (Gas Optimization) labels Aug 6, 2022
code423n4 added a commit that referenced this issue Aug 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants