├── test.sol └── README.md /test.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.15; 2 | 3 | contract Test { 4 | 5 | // 5 loops, total gas cost == 22138 6 | // 100 loops, total gas cost == 27743 7 | // 1000 loops, total gas cost == 80855 8 | function increment0(uint256 loops) external pure returns (uint256) { 9 | uint256 value; 10 | for (uint256 i; i < loops;) { 11 | unchecked { ++i; } 12 | value = i; 13 | } 14 | return value; 15 | } 16 | 17 | // 5 loops, total gas cost == 22051 18 | // 100 loops, total gas cost == 26326 19 | // 1000 loops, total gas cost == 66838 20 | function increment1(uint256 loops) external pure returns (uint256) { 21 | uint256 value; 22 | for (uint256 i;;) { 23 | unchecked { ++i; } 24 | value = i; 25 | if (i >= loops) break; 26 | } 27 | return value; 28 | } 29 | 30 | // 5 loops, total gas cost == 22019 31 | // 100 loops, total gas cost == 26294 32 | // 1000 loops, total gas cost == 66806 33 | function increment2(uint256 loops) external pure returns (uint256) { 34 | uint256 value; 35 | for (uint256 i;;) { 36 | unchecked { i += 1; } // i += 1 cheaper than ++i 37 | value = i; 38 | if (i >= loops) break; 39 | } 40 | return value; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # More optimal for loops 2 | 3 | In test.sol there are 3 functions with the total gas cost in comments above them: 4 | 5 | - **increment0** : The unchecked style for loop 6 | 7 | - **increment1** : A cheaper more optimized version of increment0 8 | 9 | ## Total gas cost breakdown 10 | ### increment0 11 | | loop count | gas cost | 12 | |------------|----------| 13 | | 5 | 22138 | 14 | | 100 | 27743 | 15 | | 1000 | 80855 | 16 | 17 | ### increment1 18 | | loop count | gas cost | 19 | |------------|----------| 20 | | 5 | 22051 | 21 | | 100 | 26326 | 22 | | 1000 | 66838 | 23 | 24 | ### increment2 25 | | loop count | gas cost | 26 | |------------|----------| 27 | | 5 | 22019 | 28 | | 100 | 26294 | 29 | | 1000 | 66806 | 30 | 31 | 32 | 33 | 34 | 35 | ## OPCODES 36 | 37 | 38 | ### increment0 39 | ### 58 total gas per loop 40 | ##### OPCODES for 1 loop with increment0 41 | 42 | 43 | 44 | | OPCODE | GAS | 45 | |---------------|--------------------------------------------------------| 46 | | JUMPDEST | 1 gas, one time cost. wont count this in total. | 47 | | DUP4. | 3 gas | 48 | | DUP2 | 3 gas | 49 | | LT | 3 gas | 50 | | ISZERO | 3 gas | 51 | | PUSH2 0112 | 3 gas | 52 | | JUMPI | 10 gas | 53 | | DUP1 | 3 gas | 54 | | PUSH1 01 | 3 gas | 55 | | ADD | 3 gas | 56 | | SWAP1 | 3 gas | 57 | | POP | 2 gas | 58 | | DUP1 | 3 gas | 59 | | SWAP2 | 3 gas | 60 | | POP | 2 gas | 61 | | PUSH2 00fc | 3 gas | 62 | | JUMP | 8 gas | 63 | 64 | 65 | ### increment1 66 | ### 47 gas total per loop 67 | #### OPCODES for 1 loop with increment1 68 | 69 | 70 | | OPCODE | GAS | 71 | |---------------|-------------------------------------------------------| 72 | | JUMPDEST | 1 gas, one time on cost. wont count this in total | 73 | | DUP1 | 3 gas | 74 | | PUSH1 01 | 3 gas | 75 | | ADD | 3 gas | 76 | | SWAP1 | 3 gas | 77 | | POP | 2 gas | 78 | | DUP1 | 3 gas | 79 | | SWAP2 | 3 gas | 80 | | POP | 2 gas | 81 | | DUP4 | 3 gas | 82 | | DUP2 | 3 gas | 83 | | GT | 3 gas | 84 | | ISZERO | 3 gas | 85 | | PUSH2 0122 | 3 gas | 86 | | JUMPI | 10 gas | 87 | 88 | 89 | ## EXPLANATION 90 | So when we declare our loop break condition in the for loop, we have check at the beginning of every loop, followed by a JUMPI which is a conditional jump that basically says if this is false jump out of the loop but if its true jump into the loop. And if its true we continue through the loop and then hit the end and have to hit an additonal jump to get back to the top of the loop. 91 | But in the new way we just continue through the loop and hit our condition at the end and then hit only one JUMPI which says either jump back to the top of the loop or just jump out of the loop. All in all saving us 11 gas a loop, plus possibly some additional gas on the for loop setup 92 | 93 | Now for this to work your if statement with the loop break has to be the very last thing in your loop. You have to increment i then check the conditional 94 | --------------------------------------------------------------------------------