---
# System prepended metadata

title: Gas Saving Techniques In Solidity Contracts

---

# Gas Saving Techniques In Solidity Contracts

There are several ways in which you can save gas fee while writing/deploying you contract. And as a good solidity/smart contract developer, it helps to know a few.

## Replacing memory with calldata

When passing arrays or strings to external functions:
- memory makes a full copy of the data → costs more gas.
- calldata is read-only and doesn’t copy data → much cheaper.

Use calldata whenever possible in external/public functions.

:::success
// Expensive
function processData(string memory input) external {}

// Cheaper
function processData(string calldata input) external {}
:::

## Loading state variables into memory

- Accessing storage (sload) is expensive.
- If you need to read a state variable multiple times, load it into a local variable (in memory/stack).

:::success
// Expensive
function foo() external view returns (uint) {
    return myStorageVar + myStorageVar;
}

// Cheaper
function foo() external view returns (uint) {
    uint temp = myStorageVar;
    return temp + temp;
}
:::

### Replace i++ with ++i

- i++ (post-increment) requires a temporary variable → extra gas.
- ++i (pre-increment) just increments.

:::success
for (uint i = 0; i < 10; ++i) {
    // cheaper
}
:::


## Caching array elements

- Accessing arr.length or arr[i] repeatedly costs extra gas.
- Cache values in a local variable.

:::success
uint length = arr.length;

for (uint i = 0; i < length; ++i) {
    uint element = arr[i];
    doSomething(element);
}
:::


## Short circuiting

Solidity’s && and || short-circuit:
- In A && B, if A is false, B is not evaluated.
- In A || B, if A is true, B is not evaluated.

Place cheaper conditions first to save gas.

:::success
if (x != 0 && 100 / x > 5) {
    // avoids divide by zero and saves gas
}
:::

## Using unchecked

unchecked { ... } tells Solidity:
➡️ “Do not insert overflow/underflow checks inside this block.”

:::success
function add(uint x, uint y) public pure returns (uint) {
    unchecked { return x + y; } // no overflow checks, cheaper
}
:::
- Gas saving: ~ 5–30 gas per operation, depending on context. This matters a lot inside loops.

### What happens on overflow?

#### Without unchecked:
:::success
uint a = type(uint).max; // max uint256
uint b = 1;
uint c = a + b; // ❌ Reverts (overflow)
:::

#### With unchecked:
:::success
uint a = type(uint).max;
uint b = 1;

unchecked {
    uint c = a + b; 
    // ✅ No revert, the counter starts again from 0 / wraps around to 0 
}
:::

👉 In other words:

With checks → transaction reverts (safe).

Unchecked → behaves like pre-Solidity 0.8 (wrap-around, aka (MAX + 1) mod (2^256) = 0).

#### When to use unchecked safely?

- In loops where overflow is impossible (e.g., for (uint i = 0; i < arr.length; ++i) since i won’t exceed arr.length).

:::success
for (uint i = 0; i < arr.length; ) {
    // safe to increment unchecked
    unchecked { ++i; }
}
:::


- When logic guarantees no overflow, e.g., subtracting where x >= y is checked before.

:::success
require(x >= y, "underflow");
unchecked { return x - y; }
:::


✅ Summary:
- unchecked removes overflow/underflow checks → saves gas.
- On overflow, the value wraps around instead of reverting.
- Use it only when you’re sure overflow cannot happen.
