Zokyo Gas Savings
  • โ›ฝZokyo Gas Savings
  • ๐Ÿ“šTutorials
    • โœ”๏ธGas Saving Technique 1: Unchecked Arithmetic
    • โ›“๏ธGas Saving Technique 2: Immutable Variable
    • โœจGas Saving Technique 3: Double star ** inefficiency
    • ๐Ÿ’ฐGas Saving Technique 4: Cache Array Length
    • โฌ…๏ธGas Saving Technique 5: ++i costs less gas compared to i++
    • โš–๏ธGas Saving Technique 6: NOT operator ! cheaper than boolean FALSE
    • ๐ŸชกGas Saving Technique 7: Using Short Reason Strings
    • ๐ŸชตGas Saving Technique 8: Use Custom Errors instead of Revert Strings to save Gas
    • โœ’๏ธGas Saving Technique 9: Use Custom Errors instead of Revert Strings to save Gas
    • ๐Ÿ‘พGas Saving Technique 10: Calldata cheaper than memory
    • โ›”Gas Saving Technique 11: > 0 is less efficient than != 0 for unsigned integers
    • โž—Gas Saving Technique 12: SafeMath no longer needed
    • ๐Ÿ˜ฎGas Saving Technique 13: variables default to 0
    • ๐ŸงฑGas Saving Technique 14: struct layout/ variable packing
    • ๐Ÿ“žGas Saving Technique 15: Cache External Call
    • โœ๏ธGas Saving Technique 16: Early Validation before external call
    • ๐Ÿ˜ŽGas Saving Technique 17: Donโ€™t cache value that is used once
    • ๐Ÿ˜งGas Saving Technique 18: Redundant code
    • โœ…Gas Saving Technique 19: Early Validation before external call
    • โ›๏ธGas Saving Technique 20: Storage vs Memory read optimizations
    • โœ’๏ธGas Saving Technique 21: Unneeded If statements
    • ๐ŸŒ—Gas Saving Technique 22: >= is cheaper than >
    • ๐ŸŽ’Gas Saving Technique 23: Public to private constants
    • โน๏ธGas Saving Technique 24: Make unchanged variables constant/immutable
    • โฑ๏ธGas Saving Techniques 25: Redundant Access Control Checks
    • โžก๏ธGas Saving Technique 26: Shift Right instead of Dividing by 2
    • ๐ŸชƒGas Saving Tutorial 27: Efficient Boolean Comparison
    • ๐ŸคGas Saving Technique 28: && operator uses more gas
    • ๐Ÿ‘“Gas Saving Technique 29: x = x + y is cheaper than x += y
    • ๐Ÿ‘‚Gas Saving Technique 30: Using 1 and 2 rather than 0 and 1 saves gas
    • โšฝGas Saving Technique 31: Optimize Storage by Avoiding Booleans
    • ๐Ÿ”™Gas Saving Technique 32: Optimal Use of Named Return Variables in Solidity
    • ๐Ÿ›ข๏ธGas Saving Technique 33: Making Functions Payable for Optimized Gas Costs
    • โœ๏ธGas Saving Technique 34: Optimizing Storage References in Smart Contracts
    • โ›ฐ๏ธGas Saving Technique 35: Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead
    • ๐ŸŒช๏ธGas Saving Technique 36: Inlining Single Use Internal Functions for Savings
    • โ˜„๏ธGas Saving Technique 37: Switching from Public to External Functions for Savings
    • ๐ŸŽ†Gas Saving Technique 38: Upgrading Solidity Compiler to Improve Gas Efficiency and Security
    • ๐Ÿ•ถ๏ธGas Saving Technique 39: Avoiding Duplicated Code for Gas Savings
    • ๐Ÿ˜„Gas Saving Technique 40: Removal of Unused Internal Functions for Gas Savings
    • ๐Ÿ–‹๏ธGas Saving Tutorial 41: In-lining Single Use Modifiers For Gas Saving
    • โ›๏ธGas Saving Technique 42: `require` vs`assert`
Powered by GitBook
On this page
  1. Tutorials

Gas Saving Technique 5: ++i costs less gas compared to i++

PreviousGas Saving Technique 4: Cache Array LengthNextGas Saving Technique 6: NOT operator ! cheaper than boolean FALSE

Last updated 1 year ago

Introduction

Gas optimization is a crucial aspect of Ethereum smart contract development due to the inherent costs associated with transaction processing. A seemingly minor yet effective gas-saving technique within loops is using ++i (pre-increment) instead of i++ (post-increment). In the realm of unsigned integers, utilizing pre-increment can yield gas savings without compromising the functionality of the contract.

Vulnerability Details & Impact

Understanding Gas Consumption

  • Increased Costs with Post-Increment: The operation i++ (post-increment) consumes more gas than ++i (pre-increment). The post-increment operation involves incrementing the variable i but returns its initial value, necessitating a temporary variable. This process results in extra gas consumption, approximately an additional 5 gas per iteration.

Gas Savings with Pre-Increment

  • Efficiency of Pre-Increment: With ++i (pre-increment), the variable i is incremented first and the updated value is immediately returned, eliminating the need for a temporary variable and thereby saving gas.

This differentiation in gas cost between i++ (post-increment) and ++i (pre-increment) in Solidity, or in Ethereum smart contracts in general, comes down to how each operation is compiled and executed on the Ethereum Virtual Machine (EVM).

