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

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

Gas Optimizations #383

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

Comments

@code423n4
Copy link
Contributor

Gas Optimizations Report

Table of Contents

  1. Don't Initialize Variables with Default Value
  2. Cache Array Length Outside of Loop
  3. Use != 0 instead of > 0 for Unsigned Integer Comparison
  4. ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, for example when used in for- and while-loops
  5. Prefix increments cheaper than Postfix increments
  6. Multiple address mappings can be combined into a single mapping of an address to a struct, where appropriate

1. Don't Initialize Variables with Default Value

Impact

Uninitialized variables are assigned with the types default value.
Explicitly initializing a variable with it's default value costs unnecesary gas.

Background Information

POC

  2022-08-rigor/contracts/Community.sol::624 => for (uint256 i = 0; i < _communities[_communityID].memberCount; i++) {
  2022-08-rigor/contracts/HomeFiProxy.sol::87 => for (uint256 i = 0; i < _length; i++) {
  2022-08-rigor/contracts/HomeFiProxy.sol::136 => for (uint256 i = 0; i < _length; i++) {
  2022-08-rigor/contracts/Project.sol::248 => for (uint256 i = 0; i < _length; i++) {
  2022-08-rigor/contracts/Project.sol::311 => for (uint256 i = 0; i < _length; i++) {
  2022-08-rigor/contracts/Project.sol::322 => for (uint256 i = 0; i < _length; i++) {
  2022-08-rigor/contracts/libraries/Tasks.sol::181 => for (uint256 i = 0; i < _length; i++) _alerts[i] = _self.alerts[i];

2. Cache Array Length Outside of Loop

Impact

Caching the array length outside a loop saves reading it on each iteration, as long as the array's length is not changed during the loop.

POC

2022-08-rigor/contracts/Project.sol::603 => for (; i < _changeOrderedTask.length; i++) {

Background Information

3. Use != 0 instead of > 0 for Unsigned Integer Comparison

Impact

When dealing with unsigned integer types, comparisons with != 0 are cheaper
then with > 0. This change saves 6 gas per instance.

POC

2022-08-rigor/contracts/Community.sol::764 => require(_repayAmount > 0, "Community::!repay");
2022-08-rigor/contracts/Community.sol::840 => if (_interestEarned > 0) {
2022-08-rigor/contracts/Disputes.sol::107 => _actionType > 0 && _actionType <= uint8(ActionType.TaskPay),
2022-08-rigor/contracts/Project.sol::195 => require(_cost > 0, "Project::!value>0");
2022-08-rigor/contracts/Project.sol::380 => if (_leftOutTokens > 0) {
2022-08-rigor/contracts/Project.sol::691 => if (_loopCount > 0) emit TaskAllocated(_tasksAllocated);

4. ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, for example when used in for- and while-loops

Impact

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

POC

2022-08-rigor/contracts/HomeFiProxy.sol::87 => for (uint256 i = 0; i < _length; i++)
2022-08-rigor/contracts/HomeFiProxy.sol::136 => for (uint256 i = 0; i < _length; i++) {
2022-08-rigor/contracts/Project.sol::311 => for (uint256 i = 0; i < _length; i++) {
2022-08-rigor/contracts/libraries/Tasks.sol::181 => for (uint256 i = 0; i < _length; i++) _alerts[i] = _self.alerts[i];

5. Prefix increments cheaper than Postfix increments

Impact

++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too) Saves S gas PER LOOP

POC

2022-08-rigor/contracts/HomeFiProxy.sol::87 => for (uint256 i = 0; i < _length; i++)
2022-08-rigor/contracts/HomeFiProxy.sol::136 => for (uint256 i = 0; i < _length; i++) {
2022-08-rigor/contracts/Project.sol::311 => for (uint256 i = 0; i < _length; i++) {
2022-08-rigor/contracts/libraries/Tasks.sol::181 => for (uint256 i = 0; i < _length; i++) _alerts[i] = _self.alerts[i];

6. Multiple address mappings can be combined into a single mapping of an address to a struct, where appropriate

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. Finally, if both fields are accessed in the same function, can save -42 gas per access due to not having to recalculate the key's keccak256 hash (Gkeccak256 - 30 gas) and that calculation's associated stack operations.

POC

https://github.com/code-423n4/2022-08-rigor/blob/5ab7ea84a1516cb726421ef690af5bc41029f88f/contracts/Community.sol#L41
@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