main ddf6ef83f041 cached
22 files
17.3 KB
5.2k tokens
1 requests
Download .txt
Repository: kadenzipfel/gas-optimizations
Branch: main
Commit: ddf6ef83f041
Files: 22
Total size: 17.3 KB

Directory structure:
gitextract_cj3l_ucq/

├── README.md
├── gas-costly-patterns/
│   ├── comparison-with-unilateral-outcome-in-a-loop.md
│   ├── constant-outcome-of-a-loop.md
│   ├── dead-code.md
│   ├── expensive-operations-in-a-loop.md
│   ├── loop-fusion.md
│   ├── opaque-predicate.md
│   ├── repeated-computations-in-a-loop.md
│   ├── storage-variable-as-loop-length.md
│   └── unnecessary-libraries.md
├── gas-golfing/
│   ├── function-ordering.md
│   ├── optimal-comparison-operator.md
│   ├── optimal-increment-and-decrement-operators.md
│   ├── payable-functions.md
│   ├── short-revert-strings.md
│   ├── unchecked-arithmetic.md
│   └── using-mulmod-over-mul&div.md
└── gas-saving-patterns/
    ├── constants-and-immutables.md
    ├── explicit-function-visibility.md
    ├── proper-data-types.md
    ├── short-circuiting.md
    └── struct-bit-packing.md

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
# Gas Optimizations in Solidity

## Gas Costly Patterns

- [Comparison with Unilateral Outcome in a Loop](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/comparison-with-unilateral-outcome-in-a-loop.md)
- [Constant Outcome of a Loop](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/constant-outcome-of-a-loop.md)
- [Dead Code](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/dead-code.md)
- [Expensive Operations in a Loop](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/expensive-operations-in-a-loop.md)
- [Loop Fusion](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/loop-fusion.md)
- [Opaque Predicate](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/opaque-predicate.md)
- [Repeated Computations in a Loop](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/repeated-computations-in-a-loop.md)
- [Storage Variable as Loop Length](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/storage-variable-as-loop-length.md)
- [Unnecessary Libraries](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/unnecessary-libraries.md)

## Gas Saving Patterns

- [Proper Data Types](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-saving-patterns/proper-data-types.md)
- [Explicit Function Visibility](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-saving-patterns/explicit-function-visibility.md)
- [Short Circuiting](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-saving-patterns/short-circuiting.md)
- [Constants and Immutables](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-saving-patterns/constants-and-immutables.md)
- [Struct Bit Packing](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-saving-patterns/struct-bit-packing.md)

## Gas Golfing

- [Short Revert Strings](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/short-revert-strings.md)
- [Unchecked Arithmetic](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/unchecked-arithmetic.md)
- [Optimal Comparison Operator](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/optimal-comparison-operator.md)
- [Payable Functions](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/payable-functions.md)
- [Function Ordering](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/function-ordering.md)
- [Using Mulmod Over Mul & Div](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/using-mulmod-over-mul&div.md)
- [Optimal Increment and Decrement Operators](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/optimal-increment-and-decrement-operators.md)

## Sources/References

- https://medium.com/coinmonks/optimizing-your-solidity-contracts-gas-usage-9d65334db6c7
- https://ethereum.stackexchange.com/questions/28813/how-to-write-an-optimized-gas-cost-smart-contract
- https://arxiv.org/pdf/1703.03994.pdf
- https://ethereum.stackexchange.com/questions/3067/why-does-uint8-cost-more-gas-than-uint256
- https://www.youtube.com/watch?v=qwBkeJ84d2g&feature=youtu.be&t=68
- https://ethereum.stackexchange.com/questions/11556/use-string-type-or-bytes32
- https://gist.github.com/hrkrshnn/ee8fabd532058307229d65dcd5836ddc
- https://github.com/ZeroEkkusu/re-golf-course


================================================
FILE: gas-costly-patterns/comparison-with-unilateral-outcome-in-a-loop.md
================================================
## Comparison with Unilateral Outcome in a Loop

When a comparison is executed in each iteration of a loop but the result is the same each time, it should be removed from the loop.

For example, the following:

```
function unilateralOutcome(uint x) public returns(uint) {
  uint sum = 0;
  for(uint i = 0; i <= 100; i++) {
    if(x > 1) {
      sum += 1;
    }
  }
  return sum;
}
```

