Gas saving techniques for Smart Contract development

By akohad Apr17,2023

[ad_1]

Photo by Lance Reis on Unsplash
contract BadVariablePacking {

address public ownerAddress; //20byte - slot 0
bytes32 public hashedValue; //32 bytes - slot 1
uint256 public counter; //32 bytes - slot2
bool public randBool; //1 byte - slot 3
}

contract BetterVariablePacking {

address public ownerAddress; //20byte - slot 0
bool public randBool; //1 byte - slot 0
uint32 public counter; //4 byte - slot 0
bytes32 public hashedValue; //32 byte - slot 1
}

contract badStorageVariableAccessing {
uint256 public count;

function incrementCount(uint256 times) external {
for(uint i = 0; i < times; ++i){
++count;
}
}
}

contract betterStorageVariableAccessing{
uint256 public count;

function incrementCount(uint256 times) external {
uint256 tempCount = 0;
for(uint i = 0; i < times; ++i){
++tempCount;
}
count += tempCount;
}
}

contract badReadingFromStorage {
uint256 public winners = 10;
uint256 public winnerNum = 0;

function sendPrizes() public {
for(uint i = 0; i < winners; ++i){
++winnerNum;
}
}
}

contract betterStorageReading {
uint256 public winners = 10;
uint256 public winnerNum = 0;

function sendPrized() public {
uint256 tempIWinners = winners;
uint256 tempNum;
for(uint i = 0; i < tempWinners; ++i){
++tempNum;
}
winnerNum += tempNum;
}
}

//before
require(anyContract.owner() == msg.sender);
//do something
require(anyContract.owner() == msg.sender);
//do other things
require(anyContract.owner() == msg.sender);

//after
address ownerAddress = anyContract.owner();
require(ownerAddress == msg.sender);
//do something
require(ownerAddress == msg.sender);
//do other things
require(ownerAddress == msg.sender);

contract deleteStateVariable {
mapping(address => uint) balances;

function deposit() external payable {
balances[msg.sender] += msg.value;
}

function withdraw() external {
payable(msg.sender).call{value: balances[msg.sender]}("");
delete balances[msg.sender];
//yep, I knoe it's vulnerable to reentrancy ^.^
}
}

contract constantAndImmutable {

bytes32 public constant VALUE = keccak256("constant value");
address public immutable owner;

constructor() public {
owner = msg.sender;
}
}

contract expensiveRequire{

uint public value = 5;

function checkValue() external {
require(value > 0);
}
}

contract cheaperRequire{

uint public value = 5;

function checkValue() external {
require(value != 0);
}
}

contract badAndRequire{
int public constant MINIMUM = 1;
int public constant MAXIMUM = 100;

function limitedAddition(int a, int b) external {
int result = a + b;
require(result < MINIMUM && result > MAXIMUM, "the result exceeds the boundaries");
}
}

contract betterAndRequire{
int public constant MINIMUM = 1;
int public constant MAXIMUM = 100;

function limitedAddition(int a, int b) external {
int result = a + b;
require(result > MINIMUM, "Result too low");
require(result < MAXIMUM, "Result too high")
}
}

contract betterAndRequire{
int public constant MINIMUM = 1;
int public constant MAXIMUM = 100;

function limitedAddition(int a, int b) external {
int result = a + b;
require(result > MINIMUM, "ME-01");
require(result < MAXIMUM, "ME-02")
}
}

/////////
ME: Mathematic Errors
ME-01: result too low
ME-02: result too high

contract customErrors{
int public constant MINIMUM = 1;
int public constant MAXIMUM = 100;

error tooLow(uint firstValue, uint secondValue, uint result);
error tooHigh(uint firstValue, uint secondValue, uint result);

function limitedAddition(int a, int b) external {
int result = a + b;
if(result < MINIMUM) {
revert tooLow(a, b, result);
}

if(result > MAXIMUM) {
revert tooHigh(a, b, result);
}
}
}

//from
uint counter = 1;
counter++;

