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 #312

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

Gas Optimizations #312

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

Comments

@code423n4
Copy link
Contributor

Issue 1 Use memory variables instead of state variables to save gas

In allocateFunds() from Project.sol, the function loops through all items in the dynamic array _changeOrderedTask using its length. However, the length is read from storage every loop, consider saving the length in memory and using that in the for loop

Additionally, this applies for looping up to taskCount

Consider rewriting to:

   function allocateFunds() public override {
        // Max amount out times this loop will run
        // This is to ensure the transaction do not run out of gas (max gas limit)
        uint256 _maxLoop = 50;

        // Difference of totalLent and totalAllocated is what can be used to allocate new tasks
        uint256 _costToAllocate = totalLent - totalAllocated;

        // Bool if max loop limit is exceeded
        bool _exceedLimit;

        // Local instance of lastAllocatedChangeOrderTask. To save gas.
        uint256 i = lastAllocatedChangeOrderTask;

        // Local instance of lastAllocatedTask. To save gas.
        uint256 j = lastAllocatedTask;

        uint256 _taskCount = taskCount;
        uint256 length = _changeOrderedTask.length;

        // Initialize empty array in which allocated tasks will be added.
        uint256[] memory _tasksAllocated = new uint256[](
            _taskCount - j + length - i
        );

        // Number of times a loop has run.
        uint256 _loopCount;

        /// CHANGE ORDERED TASK FUNDING ///
        

        // Any tasks added to _changeOrderedTask will be allocated first
        if (length > 0) {
            // Loop from lastAllocatedChangeOrderTask to _changeOrderedTask length (until _maxLoop)
            for (; i < length; i++) {
                // Local instance of task cost. To save gas.
                uint256 _taskCost = tasks[_changeOrderedTask[i]].cost;

                // If _maxLoop limit is reached then stop looping
                if (_loopCount >= _maxLoop) {
                    _exceedLimit = true;
                    break;
                }

                // If there is enough funds to allocate this task
                if (_costToAllocate >= _taskCost) {
                    // Reduce task cost from _costToAllocate
                    _costToAllocate -= _taskCost;

                    // Mark the task as allocated
                    tasks[_changeOrderedTask[i]].fundTask();

                    // Add task to _tasksAllocated array
                    _tasksAllocated[_loopCount] = _changeOrderedTask[i];

                    // Increment loop counter
                    _loopCount++;
                }
                // If there are not enough funds to allocate this task then stop looping
                else {
                    break;
                }
            }

            // If all the change ordered tasks are allocated, then delete
            // the changeOrderedTask array and reset lastAllocatedChangeOrderTask.
            if (i == length) {
                lastAllocatedChangeOrderTask = 0;
                delete _changeOrderedTask;
            }
            // Else store the last allocated change order task index.
            else {
                lastAllocatedChangeOrderTask = i;
            }
        }

        /// TASK FUNDING ///

        // If lastAllocatedTask is lesser than taskCount, that means there are un-allocated tasks
        if (j < _taskCount) {
            // Loop from lastAllocatedTask + 1 to taskCount (until _maxLoop)
            for (++j; j <= _taskCount; j++) {
                // Local instance of task cost. To save gas.
                uint256 _taskCost = tasks[j].cost;

                // If _maxLoop limit is reached then stop looping
                if (_loopCount >= _maxLoop) {
                    _exceedLimit = true;
                    break;
                }

                // If there is enough funds to allocate this task
                if (_costToAllocate >= _taskCost) {
                    // Reduce task cost from _costToAllocate
                    _costToAllocate -= _taskCost;

                    // Mark the task as allocated
                    tasks[j].fundTask();

                    // Add task to _tasksAllocated array
                    _tasksAllocated[_loopCount] = j;

                    // Increment loop counter
                    _loopCount++;
                }
                // If there are not enough funds to allocate this task then stop looping
                else {
                    break;
                }
            }

            // If all pending tasks are allocated store lastAllocatedTask equal to taskCount

            if (j > _taskCount) {
                lastAllocatedTask = _taskCount;
            }
            // If not all tasks are allocated store updated lastAllocatedTask
            else {
                lastAllocatedTask = --j;
            }
        }

        // If any tasks is allocated, then emit event
        if (_loopCount > 0) emit TaskAllocated(_tasksAllocated);

        // If allocation was incomplete, then emit event
        if (_exceedLimit) emit IncompleteAllocation();

        // Update totalAllocated with all allocations
        totalAllocated = totalLent - _costToAllocate;
    }

Using tests from repo:
average gas used for allocateFunds() before fix: 63493
average gas used for allocateFunds() after fix: 63085

Average gas saved: 408

@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