Should be re-written as:

```
function noUnilateralOutcome(uint x) public returns(uint) {
  uint sum = 0;
  bool increment = x > 1;
  for(uint i = 0; i <= 100; i++) {
    if(increment) {
      sum += 1;
    }
  }
  return sum;
}
```


================================================
FILE: gas-costly-patterns/constant-outcome-of-a-loop.md
================================================
## Constant Outcome of a Loop

If the outcome of a loop is a constant that can be inferred during compilation, it should not be used.

```
function constantOutcome() public pure returns(uint) {
  uint num = 0;
  for(uint i = 0; i < 100; i++) {
    num += 1;
  }
  return num;
}
```


================================================
FILE: gas-costly-patterns/dead-code.md
================================================
## Dead Code

Dead code is code that will never run because it’s evaluation is predicated on a condition that will always return false.

```
function deadCode(uint x) public pure {
  if(x < 1) {
    if(x > 2) {
      // this will never run
      return x;
    }
  }
}
```


================================================
FILE: gas-costly-patterns/expensive-operations-in-a-loop.md
================================================
## Expensive Operations in a Loop

We should aim to keep logic in loops as cheap as possible.

For example, due to the expensive SLOAD and SSTORE opcodes, managing a variable in storage is much more expensive than managing variables in memory. For this reason, storage variables should be avoided in loops.

```
uint num = 0;

function expensiveLoop(uint x) public {
  for(uint i = 0; i < x; i++) {
    num += 1;
  }
}
```

The fix for this pattern would be to create a memory variable to represent the state variable and once the loop is complete, reassign the value of the temporary variable to the global variable.

```
uint num = 0;

function lessExpensiveLoop(uint x) public {
  uint temp = num;
  for(uint i = 0; i < x; i++) {
    temp += 1;
  }
  num = temp;
}
```


================================================
FILE: gas-costly-patterns/loop-fusion.md
================================================
## Loop Fusion

Occasionally in smart contracts, you may find that there are two loops with the same parameters. In the case that the loop parameters are the same, they should be combined if possible.

```
 function loopFusion(uint x, uint y) public pure returns(uint) {
  for(uint i = 0; i < 100; i++) {
    x += 1;
  }
  for(uint i = 0; i < 100; i++) {
    y += 1;
  }
  return x + y;
}
```

Should be re-written as:

```
 function lessExpensiveLoopFusion(uint x, uint y) public pure returns(uint) {
  for(uint i = 0; i < 100; i++) {
    x += 1;
    y += 1;
  }
  return x + y;
}
```


================================================
FILE: gas-costly-patterns/opaque-predicate.md
================================================
## Opaque Predicate

The outcome of some conditions can be known without being executed and thus do not need to be evaluated.

```
function opaquePredicate(uint x) public pure {
  if(x > 1) {
    // redundant
    if(x > 0) {
      return x;
    }
  }
}
```


================================================
FILE: gas-costly-patterns/repeated-computations-in-a-loop.md
================================================
## Repeated Computations in a Loop

If an expression in a loop produces the same outcome in each iteration, it can be moved out of the loop. This is especially important when the variables(s) used in the expression are stored in storage.

```
uint a = 4;
uint b = 5;
function repeatedComputations(uint x) public returns(uint) {
  uint sum = 0;
  for(uint i = 0; i <= x; i++) {
    sum = a + b;
  }
  return sum;
}
```


================================================
FILE: gas-costly-patterns/storage-variable-as-loop-length.md
================================================
## Storage Variable as Loop Length

Avoid using storage variables to set the length of a for loop.

```
function expensiveLoopLength {
  for (uint i = 0; i < array.length; i++) {}
}
```

Instead assign it to a variable in memory to avoid unnecessary SLOADs.

```
function cheapLoopLength {
  uint length = array.length;
  for (uint i = 0; i < length; i++) {}
}
```


================================================
FILE: gas-costly-patterns/unnecessary-libraries.md
================================================
## Unnecessary Libraries

Libraries are often only imported for a small number of uses, meaning that they can contain a significant amount of code that is redundant to your contract. If you can safely and effectively implement the functionality imported from a library within your contract, it is optimal to do so.

