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

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

Gas Optimizations #64

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

Comments

@code423n4
Copy link
Contributor

1. Unnecessary explicit initialization of variables with default values

If a variable is not set/initialized, it has the default value (0 for uint, false for bool, etc.). Explicitly initializing a variable with its default value is an anti-pattern and wastes gas.

The OrderCombiner.sol contract has more than ten explicit initializations of default values. Other contract have more examples. Examples include:

To fix this, remove explicit initializations for default values.

2. Use unchecked for increment

Consider the following generic for loop:

for (uint i = 0; i < length; i++) {
    // do something that doesn't change the value of i
}

In this example, the for loop post condition, i.e., i++ involves checked arithmetic, which is not required. This is because the value of i is always strictly less than length <= 2**256 - 1. Therefore, the theoretical maximum value of i to enter the for-loop body is 2**256 - 2. This means that the i++ in the for loop can never overflow. Regardless, the overflow checks are performed by the compiler.

Unfortunately, the Solidity optimizer is not smart enough to detect this and remove the checks. One can manually do this by:

for (uint i = 0; i < length; i = unchecked_inc(i)) {
    // do something that doesn't change the value of i
}

function unchecked_inc(uint i) returns (uint) {
    unchecked {
        return i + 1;
    }
}

Above code and explanation from hrkrshnn.

The OrdrCombiner.sol contract has more than 5 loops that can be improved this way. Examples include:

To fix, use unchecked increment in loops.

3. iszero assembly should replace == 0

The iszero opcode is useful when comparing variables to zero. t11s suggested overusing this improvement on twitter.

The Assertions.sol and OrderCombiner.sol contracts have more than 5 zero comparisons that can be improved this way. Examples include:

To fix, replace == 0 with iszero.

4. Use vyper instead of solidity

Vyper contracts normally use less gas than their solidity counterparts. The possible savings was demonstrated for Seaport by doggo and a more general example was shown here. Seaport is written in solidity and yul, not vyper. Switching some or all of the contracts to vyper can result in gas savings.

To fix, replace solidity contracts with vyper code.

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

HardlyDifficult commented Jun 26, 2022

Unnecessary explicit initialization of variables with default values

In my testing these changes seem to make very little difference.

Use unchecked for increment

This will provide small savings.

iszero assembly should replace == 0

I like how you reference t11s own tweet here :) This could be a worthwhile change to consider including here.

Use vyper instead of solidity

Potentially. I saw 0age mention a working group exploring this more. Very curious to see if that concludes, would love a full featured comparison of Seaport in Solidity/Yul vs Vyper

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