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

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

Gas Optimizations #112

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

Comments

@code423n4
Copy link
Contributor

(1) .length Should Not Be Looked Up In Every Loop Of A For-loop

Severity: Gas Optimizations

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 (3 gas), and gets rid of the extra DUP needed to store the stack offset

Proof Of Concept

for (; i < _changeOrderedTask.length; i++) {

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L603

(2) ++i Costs Less Gas Than i++, Especially When It’s Used In For-loops (--i/i-- Too)

Severity: Gas Optimizations

Saves 6 gas per loop

Proof Of Concept

for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) {

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L624

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/HomeFiProxy.sol#L87

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/HomeFiProxy.sol#L136

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L248

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L311

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L322

for (; i < _changeOrderedTask.length; i++) {

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L603

for (uint256 _taskID = 1; _taskID <= _length; _taskID++) {

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L710

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/libraries/Tasks.sol#L181

Recommended Mitigation Steps

for example, use ++i instead of i++

(3) It Costs More Gas To Initialize Variables To Zero Than To Let The Default Of Zero Be Applied

Severity: Gas Optimizations

Proof Of Concept

for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) {

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L624

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/HomeFiProxy.sol#L87

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/HomeFiProxy.sol#L136

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L248

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L311

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L322

(4) Using > 0 Costs More Gas Than != 0 When Used On A Uint In A Require() Statement

Severity: Gas Optimizations

This change saves 6 gas per instance

Proof Of Concept

require(_repayAmount > 0, "Community::!repay");

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L764

require(_cost > 0, "Project::!value>0");

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L195

(5) Multiple Address Mappings Can Be Combined Into A Single Mapping Of An Address To A Struct, Where Appropriate

Severity: Gas Optimizations

Saves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot.

Proof Of Concept

mapping(address => uint256) public override projectPublished;
mapping(address => mapping(bytes32 => bool)) public override approvedHashes;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L59

mapping(address => uint256) public override projectTokenId;
mapping(address => address) public override wrappedToken;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/HomeFi.sol#L64

(6) Multiplication/division By Two Should Use Bit Shifting

Severity: Gas Optimizations

* 2 is equivalent to << 1 and / 2 is the same as >> 1. The MUL and DIV opcodes cost 5 gas, whereas SHL and SHR only cost 3 gas

Proof Of Concept

_communityProject.lastTimestamp) / 86400; // 24*60*60

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L686

(7) += Costs More Gas Than = + For State Variables

Severity: Gas Optimizations

Proof Of Concept

.totalLent += _amountToProject;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L423

.lentAmount += _lendingAmount;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L435

.totalLent += _amountToProject;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L423

.lentAmount += _lendingAmount;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L435

_interest -= _repayAmount;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L798

projectCount += 1;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/HomeFi.sol#L289

hashChangeNonce += 1;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L179

_taskCount += 1;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L250

hashChangeNonce += 1;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L290

totalAllocated -= _withdrawDifference;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L431

totalAllocated += _newCost - _taskCost;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L440

totalAllocated -= _taskCost;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L456

totalAllocated -= _withdrawDifference;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L431

totalAllocated += _newCost - _taskCost;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L440

totalAllocated -= _taskCost;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L456

totalAllocated -= _withdrawDifference;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L431

totalAllocated += _newCost - _taskCost;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L440

totalAllocated -= _taskCost;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L456

_costToAllocate -= _taskCost;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L616

_costToAllocate -= _taskCost;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L616

_cost += tasks[_taskID].cost;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L711

totalLent -= _amount;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L772

v += 27;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/libraries/SignatureDecoder.sol#L83

(8) Using Private Rather Than Public For Constants, Saves Gas

Severity: Gas Optimizations

If needed, the value can be read from the verified contract source code. Savings are due to the compiler not having to create non-payable getter functions for deployment calldata, and not adding another entry to the method ID table

Proof Of Concept

uint256 public constant override VERSION = 25000;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L60

Recommended Mitigation Steps

Set variable to private.

(9) Help The Optimizer By Saving A Storage Variable’s Reference Instead Of Repeatedly Fetching It

Severity: Gas Optimizations

To help the optimizer, declare a storage type variable and use it instead of repeatedly fetching the reference in a map or an array.
The effect can be quite significant.
As an example, instead of repeatedly calling someMap[someIndex], save its reference like this: SomeStruct storage someStruct = someMap[someIndex] and use it.

Proof Of Concept

CommunityStruct storage _community = _communities[communityCount];

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L143

Dispute storage _dispute = disputes[disputeCount];

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Disputes.sol#L112

cost = tasks[id].cost;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L553

subcontractor = tasks[id].subcontractor;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L554

state = tasks[id].state;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L555

cost = tasks[id].cost;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L553

subcontractor = tasks[id].subcontractor;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L554

state = tasks[id].state;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L555

cost = tasks[id].cost;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L553

subcontractor = tasks[id].subcontractor;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L554

state = tasks[id].state;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L555

(10) ++i/i++ Should Be Unchecked{++i}/unchecked{i++} When It Is Not Possible For Them To Overflow, As Is The Case When Used In For- And While-loops

Severity: Gas Optimizations

The unchecked keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas PER LOOP

Proof Of Concept

for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) {

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L624

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/HomeFiProxy.sol#L87

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/HomeFiProxy.sol#L136

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L248

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L311

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

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L322

for (; i < _changeOrderedTask.length; i++) {

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L603

for (++j; j <= taskCount; j++) {

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L650

for (; i < _changeOrderedTask.length; i++) {

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L603

for (++j; j <= taskCount; j++) {

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L650

for (uint256 _taskID = 1; _taskID <= _length; _taskID++) {

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L710

(11) Using Bools For Storage Incurs Overhead

Severity: Gas Optimizations

booleans are more expensive than uint256 or any type that takes up a full word because each write operation emits an extra SLOAD to first read the slot's contents, replace the bits taken up by the boolean, and then write back. This is the compiler's defense against contract upgrades and pointer aliasing, and it cannot be disabled.

Proof Of Concept

bool public override restrictedToAdmin;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L55

mapping(address => mapping(bytes32 => bool)) public override approvedHashes;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L61

bool public override restrictedToAdmin;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L55

mapping(address => mapping(bytes32 => bool)) public override approvedHashes;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Community.sol#L61

bool public override addrSet;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/HomeFi.sol#L50

mapping(address => bool) internal contractsActive;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/HomeFiProxy.sol#L30

bool public override contractorConfirmed;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L68

bool public override contractorDelegated;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L78

mapping(address => mapping(bytes32 => bool)) public override approvedHashes;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L84

bool public override contractorConfirmed;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L68

bool public override contractorDelegated;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L78

mapping(address => mapping(bytes32 => bool)) public override approvedHashes;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L84

bool public override contractorConfirmed;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L68

bool public override contractorDelegated;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L78

mapping(address => mapping(bytes32 => bool)) public override approvedHashes;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/Project.sol#L84

mapping(uint256 => bool) alerts;

https://github.com/code-423n4/2022-08-rigor/tree/main/contracts/libraries/Tasks.sol#L16

@code423n4 code423n4 added bug Something isn't working G (Gas Optimization) labels Aug 5, 2022
code423n4 added a commit that referenced this issue Aug 5, 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