//to
uint counter = 1;
++counter;

//from
require(value >= 2);
//to
require(value > 1);

//from
require(value <= 2);
//to
require(value < 3);

contract publicAndExternal {
string message = "Hello World";

function publicFunction() public view returns(string memory){
return message;
}

function externalFunction() external view returns(string memory){
return message;
}
}

module.exports = {
solidity: {
compilers: [
{
version: "0.8.15",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
]
}
}
k(x) //expensive
j(y) //not expensive

j(y) && k(x)
j(y) || k(x)

string public caughtPokemon[];
caughtPokemon = ['Charizard', 'Alakazam', 'Mewtwo'];
mapping(uint => string) public betterCoughtPokemon;

betterCaughtPokemon[6] = 'Charizard';
betterCaughtPokemon[65] = 'Alakazam';
betterCaughtPokemon[150] = 'Mewtwo';

contract goodUseOfCallData {

string public name;

constructor(string calldata ownerName) external {
name = ownerName;
}

}

contract badUseOfCalldata {

uint256[] public favoriteNumbers;

constructor(uint256[] calldata favNum) external {
favoriteNumbers = new uint256[](favNum.length);
for(uint256 i = 0; i < favNum.length; ++i){
favoriteNumbers[i] = favNum[i] + 1;
}
}

}

contract badUseOfMemory {

string public name;

constructor(string memory ownerName) external {
name = ownerName;
}

}

contract goodUseOfMemory {

uint256[] public favoriteNumbers;

constructor(uint256[] calldata favNum) external {
favoriteNumbers = new uint256[](favNum.length);
for(uint256 i = 0; i < favNum.length; ++i){
favoriteNumbers[i] = favNum[i] + 1;
}
}

}

function forLoop(uint256 whenToStop) public {
for(uint256 i = 0; i < whenToStop;){
//do something
unchecked {
++i;
}
}
}
contract notIndexed {

event Log(address guy, uint256 favNumber);

function favoriteNumbers(uint256 number) external {
emit Log(msg.sender, number)
}
}

contract Indexed {

event Log(address indexed guy, uint256 indexed favNumber);

function favoriteNumbers(uint256 number) external {
emit Log(msg.sender, number)
}
}


function someOperation(uint256 x, uint256 y, uint256 z) external {
require(registered[msg.sender], "Not registered");
_someOperations(x, y, z);
}

function _someOperations(uint256 x, uint256 y, uint256 z) internal {
//do something
}

function batchSomeOperations(uint256[] calldata x, uint256[] calldata y, uint256[] calldata z) external {
require(registered[msg.sender], "Not registered");
require(x.length == z.length == y.length, "Wrong input");

for(uint i = 0; i < x.length;) {
_someOperations(x, y, z);
unchecked{
++i;
}
}
}

function someOperation(uint256 x, uint256 y, uint256 z) external {
require(registered[msg.sender], "Not registered");
_someOperations(x, y, z);
}

function _someOperations(uint256 x, uint256 y, uint256 z) internal {
//do something
}

modifier onlyOwner(){
require(owner() == msg.sender, "Ownable: caller is not the owner");
_;
}
modifier onlyOwner(){
_checkOwner();
_;
}

function _checkOwner() internal view virtual {
require(owner() == msg.sender, "Ownable: caller is not the owner");
}

  1. Celo. (n.d.). Gas Optimization Techniques in Solidity. Retrieved from https://docs.celo.org/blog/tutorials/gas-optimization-techniques-in-solidity#:~:text=One%20way%20to%20reduce%20gas,not%20modify%20the%20contract%20state.&text=In%20this%20contract%2C%20the%20constantValue,initialized%20with%20the%20value%2042.
  2. 0xmacro. (n.d.). Solidity Gas Optimizations Cheat Sheet. Retrieved from https://0xmacro.com/blog/solidity-gas-optimizations-cheat-sheet/

[ad_2]

Source link

By akohad

Related Post

Leave a Reply

Your email address will not be published. Required fields are marked *