Skip to content

Commit

Permalink
adding modify input example
Browse files Browse the repository at this point in the history
  • Loading branch information
devdacian committed Feb 12, 2025
1 parent 2634aef commit 7f53460
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 0 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,22 @@ Again using only the 1 storage slot, this produces the following call stack:
```

In our simplied example using only 1 storage slot the gas cost was 9.45% cheaper with optimizer enabled and 11.86% cheaper without the optimizer. In real-world protocols where multiple storage slots are not changed but frequently read the gas savings are likely to be even greater.


### #14 Modify Input Instead Of Temp Variable: EFFECTIVE 0.19% CHEAPER ###
When an input variable's value doesn't need to be preserved, modifying that input variable is more efficient than using a temporary variable inside the function:
```diff
function returnLowest(uint256 input) external view returns(uint256 lowest) {
lowest = input;

uint256 compsLen = comps.length;
for(uint256 i; i<compsLen; i++) {
- uint256 temp = comps[i];
+ input = comps[i];

if(temp < lowest) {
lowest = temp;
}
}
}
```
24 changes: 24 additions & 0 deletions src/14-modify-input/ModifyInputFixed.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {ModifyInputUnop} from "./ModifyInputUnop.sol";

contract ModifyInputFixed is ModifyInputUnop {

constructor(uint256[] memory _comps) ModifyInputUnop(_comps) {}

function returnLowest(uint256 input) external view override returns(uint256 lowest) {
lowest = input;

uint256 compsLen = comps.length;
for(uint256 i; i<compsLen; i++) {
// overwrite input for comparison, no need for additional
// temporary variable if original input val doesn't need preservation
input = comps[i];

if(input < lowest) {
lowest = input;
}
}
}
}
30 changes: 30 additions & 0 deletions src/14-modify-input/ModifyInputUnop.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

interface IModifyInput {
function returnLowest(uint256 input) external view returns(uint256 lowest);
}

contract ModifyInputUnop is IModifyInput {
uint256[] internal comps;

constructor(uint256[] memory _comps) {
for(uint256 i; i<_comps.length; i++) {
comps.push(_comps[i]);
}
}

function returnLowest(uint256 input) external view virtual returns(uint256 lowest) {
lowest = input;

uint256 compsLen = comps.length;
for(uint256 i; i<compsLen; i++) {
// use a temporary variable for the comparison
uint256 temp = comps[i];

if(temp < lowest) {
lowest = temp;
}
}
}
}
54 changes: 54 additions & 0 deletions test/14-modify-input/ModifyInputTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Test, console} from "forge-std/Test.sol";
import {IModifyInput, ModifyInputUnop} from "../../src/14-modify-input/ModifyInputUnop.sol";
import {ModifyInputFixed} from "../../src/14-modify-input/ModifyInputFixed.sol";

// Optimizer ON, 10000 runs
// ========================
// Pre : 19260 gas
// Post : 19223 gas (0.19% cheaper)
// forge test --optimizer-runs 10000 --match-contract ModifyInputTest --match-test test_returnLowest -vvv
//
// Optimizer OFF
// =============
// Pre : 19278 gas
// Post : 19241 gas (0.19% cheaper)
// forge test --match-contract ModifyInputTest --match-test test_returnLowest -vvv
//
// Conclusion
// ==========
// Modifying an input variable whose value doesn't need to be preserved
// is more gas-efficient than using an additional temporary variable
contract ModifyInputTest is Test {
IModifyInput internal modifyInputUnop;
IModifyInput internal modifyInputFixed;

function setUp() external virtual {
// create contracts being tested
uint256[] memory comps = new uint256[](5);
comps[0] = 5;
comps[1] = 4;
comps[2] = 3;
comps[3] = 2;
comps[4] = 1;

modifyInputUnop = new ModifyInputUnop(comps);
modifyInputFixed = new ModifyInputFixed(comps);

assertEq(modifyInputUnop.returnLowest(10), comps[4]);
assertEq(modifyInputFixed.returnLowest(10), comps[4]);
}

function test_returnLowest() external view {
// call functions under test
uint256 gasPre = gasleft();
modifyInputUnop.returnLowest(10);
console.log("Unoptimized returnLowest() cost %d gas", gasPre - gasleft());

gasPre = gasleft();
modifyInputFixed.returnLowest(10);
console.log("Optimized returnLowest() cost %d gas", gasPre - gasleft());
}
}

0 comments on commit 7f53460

Please sign in to comment.