Bird
Raised Fist0
Blockchain / Solidityprogramming~20 mins

Gas optimization for L2 in Blockchain / Solidity - Practice Problems & Coding Challenges

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Challenge - 5 Problems
🎖️
L2 Gas Optimization Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
Predict Output
intermediate
2:00remaining
Gas cost difference between storage and memory

Consider the following Solidity function on an L2 chain. What is the main difference in gas cost when using storage vs memory for the array?

Blockchain / Solidity
pragma solidity ^0.8.19;

contract GasTest {
    uint[] public data;

    function storeData(uint[] calldata input) external {
        for (uint i = 0; i < input.length; i++) {
            data.push(input[i]);
        }
    }

    function processData() external view returns (uint sum) {
        uint[] storage arr = data;
        for (uint i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
    }

    function processDataMemory() external view returns (uint sum) {
        uint[] memory arr = data;
        for (uint i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
    }
}
ABoth <code>storage</code> and <code>memory</code> have the same gas cost on L2 because storage reads are free.
BUsing <code>memory</code> copies the entire array from storage to memory, increasing gas cost due to data copying on L2.
CUsing <code>storage</code> for the array reads directly from blockchain storage, which is cheaper on L2 than copying to <code>memory</code>.
DUsing <code>memory</code> is cheaper because it avoids storage reads, which are very expensive on L2.
Attempts:
2 left
💡 Hint

Think about what happens when you copy data from storage to memory on L2.

Predict Output
intermediate
2:00remaining
Effect of calldata vs memory on gas usage

What is the gas cost difference when using calldata vs memory for function parameters on an L2 chain?

Blockchain / Solidity
pragma solidity ^0.8.19;

contract CalldataTest {
    function useCalldata(uint[] calldata input) external pure returns (uint) {
        uint sum = 0;
        for (uint i = 0; i < input.length; i++) {
            sum += input[i];
        }
        return sum;
    }

    function useMemory(uint[] memory input) external pure returns (uint) {
        uint sum = 0;
        for (uint i = 0; i < input.length; i++) {
            sum += input[i];
        }
        return sum;
    }
}
AUsing <code>calldata</code> is more expensive because it requires decoding data on each access.
BUsing <code>memory</code> is cheaper because it allows faster access to data on L2.
CBoth <code>calldata</code> and <code>memory</code> cost the same gas on L2.
DUsing <code>calldata</code> is cheaper because it avoids copying data into memory on L2.
Attempts:
2 left
💡 Hint

Consider how calldata is handled differently from memory in Solidity.

🔧 Debug
advanced
2:30remaining
Unexpected high gas cost in loop with storage writes

Why does the following Solidity function consume unexpectedly high gas on an L2 chain?

Blockchain / Solidity
pragma solidity ^0.8.19;

contract LoopGas {
    mapping(uint => uint) public data;

    function updateData(uint n) external {
        for (uint i = 0; i < n; i++) {
            data[i] = i * 2;
        }
    }
}
ABecause each storage write inside the loop costs gas, and writing to storage is expensive even on L2.
BBecause the loop variable <code>i</code> is not declared as <code>uint256</code>, causing overflow errors.
CBecause the mapping <code>data</code> is not initialized, causing runtime errors.
DBecause the function lacks the <code>payable</code> modifier, causing gas to be refunded.
Attempts:
2 left
💡 Hint

Think about the cost of writing to storage repeatedly in a loop on L2.

📝 Syntax
advanced
2:00remaining
Correct syntax for unchecked arithmetic to save gas

Which option correctly uses unchecked to save gas on L2 by skipping overflow checks?

Blockchain / Solidity
pragma solidity ^0.8.19;

contract UncheckedExample {
    function sum(uint a, uint b) external pure returns (uint) {
        uint c;
        // Insert unchecked block here
        return c;
    }
}
A{ unchecked c = a + b; }
Bunchecked c = a + b;
Cunchecked { c = a + b; }
Dc = unchecked(a + b);
Attempts:
2 left
💡 Hint

Recall the correct syntax for the unchecked block in Solidity.

🚀 Application
expert
3:00remaining
Optimizing batch token transfers on L2

You want to optimize a batch token transfer function on an L2 chain to minimize gas. Which approach will reduce gas the most?

AUse a single <code>transferFrom</code> call for the total amount, then update balances in memory and write once to storage.
BUse <code>delegatecall</code> to an external contract for each transfer to save gas.
CUse multiple <code>transferFrom</code> calls but mark the function <code>payable</code> to get gas refunds.
DUse a single <code>transferFrom</code> call per recipient inside a loop, writing to storage each time.
Attempts:
2 left
💡 Hint

Think about minimizing storage writes and external calls on L2.

Practice

(1/5)
1. Which of the following is a common method to reduce gas costs on Layer 2 blockchains?
easy
A. Using loops with many iterations
B. Increasing the block size limit
C. Adding more storage variables to the contract
D. Using calldata instead of memory for function inputs

Solution

  1. Step 1: Understand calldata vs memory

    Calldata is cheaper than memory because it is read-only and does not require copying data.
  2. Step 2: Identify gas saving method

    Using calldata for function inputs reduces gas compared to memory or storage.
  3. Final Answer:

    Using calldata instead of memory for function inputs -> Option D
  4. Quick Check:

    Calldata is cheaper than memory [OK]
Hint: Choose calldata for inputs to save gas on L2 [OK]
Common Mistakes:
  • Thinking increasing block size reduces gas
  • Assuming more storage variables save gas
  • Using loops without optimization
2. Which Solidity syntax correctly declares a function parameter to use calldata for gas optimization on L2?
easy
A. function foo(string memory data) external {}
B. function foo(string calldata data) external {}
C. function foo(string storage data) external {}
D. function foo(string data) external {}

Solution

  1. Step 1: Recall parameter data location keywords

    Solidity allows memory, storage, or calldata for reference types in parameters.
  2. Step 2: Identify calldata usage

    Calldata is specified explicitly as string calldata for external functions to save gas.
  3. Final Answer:

    function foo(string calldata data) external {} -> Option B
  4. Quick Check:

    Calldata keyword used correctly [OK]
Hint: Use 'calldata' keyword for external function parameters [OK]
Common Mistakes:
  • Using memory instead of calldata for external inputs
  • Omitting data location keyword
  • Using storage incorrectly in parameters
3. What will be the gas cost difference when using unchecked math in Solidity on L2 compared to normal math?
medium
A. Gas cost decreases because overflow checks are skipped
B. Gas cost increases due to extra checks
C. Gas cost stays the same
D. Gas cost is unpredictable

Solution

  1. Step 1: Understand unchecked math

    Unchecked math skips overflow and underflow checks, saving gas.
  2. Step 2: Compare gas costs

    Skipping checks reduces gas cost compared to normal safe math operations.
  3. Final Answer:

    Gas cost decreases because overflow checks are skipped -> Option A
  4. Quick Check:

    Unchecked math saves gas by skipping checks [OK]
Hint: Unchecked math skips checks, lowering gas [OK]
Common Mistakes:
  • Assuming unchecked math adds overhead
  • Believing gas cost is unchanged
  • Ignoring overflow risks
4. Given this Solidity snippet on L2, what is the main issue causing higher gas usage?
uint256 public count;
function increment() external {
  count = count + 1;
}
medium
A. Missing unchecked block for increment
B. Using public variable instead of private
C. Function should be view instead of external
D. No issue, code is optimal

Solution

  1. Step 1: Identify gas cost in arithmetic

    Normal addition includes overflow checks increasing gas.
  2. Step 2: Suggest unchecked usage

    Wrapping increment in unchecked { count += 1; } saves gas by skipping checks.
  3. Final Answer:

    Missing unchecked block for increment -> Option A
  4. Quick Check:

    Unchecked block reduces gas for safe increments [OK]
Hint: Use unchecked for simple increments to save gas [OK]
Common Mistakes:
  • Thinking public visibility affects gas here
  • Confusing external with view function
  • Assuming code is already optimized
5. You want to optimize a Layer 2 contract that stores multiple small variables. Which approach best reduces gas usage?
hard
A. Use dynamic arrays for all variables
B. Store each variable in separate storage slots for clarity
C. Pack multiple uint8 variables into a single uint256 storage slot
D. Avoid using calldata and always copy to memory

Solution

  1. Step 1: Understand storage slot packing

    Multiple small variables like uint8 can fit into one 256-bit slot, saving gas.
  2. Step 2: Compare storage strategies

    Separating variables wastes slots; dynamic arrays add overhead; calldata usage unrelated here.
  3. Final Answer:

    Pack multiple uint8 variables into a single uint256 storage slot -> Option C
  4. Quick Check:

    Storage packing reduces gas by slot sharing [OK]
Hint: Pack small vars into one slot to save gas [OK]
Common Mistakes:
  • Using separate slots wastes gas
  • Overusing dynamic arrays increases cost
  • Ignoring calldata benefits in storage