```
import './SafeMath.sol' as SafeMath;

// redundant library
contract SafeAddition {
  function safeAdd(uint a, uint b) public pure returns(uint) {
    return SafeMath.add(a, b);
  }
}
```

```
// w/o library
contract SafeAddition {
  function safeAdd(uint a, uint b) public pure returns(uint) {
    uint c = a + b;
    require(c >= a, "Addition overflow");
    return c;
  }
}
```


================================================
FILE: gas-golfing/function-ordering.md
================================================
## Function Ordering
When a function is called, the EVM compares the method ID of the transaction to the method ID's present in the contract, with each comparison costing an additional 22 gas. These comparisons are performed in order from least to greatest byte value of method ID's (alphanumerically based on the method ID). This is done using binary search.

For this reason:
### 1. Have method name with IDs that have more 0s.
As with calldata, having a method name whose function selector has more 0s helps.
```
// method ID: 0x6a761202
execTransaction()

// method ID: 0x00000081
execTransaction32785586()
```
This saves 192 bytes of data.

### 2. Reorder methods based on call frequency
there is some value in renaming functions to be ordered based on the frequency you expect them to be used, saving average overall gas cost of interacting with your contract.

```
// method ID: 0x1249c58b
mint()

// method ID: 0x0000b696
mint_Aci()
```

Useful tool: https://emn178.github.io/solidity-optimize-name/


================================================
FILE: gas-golfing/optimal-comparison-operator.md
================================================
## Optimal Comparison Operator

When comparing uints, you can save gas costs by strategically picking the optimal operator.

For example, it is cheaper to use strict < or > operators over <= or >= operators. This is due to the additional EQ opcode which must be performed.

In the case of a conditional statement, it is further optimal to use != when possible.

```
// pragma solidity ^0.8.0;

// 149 gas
function a() external pure returns(bool) {
  return 1 > 0;
}

// 193 gas
function b() external pure returns(bool) {
  return 1 >= 0;
}

// 237 gas
function c() external pure returns(bool) {
  return 1 != 0;
}

// 164 gas
function d() external pure {
  require(1 > 0);
}

// 208 gas
function e() external pure {
  require(1 >= 0);
}

// 120 gas
function f() external pure {
  require(1 != 0);
}
```


================================================
FILE: gas-golfing/optimal-increment-and-decrement-operators.md
================================================
## Optimal Increment and Decrement Operators

Increment and decrement operators are used to either increment or decrement their operand by one. These incrementers/decrementers can either be presented as e.g. `i++` or `++i`, with the only difference being the order of operations being executed. `i++` will return `i`, then increment the value of `i`, whereas `++i` will increment before returning the value.

As a result of the variance in order of operations, `++i` will save two opcodes from being performed. Consider the following example:

```
pragma solidity ^0.8.0;

contract IPlusPlus {
    // 1996 gas
    function loop() external pure {
        for (uint256 i; i < 10; i++) {
            // do something
        }
    }
}

contract PlusPlusI {
    // 1946 gas
    function loop() external pure {
        for (uint256 i; i < 10; ++i) {
            // do something
        }
    }
}
```

Using `++i` above shaves off 5 gas per loop. This is because `i++` must handle the value of `i` both before and after the increment, in this case by executing a `DUPN` opcode (3 gas) and later cleaning up the stack by performing a `POP` (2 gas).


================================================
FILE: gas-golfing/payable-functions.md
================================================
## Payable Functions

Functions that are not explicitly marked as payable require an initial check that msg.value == 0, which costs 21 gas. In the case that this check does not provide any benefit, it may be optimal to mark your function as payable.

**Note**: Do not use this pattern unless you understand the security trade-off being made.


================================================
FILE: gas-golfing/short-revert-strings.md
================================================
## Short Revert Strings

Keeping revert strings under 32-bytes prevents the string from being stored in more than one memory slot.

```
function expensiveRevertStrings() {
  require(a < b; "long revert string over 32 bytes");
}
```

Alternatively you can write comments to map short strings to longer ones in your contract, e.g.:

```
// a: long revert string over 32 bytes
function cheapRevertStrings() {
  require(a < b; "a");
}
```

