I was asked to recompute the savings for various findings, boasting 100+ gas per +=
This is factually incorrect, using += will save 13 gas (for some reason), when
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
import "../../lib/test.sol";
import "../../lib/Console.sol";
contract GasTest is DSTest {
Adder c0;
AdderWithCache c1;
AdderWithUnchecked c2;
AdderWithUncheckedCache c3;
function setUp() public {
c0 = new Adder();
c1 = new AdderWithCache();
c2 = new AdderWithUnchecked();
c3 = new AdderWithUncheckedCache();
}
function testGas() public {
c0.addValue(123);
c1.addValue(123);
c2.addValue(123);
c3.addValue(123);
}
}
contract Adder {
uint256 value = 123;
function addValue(uint256 input) external returns (uint256) {
return value += input;
}
}
contract AdderWithCache {
uint256 value = 123;
function addValue(uint256 input) external returns (uint256) {
return value = value + input;
}
}
contract AdderWithUnchecked {
uint256 value = 123;
function addValue(uint256 input) external returns (uint256) {
unchecked {
return value += input;
}
}
}
contract AdderWithUncheckedCache {
uint256 value = 123;
function addValue(uint256 input) external returns (uint256) {
unchecked {
return value = value + input;
}
}
}
The finding saves at most 13 gas per instance, but won't save gas if used with unchecked
[PASS] testGas() (gas: 41203)
Test result: ok. 1 passed; 0 failed; finished in 905.07µs
| src/test/GasTest.t.sol:Adder contract | | | | | |
|---------------------------------------|-----------------|------|--------|------|---------|
| Deployment Cost | Deployment Size | | | | |
| 71805 | 284 | | | | |
| Function Name | min | avg | median | max | # calls |
| addValue | 5360 | 5360 | 5360 | 5360 | 1 |
| src/test/GasTest.t.sol:AdderWithCache contract | | | | | |
|------------------------------------------------|-----------------|------|--------|------|---------|
| Deployment Cost | Deployment Size | | | | |
| 71005 | 280 | | | | |
| Function Name | min | avg | median | max | # calls |
| addValue | 5347 | 5347 | 5347 | 5347 | 1 |
| src/test/GasTest.t.sol:AdderWithUnchecked contract | | | | | |
|----------------------------------------------------|-----------------|------|--------|------|---------|
| Deployment Cost | Deployment Size | | | | |
| 55393 | 201 | | | | |
| Function Name | min | avg | median | max | # calls |
| addValue | 5259 | 5259 | 5259 | 5259 | 1 |
| src/test/GasTest.t.sol:AdderWithUncheckedCache contract | | | | | |
|---------------------------------------------------------|-----------------|------|--------|------|---------|
| Deployment Cost | Deployment Size | | | | |
| 55393 | 201 | | | | |
| Function Name | min | avg | median | max | # calls |
| addValue | 5259 | 5259 | 5259 | 5259 | 1 |
For this specific finding optimizer doesn't matter (try for yourself)
I've used the excellent starter repo: https://github.com/0xKitsune/gas-lab
When I flag this issue, I always link to my gist and it shows the byte code differences, and there's an extra sload. You can check in remix too with the following: