[
  {
    "path": "README.md",
    "content": "# Gas Optimizations in Solidity\n\n## Gas Costly Patterns\n\n- [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)\n- [Constant Outcome of a Loop](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/constant-outcome-of-a-loop.md)\n- [Dead Code](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/dead-code.md)\n- [Expensive Operations in a Loop](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/expensive-operations-in-a-loop.md)\n- [Loop Fusion](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/loop-fusion.md)\n- [Opaque Predicate](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/opaque-predicate.md)\n- [Repeated Computations in a Loop](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/repeated-computations-in-a-loop.md)\n- [Storage Variable as Loop Length](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/storage-variable-as-loop-length.md)\n- [Unnecessary Libraries](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-costly-patterns/unnecessary-libraries.md)\n\n## Gas Saving Patterns\n\n- [Proper Data Types](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-saving-patterns/proper-data-types.md)\n- [Explicit Function Visibility](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-saving-patterns/explicit-function-visibility.md)\n- [Short Circuiting](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-saving-patterns/short-circuiting.md)\n- [Constants and Immutables](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-saving-patterns/constants-and-immutables.md)\n- [Struct Bit Packing](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-saving-patterns/struct-bit-packing.md)\n\n## Gas Golfing\n\n- [Short Revert Strings](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/short-revert-strings.md)\n- [Unchecked Arithmetic](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/unchecked-arithmetic.md)\n- [Optimal Comparison Operator](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/optimal-comparison-operator.md)\n- [Payable Functions](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/payable-functions.md)\n- [Function Ordering](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/function-ordering.md)\n- [Using Mulmod Over Mul & Div](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/using-mulmod-over-mul&div.md)\n- [Optimal Increment and Decrement Operators](https://github.com/KadenZipfel/gas-optimizations/blob/main/gas-golfing/optimal-increment-and-decrement-operators.md)\n\n## Sources/References\n\n- https://medium.com/coinmonks/optimizing-your-solidity-contracts-gas-usage-9d65334db6c7\n- https://ethereum.stackexchange.com/questions/28813/how-to-write-an-optimized-gas-cost-smart-contract\n- https://arxiv.org/pdf/1703.03994.pdf\n- https://ethereum.stackexchange.com/questions/3067/why-does-uint8-cost-more-gas-than-uint256\n- https://www.youtube.com/watch?v=qwBkeJ84d2g&feature=youtu.be&t=68\n- https://ethereum.stackexchange.com/questions/11556/use-string-type-or-bytes32\n- https://gist.github.com/hrkrshnn/ee8fabd532058307229d65dcd5836ddc\n- https://github.com/ZeroEkkusu/re-golf-course\n"
  },
  {
    "path": "gas-costly-patterns/comparison-with-unilateral-outcome-in-a-loop.md",
    "content": "## Comparison with Unilateral Outcome in a Loop\n\nWhen 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.\n\nFor example, the following:\n\n```\nfunction unilateralOutcome(uint x) public returns(uint) {\n  uint sum = 0;\n  for(uint i = 0; i <= 100; i++) {\n    if(x > 1) {\n      sum += 1;\n    }\n  }\n  return sum;\n}\n```\n\nShould be re-written as:\n\n```\nfunction noUnilateralOutcome(uint x) public returns(uint) {\n  uint sum = 0;\n  bool increment = x > 1;\n  for(uint i = 0; i <= 100; i++) {\n    if(increment) {\n      sum += 1;\n    }\n  }\n  return sum;\n}\n```\n"
  },
  {
    "path": "gas-costly-patterns/constant-outcome-of-a-loop.md",
    "content": "## Constant Outcome of a Loop\n\nIf the outcome of a loop is a constant that can be inferred during compilation, it should not be used.\n\n```\nfunction constantOutcome() public pure returns(uint) {\n  uint num = 0;\n  for(uint i = 0; i < 100; i++) {\n    num += 1;\n  }\n  return num;\n}\n```\n"
  },
  {
    "path": "gas-costly-patterns/dead-code.md",
    "content": "## Dead Code\n\nDead code is code that will never run because it’s evaluation is predicated on a condition that will always return false.\n\n```\nfunction deadCode(uint x) public pure {\n  if(x < 1) {\n    if(x > 2) {\n      // this will never run\n      return x;\n    }\n  }\n}\n```\n"
  },
  {
    "path": "gas-costly-patterns/expensive-operations-in-a-loop.md",
    "content": "## Expensive Operations in a Loop\n\nWe should aim to keep logic in loops as cheap as possible.\n\nFor 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.\n\n```\nuint num = 0;\n\nfunction expensiveLoop(uint x) public {\n  for(uint i = 0; i < x; i++) {\n    num += 1;\n  }\n}\n```\n\nThe 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.\n\n```\nuint num = 0;\n\nfunction lessExpensiveLoop(uint x) public {\n  uint temp = num;\n  for(uint i = 0; i < x; i++) {\n    temp += 1;\n  }\n  num = temp;\n}\n```\n"
  },
  {
    "path": "gas-costly-patterns/loop-fusion.md",
    "content": "## Loop Fusion\n\nOccasionally 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.\n\n```\n function loopFusion(uint x, uint y) public pure returns(uint) {\n  for(uint i = 0; i < 100; i++) {\n    x += 1;\n  }\n  for(uint i = 0; i < 100; i++) {\n    y += 1;\n  }\n  return x + y;\n}\n```\n\nShould be re-written as:\n\n```\n function lessExpensiveLoopFusion(uint x, uint y) public pure returns(uint) {\n  for(uint i = 0; i < 100; i++) {\n    x += 1;\n    y += 1;\n  }\n  return x + y;\n}\n```\n"
  },
  {
    "path": "gas-costly-patterns/opaque-predicate.md",
    "content": "## Opaque Predicate\n\nThe outcome of some conditions can be known without being executed and thus do not need to be evaluated.\n\n```\nfunction opaquePredicate(uint x) public pure {\n  if(x > 1) {\n    // redundant\n    if(x > 0) {\n      return x;\n    }\n  }\n}\n```\n"
  },
  {
    "path": "gas-costly-patterns/repeated-computations-in-a-loop.md",
    "content": "## Repeated Computations in a Loop\n\nIf 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.\n\n```\nuint a = 4;\nuint b = 5;\nfunction repeatedComputations(uint x) public returns(uint) {\n  uint sum = 0;\n  for(uint i = 0; i <= x; i++) {\n    sum = a + b;\n  }\n  return sum;\n}\n```\n"
  },
  {
    "path": "gas-costly-patterns/storage-variable-as-loop-length.md",
    "content": "## Storage Variable as Loop Length\n\nAvoid using storage variables to set the length of a for loop.\n\n```\nfunction expensiveLoopLength {\n  for (uint i = 0; i < array.length; i++) {}\n}\n```\n\nInstead assign it to a variable in memory to avoid unnecessary SLOADs.\n\n```\nfunction cheapLoopLength {\n  uint length = array.length;\n  for (uint i = 0; i < length; i++) {}\n}\n```\n"
  },
  {
    "path": "gas-costly-patterns/unnecessary-libraries.md",
    "content": "## Unnecessary Libraries\n\nLibraries 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.\n\n```\nimport './SafeMath.sol' as SafeMath;\n\n// redundant library\ncontract SafeAddition {\n  function safeAdd(uint a, uint b) public pure returns(uint) {\n    return SafeMath.add(a, b);\n  }\n}\n```\n\n```\n// w/o library\ncontract SafeAddition {\n  function safeAdd(uint a, uint b) public pure returns(uint) {\n    uint c = a + b;\n    require(c >= a, \"Addition overflow\");\n    return c;\n  }\n}\n```\n"
  },
  {
    "path": "gas-golfing/function-ordering.md",
    "content": "## Function Ordering\nWhen 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.\n\nFor this reason:\n### 1. Have method name with IDs that have more 0s.\nAs with calldata, having a method name whose function selector has more 0s helps.\n```\n// method ID: 0x6a761202\nexecTransaction()\n\n// method ID: 0x00000081\nexecTransaction32785586()\n```\nThis saves 192 bytes of data.\n\n### 2. Reorder methods based on call frequency\nthere 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.\n\n```\n// method ID: 0x1249c58b\nmint()\n\n// method ID: 0x0000b696\nmint_Aci()\n```\n\nUseful tool: https://emn178.github.io/solidity-optimize-name/\n"
  },
  {
    "path": "gas-golfing/optimal-comparison-operator.md",
    "content": "## Optimal Comparison Operator\n\nWhen comparing uints, you can save gas costs by strategically picking the optimal operator.\n\nFor example, it is cheaper to use strict < or > operators over <= or >= operators. This is due to the additional EQ opcode which must be performed.\n\nIn the case of a conditional statement, it is further optimal to use != when possible.\n\n```\n// pragma solidity ^0.8.0;\n\n// 149 gas\nfunction a() external pure returns(bool) {\n  return 1 > 0;\n}\n\n// 193 gas\nfunction b() external pure returns(bool) {\n  return 1 >= 0;\n}\n\n// 237 gas\nfunction c() external pure returns(bool) {\n  return 1 != 0;\n}\n\n// 164 gas\nfunction d() external pure {\n  require(1 > 0);\n}\n\n// 208 gas\nfunction e() external pure {\n  require(1 >= 0);\n}\n\n// 120 gas\nfunction f() external pure {\n  require(1 != 0);\n}\n```\n"
  },
  {
    "path": "gas-golfing/optimal-increment-and-decrement-operators.md",
    "content": "## Optimal Increment and Decrement Operators\n\nIncrement 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.\n\nAs a result of the variance in order of operations, `++i` will save two opcodes from being performed. Consider the following example:\n\n```\npragma solidity ^0.8.0;\n\ncontract IPlusPlus {\n    // 1996 gas\n    function loop() external pure {\n        for (uint256 i; i < 10; i++) {\n            // do something\n        }\n    }\n}\n\ncontract PlusPlusI {\n    // 1946 gas\n    function loop() external pure {\n        for (uint256 i; i < 10; ++i) {\n            // do something\n        }\n    }\n}\n```\n\nUsing `++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).\n"
  },
  {
    "path": "gas-golfing/payable-functions.md",
    "content": "## Payable Functions\n\nFunctions 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.\n\n**Note**: Do not use this pattern unless you understand the security trade-off being made.\n"
  },
  {
    "path": "gas-golfing/short-revert-strings.md",
    "content": "## Short Revert Strings\n\nKeeping revert strings under 32-bytes prevents the string from being stored in more than one memory slot.\n\n```\nfunction expensiveRevertStrings() {\n  require(a < b; \"long revert string over 32 bytes\");\n}\n```\n\nAlternatively you can write comments to map short strings to longer ones in your contract, e.g.:\n\n```\n// a: long revert string over 32 bytes\nfunction cheapRevertStrings() {\n  require(a < b; \"a\");\n}\n```\n\nIdeally, if you are using solidity >= 0.8.4, it is even better to use custom errors to further save on gas.\n\n```\n// pragma solidity ^0.8.0;\n\nerror CustomError();\ncontract CustomErrors {\n  if (a < b) {\n    revert CustomError();\n  }\n}\n```\n"
  },
  {
    "path": "gas-golfing/unchecked-arithmetic.md",
    "content": "## Unchecked Arithmetic\n\nIf 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:\n\n```\n// pragma solidity ^0.8.0;\n\nfor (uint i = 0; i < length; i = unchecked_inc(i)) {\n    // do something that doesn't change the value of i\n}\n\nfunction unchecked_inc(uint i) returns (uint) {\n    unchecked {\n        return i + 1;\n    }\n}\n```\n"
  },
  {
    "path": "gas-golfing/using-mulmod-over-mul&div.md",
    "content": "## 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. 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.\n\n- Gas inefficient method\n```\n    contract UsingMul&Div {\n        error InExactDivision();\n\n        function exactDivide(\n            uint256 numerator,\n            uint256 denominator,\n            uint256 value\n        ) public pure returns (uint256 newValue) {\n            newValue = (value * numerator)/denominator;\n            if(value != (newValue * denominator)/ numerator) {\n                revert InExactDivision();\n            }\n        }\n    }\n\n```\n\n- Gas efficient method\n\n```\n    contract UsingMulMod {\n        error InExactDivision();\n\n        function exactDivide(\n            uint256 numerator,\n            uint256 denominator,\n            uint256 value\n        ) public pure returns (uint256 newValue) {\n            newValue = (value * numerator)/denominator;\n            if(mulmod(value, numerator, denominator) != 0) {\n                revert InExactDivision();\n            }\n        }\n    }\n\n```\n\n- Gas efficient method(With Assembly)\n\n```\n    contract UsingMulModWithAssembly {\n        error InExactDivision();\n\n        function exactDivide(\n            uint256 numerator,\n            uint256 denominator,\n            uint256 value\n        ) public pure returns (uint256 newValue) {\n            bool inexact;\n            assembly {\n                newValue := div(mul(value, numerator, denominator));\n                inexact := iszero(iszero(mulmod(value, numerator, denominator)));\n            }\n            if(inexact) {\n                revert InExactDivision();\n            }\n        }\n    }\n\n```"
  },
  {
    "path": "gas-saving-patterns/constants-and-immutables.md",
    "content": "## Constants and Immutables\n\nIf a storage variable must be assigned at deployment and doesn't need to be reassigned, it should be marked as immutable.\nBetter yet, if it doesn't need to be assigned at deployment then it can be set as a constant.\n\n```\ncontract ExpensiveStorageVar {\n    uint256 MAX_SUPPLY = 10000;\n\n    // 520 gas\n    function getMaxSupply() external view returns (uint256) {\n        return MAX_SUPPLY;\n    }\n}\n```\n\n```\n// pragma solidity ^0.8.0;\n\ncontract CheapImmutable {\n    uint256 immutable maxSupply;\n\n    constructor(uint256 _maxSupply) {\n        maxSupply = _maxSupply;\n    }\n\n    // 379 gas\n    function getMaxSupply() external view returns (uint256) {\n        return maxSupply;\n    }\n}\n```\n\n```\n// pragma solidity ^0.8.0;\n\ncontract ExtraCheapConstant {\n    uint256 constant MAX_SUPPLY = 10000;\n\n    // 320 gas\n    function getMaxSupply() external pure returns (uint256) {\n        return MAX_SUPPLY;\n    }\n}\n```\n"
  },
  {
    "path": "gas-saving-patterns/explicit-function-visibility.md",
    "content": "## Explicit Function Visibility\n\nExplicit 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.\n"
  },
  {
    "path": "gas-saving-patterns/proper-data-types.md",
    "content": "## Proper Data Types\n\nIn 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.\n\n- Type uint or bytes32 should be used in place of type string whenever possible.\n- 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)).\n- Type bytes should be used over byte[].\n- If the length of bytes can be limited, use the lowest amount possible from bytes1 to bytes32.\n"
  },
  {
    "path": "gas-saving-patterns/short-circuiting.md",
    "content": "## Short Circuiting\n\nShort-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.\n\n```\n// f(x) is low cost\n// g(y) is expensive\n\n// Ordering should go as follows\nf(x) || g(y)\nf(x) && g(y)\n```\n"
  },
  {
    "path": "gas-saving-patterns/struct-bit-packing.md",
    "content": "## Struct Bit Packing\n\nSolidity'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.\n\nWhen 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:\n\n```\nstruct ThreeSlots {\n    uint256 firstSlot; // takes an entire slot because uint256 is 256 bits == 32 bytes\n    uint256 secondSlot; // takes an entire slot because uint256 is 256 bits == 32 bytes\n    address thirdSlot; // although addresses are 20 bytes, it will take the third slot since the first two are full\n}\n```\n\nIf 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:\n\n```\nstruct OneSlot {\n    uint48 firstValue; // if the value will never exceed 2**48 we can do this to use just 48 bits == 6 bytes\n    uint48 secondValue; // if the value will never exceed 2**48 we can do this to use just 48 bits == 6 bytes\n    address thirdValue; // since we've only consumed 12 bytes we can fit our 20 byte address for a total of 32 bytes\n}\n```\n"
  }
]