Ideally, if you are using solidity >= 0.8.4, it is even better to use custom errors to further save on gas.

```
// pragma solidity ^0.8.0;

error CustomError();
contract CustomErrors {
  if (a < b) {
    revert CustomError();
  }
}
```


================================================
FILE: gas-golfing/unchecked-arithmetic.md
================================================
## Unchecked Arithmetic

If using solidity >= 0.8.0, safe arithmetic is built-in. In situations that overflow/underflow checks are redundant, code should be wrapped in an unchecked block. For example, the for loop increment can be unchecked as follows:

```
// pragma solidity ^0.8.0;

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;
    }
}
```


================================================
FILE: gas-golfing/using-mulmod-over-mul&div.md
================================================
## Using Mulmod Over Mul & Div

If you have to check whether a value obtained by dividing it by a number is exact(i.e. significant digits have not truncated during division), use `mulmod` instead of mul & div as it costs 8 gas. In contrast, `mul` and `div` cost 5 gas each.

- Gas inefficient method
```
    contract UsingMul&Div {
        error InExactDivision();

        function exactDivide(
            uint256 numerator,
            uint256 denominator,
            uint256 value
        ) public pure returns (uint256 newValue) {
            newValue = (value * numerator)/denominator;
            if(value != (newValue * denominator)/ numerator) {
                revert InExactDivision();
            }
        }
    }

```

- Gas efficient method

```
    contract UsingMulMod {
        error InExactDivision();

        function exactDivide(
            uint256 numerator,
            uint256 denominator,
            uint256 value
        ) public pure returns (uint256 newValue) {
            newValue = (value * numerator)/denominator;
            if(mulmod(value, numerator, denominator) != 0) {
                revert InExactDivision();
            }
        }
    }

```

- Gas efficient method(With Assembly)

```
    contract UsingMulModWithAssembly {
        error InExactDivision();

        function exactDivide(
            uint256 numerator,
            uint256 denominator,
            uint256 value
        ) public pure returns (uint256 newValue) {
            bool inexact;
            assembly {
                newValue := div(mul(value, numerator, denominator));
                inexact := iszero(iszero(mulmod(value, numerator, denominator)));
            }
            if(inexact) {
                revert InExactDivision();
            }
        }
    }

```

================================================
FILE: gas-saving-patterns/constants-and-immutables.md
================================================
## Constants and Immutables

If a storage variable must be assigned at deployment and doesn't need to be reassigned, it should be marked as immutable.
Better yet, if it doesn't need to be assigned at deployment then it can be set as a constant.

```
contract ExpensiveStorageVar {
    uint256 MAX_SUPPLY = 10000;

    // 520 gas
    function getMaxSupply() external view returns (uint256) {
        return MAX_SUPPLY;
    }
}
```

```
// pragma solidity ^0.8.0;

contract CheapImmutable {
    uint256 immutable maxSupply;

    constructor(uint256 _maxSupply) {
        maxSupply = _maxSupply;
    }

    // 379 gas
    function getMaxSupply() external view returns (uint256) {
        return maxSupply;
    }
}
```

```
// pragma solidity ^0.8.0;

contract ExtraCheapConstant {
    uint256 constant MAX_SUPPLY = 10000;

    // 320 gas
    function getMaxSupply() external pure returns (uint256) {
        return MAX_SUPPLY;
    }
}
```


================================================
FILE: gas-saving-patterns/explicit-function-visibility.md
================================================
## Explicit Function Visibility

Explicit function visibility can often provide benefits in terms of smart contract security as well as gas optimization. For example, explicitly labeling external functions forces the function parameter storage location to be set as calldata, which saves gas each time the function is executed.


================================================
FILE: gas-saving-patterns/proper-data-types.md
================================================
## Proper Data Types

In Solidity, some data types are more expensive than others. It’s valuable to know the most efficient type that can be used. Here are a few rules about data types.

