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

Open
code423n4 opened this issue Apr 1, 2022 · 1 comment
Open

Gas Optimizations #92

code423n4 opened this issue Apr 1, 2022 · 1 comment
Labels
bug Something isn't working G (Gas Optimization)

Comments

@code423n4
Copy link
Contributor

C4-001 : There is no need to assign default values to variables

Impact - Gas Optimization

When a variable is declared solidity assigns the default value. In case the contract assigns the value again, it costs extra gas.

Example: uint x = 0 costs more gas than uint x without having any different functionality.

Proof of Concept

  2022-03-joyn/core-contracts/contracts/CoreCollection.sol::279 => for (uint256 i = 0; i < _amount; i++) {

Tools Used

Code Review

Recommended Mitigation Steps

uint x = 0 costs more gas than uint x without having any different functionality.

C4-002 : Cache array length in for loops can save gas

Impact

Reading array length at each iteration of the loop takes 6 gas (3 for mload and 3 to place memory_offset) in the stack.

Caching the array length in the stack saves around 3 gas per iteration.

Proof of Concept

  1. Navigate to the following smart contract line.
  2022-03-joyn/core-contracts/contracts/CoreCollection.sol::205 => bytes(HASHED_PROOF).length == 0,
  2022-03-joyn/core-contracts/contracts/CoreFactory.sol::75 => _collections.length > 0,
  2022-03-joyn/core-contracts/contracts/CoreFactory.sol::79 => for (uint256 i; i < _collections.length; i++) {

Tools Used

None

Recommended Mitigation Steps

Consider to cache array length.

C4-003: > 0 can be replaced with != 0 for gas optimization

Impact

!= 0 is a cheaper operation compared to > 0, when dealing with uint.

Proof of Concept

  1. Navigate to the following contracts.
  2022-03-joyn/core-contracts/contracts/CoreCollection.sol::53 => _maxSupply > 0,
  2022-03-joyn/core-contracts/contracts/CoreCollection.sol::146 => require(amount > 0, "CoreCollection: Amount should be greater than 0");
  2022-03-joyn/core-contracts/contracts/CoreCollection.sol::161 => if (mintFee > 0) {
  2022-03-joyn/core-contracts/contracts/CoreCollection.sol::305 => IRoyaltyVault(royaltyVault).getVaultBalance() > 0
  2022-03-joyn/core-contracts/contracts/CoreFactory.sol::75 => _collections.length > 0,

Tools Used

Code Review

Recommended Mitigation Steps

Use "!=0" instead of ">0" for the gas optimization.

C4-004: Immutable variables

Impact

'immutable' greatly reduces gas costs. There are variables that do not change so they can be marked as immutable to greatly improve the gas costs.

Proof of Concept

2022-03-joyn/core-contracts/contracts/CoreCollection.sol::227 => keccak256(abi.encodePacked("CoreCollection", block.number))
2022-03-joyn/core-contracts/contracts/CoreFactory.sol::148 => new CoreProxy{salt: keccak256(abi.encodePacked(_collection.id))}(
2022-03-joyn/core-contracts/contracts/ERC721Claimable.sol::98 => return keccak256(abi.encodePacked(who, claimableAmount));

Tools Used

Code Review

Recommended Mitigation Steps

Mark variables as immutable.

C4-005: Revert String Size Optimization

Impact

Shortening revert strings to fit in 32 bytes will decrease deploy time gas and will decrease runtime gas when the revert condition has been met.

Revert strings that are longer than 32 bytes require at least one additional mstore, along with additional overhead for computing memory offset, etc.

Proof of Concept

Revert strings > 32 bytes are here:

2022-03-joyn/core-contracts/contracts/CoreCollection.sol::47 => require(!initialized, "CoreCollection: Already initialized");

Tools Used

Manual Review

Recommended Mitigation Steps

Shorten the revert strings to fit in 32 bytes. That will affect gas optimization.

C4-006 : Adding unchecked directive can save gas

Impact

For the arithmetic operations that will never over/underflow, using the unchecked directive (Solidity v0.8 has default overflow/underflow checks) can save some gas from the unnecessary internal over/underflow checks.

Proof of Concept

 2022-03-joyn/core-contracts/contracts/CoreCollection.sol::205 => bytes(HASHED_PROOF).length == 0,
  2022-03-joyn/core-contracts/contracts/CoreFactory.sol::75 => _collections.length > 0,
  2022-03-joyn/core-contracts/contracts/CoreFactory.sol::79 => for (uint256 i; i < _collections.length; i++) {

Tools Used

None

Recommended Mitigation Steps

Consider applying unchecked arithmetic where overflow/underflow is not possible.

C4-007 : Free gas savings for using solidity 0.8.10+

Impact

Using newer compiler versions and the optimizer gives gas optimizations and additional safety checks are available for free.

Proof of Concept

Solidity 0.8.10 has a useful change which reduced gas costs of external calls which expect a return value: https://blog.soliditylang.org/2021/11/09/solidity-0.8.10-release-announcement/

Code Generator: Skip existence check for external contract if return data is expected. In this case, the ABI decoder will revert if the contract does not exist

All Contracts

Tools Used

None

Recommended Mitigation Steps

Consider to upgrade pragma to at least 0.8.10.

C4-008 : Use calldata instead of memory for function parameters

Impact

In some cases, having function arguments in calldata instead of
memory is more optimal.

Consider the following generic example:

contract C {
function add(uint[] memory arr) external returns (uint sum) {
uint length = arr.length;
for (uint i = 0; i < arr.length; i++) {
sum += arr[i];
}
}
}

In the above example, the dynamic array arr has the storage location
memory. When the function gets called externally, the array values are
kept in calldata and copied to memory during ABI decoding (using the
opcode calldataload and mstore). And during the for loop, arr[i]
accesses the value in memory using a mload. However, for the above
example this is inefficient. Consider the following snippet instead:

contract C {
function add(uint[] calldata arr) external returns (uint sum) {
uint length = arr.length;
for (uint i = 0; i < arr.length; i++) {
sum += arr[i];
}
}
}

In the above snippet, instead of going via memory, the value is directly
read from calldata using calldataload. That is, there are no
intermediate memory operations that carries this value.

Gas savings: In the former example, the ABI decoding begins with
copying value from calldata to memory in a for loop. Each iteration
would cost at least 60 gas. In the latter example, this can be
completely avoided. This will also reduce the number of instructions and
therefore reduces the deploy time cost of the contract.

In short, use calldata instead of memory if the function argument
is only read.

Note that in older Solidity versions, changing some function arguments
from memory to calldata may cause "unimplemented feature error".
This can be avoided by using a newer (0.8.*) Solidity compiler.

Examples
Note: The following pattern is prevalent in the codebase:

function f(bytes memory data) external {
(...) = abi.decode(data, (..., types, ...));
}

Here, changing to bytes calldata will decrease the gas. The total
savings for this change across all such uses would be quite
significant.

Proof Of Concept

Examples:

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreCollection.sol#L144

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreCollection.sol#L203

Tools Used

None

Recommended Mitigation Steps

Change memory definition with calldata.

C4-009 : Non-strict inequalities are cheaper than strict ones

Impact

Strict inequalities add a check of non equality which costs around 3 gas.

Proof of Concept


All Facets Directory Contracts
Examples :
https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreCollection.sol#L305

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreCollection.sol#L161

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreCollection.sol#L146

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreCollection.sol#L53

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreCollection.sol#L161

https://github.com/code-423n4/2022-03-joyn/blob/main/royalty-vault/contracts/RoyaltyVault.sol#L35

Tools Used

Code Review

Recommended Mitigation Steps

Use >= or <= instead of > and < when possible.

C4-010 : Changing function visibility from public to external can save gas

Impact

There is a function declared as public that are never called internally within the contract. It is best practice to mark such functions as external instead, as this saves gas (especially in the case where the function takes arguments, as external functions can read arguments directly from calldata instead of having to allocate memory).

Proof of Concept

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreCollection.sol#L236

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreCollection.sol#L248

Tools Used

Code Review

Recommended Mitigation Steps

All of the public functions in the contract are not called internally, so access can be changed to external to reduce gas.

C4-011: Redundant Import

Impact

Constructor is redundant in the following code.

Proof of Concept

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreCollection.sol#L37

Tools Used

Code Review

Recommended Mitigation Steps

Consider deleting the redundant code.

@code423n4 code423n4 added bug Something isn't working G (Gas Optimization) labels Apr 1, 2022
code423n4 added a commit that referenced this issue Apr 1, 2022
@sofianeOuafir
Copy link
Collaborator

high quality report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working G (Gas Optimization)
Projects
None yet
Development

No branches or pull requests

2 participants