Post-increment (i++):

When you use i++, it is a post-increment operation. What this means is that the value of i is used first and then incremented. This involves temporarily storing the original value of i before it gets incremented, so it can be used or returned by the operation.

Here is a breakdown:

  • j = i; This step involves assigning the current value of i to a temporary variable j. This is an extra operation that consumes gas.

  • i = i + 1; This increments the value of i.

  • return j; Finally, the original value of i (now stored in j) is returned.

Due to the extra steps and the usage of a temporary variable, post-increment tends to consume more gas.

Pre-increment (++i):

On the other hand, ++i is a pre-increment operation. It increments the value of i first and then uses it or returns it, which is more straightforward and involves fewer steps.

Here is a breakdown:

  • i = i + 1; This step increments the value of i.

  • return i; This step returns the new incremented value.

Rational:

The key difference lies in the temporary variable and extra assignment operation used in the post-increment (i++). The EVM charges gas for every computational step, and since post-increment involves more steps, it tends to be costlier in terms of gas.

Optimizing for gas is crucial in Ethereum smart contracts to ensure that they are economical to run. Thus, choosing pre-increment (++i) over post-increment (i++) where possible is a better practice for gas optimization.

How to Implement ++i for Gas Savings

Practical Example: Pre-Increment Optimization

Consider a loop where you're incrementing a counter. Using pre-increment can save gas on each iteration:

Before Optimization:

solidityCopy code// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract LoopIncrementOptimizer {
    uint public counter = 0;

    function incrementCounter(uint times) public {
        for (uint i = 0; i < times; i++) {  // Using post-increment
            counter += 1;
        }
    }
}

After Optimization:

solidityCopy code// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract LoopIncrementOptimizer {
    uint public counter = 0;

    function incrementCounter(uint times) public {
        for (uint i = 0; i < times; ++i) {  // Using pre-increment
            counter += 1;
        }
    }
}

In the optimized version, ++i is used instead of i++, reducing gas consumption per loop iteration due to the avoidance of temporary variable creation and assignment.

Recommended Mitigation Steps

  1. Identify Loop Increments: Review your smart contract for loop structures where a counter variable is incremented.

  2. Use Pre-Increment: Change i++ to ++i in the loop to save gas on each iteration.

  3. Test: Ensure that the change doesnโ€™t affect the contract's functionality by conducting thorough testing.

Conclusion

While minor, the optimization from using pre-increment ++i over post-increment i++ can accumulate into meaningful gas savings, especially in contracts with extensive loop operations. This technique is simple and straightforward to implement but always verify through testing that the optimization does not inadvertently alter the expected behavior of the contract. Every bit of gas saved contributes to a more efficient and economical smart contract execution.

Recommendation

Custom Slither Detector

import re
from typing import List
from slither.detectors.abstract_detector import (
    AbstractDetector,
    DetectorClassification,
    DETECTOR_INFO,
)
from slither.formatters.naming_convention.naming_convention import custom_format
from slither.utils.output import Output


class ZokyoOptimizeIncrement(AbstractDetector):
    ARGUMENT = 'zokyo-optimize-increment'
    HELP = 'Zokyo: Optimize increment and decrement operations'
    IMPACT = DetectorClassification.OPTIMIZATION
    CONFIDENCE = DetectorClassification.HIGH

    WIKI = 'https://zokyo-auditing-tutorials.gitbook.io/zokyo-book-of-gas-savings/tutorials/gas-saving-technique-5-++i-costs-less-gas-compared-to-i++'
    WIKI_TITLE = 'Optimize Increment and Decrement'
    WIKI_DESCRIPTION = 'Detect post-increment (x++) and post-decrement (x--) operations and suggest using pre-increment (++x) and pre-decrement (--x) for optimization.'
    WIKI_EXPLOIT_SCENARIO = ''
    WIKI_RECOMMENDATION = 'Use pre-increment (++x) and pre-decrement (--x) rather than post-increment (x++) and post-decrement (x--).'

    def _detect(self) -> List[Output]:
        """ Detect the postfix increment and decrement operations """
        results = []

        info: DETECTOR_INFO



        for contract in self.contracts:
            for func in contract.functions:
                for node in func.nodes:
                    irs = node.irs
                    for index, ir in enumerate(irs):
                        code = str(ir)
                        # Regex pattern to specifically match post-increment in the IR
                        if re.search(r'TMP_\d+\(uint256\) := \w+\(uint256\)', code) and \
                           re.search(r'\w+\(uint256\) = \w+ \(c\)[+|-] 1', str(irs[index+1])):
                            
                            info = [
                                "Contract ", contract.name, ", function: ",func," has post inctrement/decrement (x++ / x--) \n"
                                'Consider using pre-increment/decrement for gas optimization. (++x / --x) \n'
                            ]

                            res = self.generate_result(info)
                            res.add(contract, {"target": "contract", "convention": "increment"})
                            results.append(res)

        return results

Any suggestions? please contact me on or

๐Ÿ“š
โฌ…๏ธ
Book an audit with Zokyo
[G-09] Gas: Using the logical NOT operator ! is cheaper than a comparison to the constant boolean value false - NOT operator ! cheaper than boolean FALSE
Linkedin
Twitter