- Type uint or bytes32 should be used in place of type string whenever possible.
- Type uint256 takes less gas to store than other uint types ([see why](https://ethereum.stackexchange.com/questions/3067/why-does-uint8-cost-more-gas-than-uint256)).
- Type bytes should be used over byte[].
- If the length of bytes can be limited, use the lowest amount possible from bytes1 to bytes32.


================================================
FILE: gas-saving-patterns/short-circuiting.md
================================================
## Short Circuiting

Short-circuiting is a strategy we can make use of when an operation makes use of either || or &&. This pattern works by ordering the lower-cost operation first so that the higher-cost operation may be skipped (short-circuited) if the first operation evaluates to true.

```
// f(x) is low cost
// g(y) is expensive

// Ordering should go as follows
f(x) || g(y)
f(x) && g(y)
```


================================================
FILE: gas-saving-patterns/struct-bit-packing.md
================================================
## Struct Bit Packing

Solidity's [storage layout](https://docs.soliditylang.org/en/v0.8.15/internals/layout_in_storage.html?highlight=storage%20layout) consists of 2\*\*256 32 byte slots, with reads and writes requiring a fixed cost per slot. As such, to reduce gas costs, we should aim to use as few slots as necessary.

When variables are stored, they are done so in a compact way such that multiple values sometimes use the same slot. Structs may contain multiple data types, of which will also be stored as compact as the data types allow. For example, the following struct will consume 3 slots:

```
struct ThreeSlots {
    uint256 firstSlot; // takes an entire slot because uint256 is 256 bits == 32 bytes
    uint256 secondSlot; // takes an entire slot because uint256 is 256 bits == 32 bytes
    address thirdSlot; // although addresses are 20 bytes, it will take the third slot since the first two are full
}
```

If however, we know for a fact our uints will have a low enough upper bound, we can reduce the size to pack variables into fewer slots. For example:

```
struct OneSlot {
    uint48 firstValue; // if the value will never exceed 2**48 we can do this to use just 48 bits == 6 bytes
    uint48 secondValue; // if the value will never exceed 2**48 we can do this to use just 48 bits == 6 bytes
    address thirdValue; // since we've only consumed 12 bytes we can fit our 20 byte address for a total of 32 bytes
}
```
Download .txt
gitextract_cj3l_ucq/

├── README.md
├── gas-costly-patterns/
│   ├── comparison-with-unilateral-outcome-in-a-loop.md
│   ├── constant-outcome-of-a-loop.md
│   ├── dead-code.md
│   ├── expensive-operations-in-a-loop.md
│   ├── loop-fusion.md
│   ├── opaque-predicate.md
│   ├── repeated-computations-in-a-loop.md
│   ├── storage-variable-as-loop-length.md
│   └── unnecessary-libraries.md
├── gas-golfing/
│   ├── function-ordering.md
│   ├── optimal-comparison-operator.md
│   ├── optimal-increment-and-decrement-operators.md
│   ├── payable-functions.md
│   ├── short-revert-strings.md
│   ├── unchecked-arithmetic.md
│   └── using-mulmod-over-mul&div.md
└── gas-saving-patterns/
    ├── constants-and-immutables.md
    ├── explicit-function-visibility.md
    ├── proper-data-types.md
    ├── short-circuiting.md
    └── struct-bit-packing.md
Condensed preview — 22 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (20K chars).
[
  {
    "path": "README.md",
    "chars": 3504,
    "preview": "# Gas Optimizations in Solidity\n\n## Gas Costly Patterns\n\n- [Comparison with Unilateral Outcome in a Loop](https://github"
  },
  {
    "path": "gas-costly-patterns/comparison-with-unilateral-outcome-in-a-loop.md",
    "chars": 620,
    "preview": "## Comparison with Unilateral Outcome in a Loop\n\nWhen a comparison is executed in each iteration of a loop but the resul"
  },
  {
    "path": "gas-costly-patterns/constant-outcome-of-a-loop.md",
    "chars": 282,
    "preview": "## Constant Outcome of a Loop\n\nIf the outcome of a loop is a constant that can be inferred during compilation, it should"
  },
  {
    "path": "gas-costly-patterns/dead-code.md",
    "chars": 272,
    "preview": "## Dead Code\n\nDead code is code that will never run because it’s evaluation is predicated on a condition that will alway"
  },
  {
    "path": "gas-costly-patterns/expensive-operations-in-a-loop.md",
    "chars": 772,
    "preview": "## Expensive Operations in a Loop\n\nWe should aim to keep logic in loops as cheap as possible.\n\nFor example, due to the e"
  },
  {
    "path": "gas-costly-patterns/loop-fusion.md",
    "chars": 586,
    "preview": "## Loop Fusion\n\nOccasionally in smart contracts, you may find that there are two loops with the same parameters. In the "
  },
  {
    "path": "gas-costly-patterns/opaque-predicate.md",
    "chars": 257,
    "preview": "## Opaque Predicate\n\nThe outcome of some conditions can be known without being executed and thus do not need to be evalu"
  },
  {
    "path": "gas-costly-patterns/repeated-computations-in-a-loop.md",
    "chars": 418,
    "preview": "## Repeated Computations in a Loop\n\nIf an expression in a loop produces the same outcome in each iteration, it can be mo"
  },
  {
    "path": "gas-costly-patterns/storage-variable-as-loop-length.md",
    "chars": 365,
    "preview": "## Storage Variable as Loop Length\n\nAvoid using storage variables to set the length of a for loop.\n\n```\nfunction expensi"
  },
  {
    "path": "gas-costly-patterns/unnecessary-libraries.md",
    "chars": 700,
    "preview": "## Unnecessary Libraries\n\nLibraries are often only imported for a small number of uses, meaning that they can contain a "
  },
  {
    "path": "gas-golfing/function-ordering.md",
    "chars": 1008,
    "preview": "## Function Ordering\nWhen a function is called, the EVM compares the method ID of the transaction to the method ID's pre"
  },
  {
    "path": "gas-golfing/optimal-comparison-operator.md",
    "chars": 803,
    "preview": "## Optimal Comparison Operator\n\nWhen comparing uints, you can save gas costs by strategically picking the optimal operat"
  },
  {
    "path": "gas-golfing/optimal-increment-and-decrement-operators.md",
    "chars": 1141,
    "preview": "## Optimal Increment and Decrement Operators\n\nIncrement and decrement operators are used to either increment or decremen"
  },
  {
    "path": "gas-golfing/payable-functions.md",
    "chars": 342,
    "preview": "## Payable Functions\n\nFunctions that are not explicitly marked as payable require an initial check that msg.value == 0, "
  },
  {
    "path": "gas-golfing/short-revert-strings.md",
    "chars": 673,
    "preview": "## Short Revert Strings\n\nKeeping revert strings under 32-bytes prevents the string from being stored in more than one me"
  },
  {
    "path": "gas-golfing/unchecked-arithmetic.md",
    "chars": 495,
    "preview": "## Unchecked Arithmetic\n\nIf using solidity >= 0.8.0, safe arithmetic is built-in. In situations that overflow/underflow "
  },
  {
    "path": "gas-golfing/using-mulmod-over-mul&div.md",
    "chars": 1792,
    "preview": "## Using Mulmod Over Mul & Div\n\nIf you have to check whether a value obtained by dividing it by a number is exact(i.e. s"
  },
  {
    "path": "gas-saving-patterns/constants-and-immutables.md",
    "chars": 936,
    "preview": "## Constants and Immutables\n\nIf a storage variable must be assigned at deployment and doesn't need to be reassigned, it "
  },
  {
    "path": "gas-saving-patterns/explicit-function-visibility.md",
    "chars": 328,
    "preview": "## Explicit Function Visibility\n\nExplicit function visibility can often provide benefits in terms of smart contract secu"
  },
  {
    "path": "gas-saving-patterns/proper-data-types.md",
    "chars": 572,
    "preview": "## Proper Data Types\n\nIn Solidity, some data types are more expensive than others. It’s valuable to know the most effici"
  },
  {
    "path": "gas-saving-patterns/short-circuiting.md",
    "chars": 400,
    "preview": "## Short Circuiting\n\nShort-circuiting is a strategy we can make use of when an operation makes use of either || or &&. T"
  },
  {
    "path": "gas-saving-patterns/struct-bit-packing.md",
    "chars": 1437,
    "preview": "## Struct Bit Packing\n\nSolidity's [storage layout](https://docs.soliditylang.org/en/v0.8.15/internals/layout_in_storage."
  }
]

About this extraction

This page contains the full source code of the kadenzipfel/gas-optimizations GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 22 files (17.3 KB), approximately 5.2k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!