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?
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]; } } }
Think about what happens when you copy data from storage to memory on L2.
On L2, reading from storage is cheaper than on L1 but still costs gas. Copying data from storage to memory requires reading each element and writing it to memory, which increases gas cost. Therefore, using memory for large arrays increases gas due to copying overhead.
What is the gas cost difference when using calldata vs memory for function parameters on an L2 chain?
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; } }
Consider how calldata is handled differently from memory in Solidity.
calldata is a read-only area where function arguments are stored. Using calldata avoids copying data into memory, saving gas on L2. memory requires copying, which costs more gas.
Why does the following Solidity function consume unexpectedly high gas on an L2 chain?
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; } } }
Think about the cost of writing to storage repeatedly in a loop on L2.
Each write to storage costs gas, even on L2. Writing inside a loop multiplies this cost by the number of iterations, causing high gas consumption.
Which option correctly uses unchecked to save gas on L2 by skipping overflow checks?
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; } }
Recall the correct syntax for the unchecked block in Solidity.
The unchecked keyword is used as a block to wrap code where overflow checks are skipped. The correct syntax is unchecked { ... }.
You want to optimize a batch token transfer function on an L2 chain to minimize gas. Which approach will reduce gas the most?
Think about minimizing storage writes and external calls on L2.
Minimizing storage writes is key for gas savings on L2. Doing all balance updates in memory and writing once reduces gas. Multiple transferFrom calls and storage writes increase gas cost.