You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Description:
Short-circuiting is a solidity contract development model that uses OR/AND logic to sequence different cost operations. It puts low gas cost operations in the front and high gas cost operations in the back, so that if the front is low If the cost operation is feasible, you can skip (short-circuit) the subsequent high-cost Ethereum virtual machine operation.
//f(x) is a low gas cost operation
//g(y) is a high gas cost operation
//Sort operations with different gas costs as follows
f(x) || g(y)
f(x) && g(y)
Proof Of Concept:
The optimizer was turned on and set to 10000 runs
Operator.sol#L739-L741 : [ Min 2000 Gas Saved ]
RANGE.sol#L221 : [ 2111 Gas Saved (Poc is given below) ]
Description:
In the repayLoan function, gas is saved if transactions that consume gas but are not necessary are removed safeTransferFrom. Since the safeTransferFrom function does all balance and return success checks, there is no need for an additional check. So if we removed to balanceOf and other math. totaly ~1000 gas saved (Get the balance of the account it will cost 400 units of gas)
functionrepayLoan(ERC20token_,uint256amount_)externalnonReentrant{if(reserveDebt[token_][msg.sender]==0)revertTRSRY_NoDebtOutstanding();// uint256 prevBalance = token_.balanceOf(address(this)); (This line not necessary)token_.safeTransferFrom(msg.sender,address(this),amount_);// uint256 received = token_.balanceOf(address(this)) - prevBalance; (This line not necessary)reserveDebt[token_][msg.sender]-=amount;// (directly read to ‘amount’ )totalDebt[token_]-=amount;// (directly read to ‘amount’ )emitDebtRepaid(token_,msg.sender,amount);// (directly read to ‘amount’ )}
3 – Gas improvement on returning instructionsId value [~200 gas saved]
Description:
A division by 2 can be calculated by shifting one to the right. While the DIV opcode uses 5 gas, the SHR opcode only uses 3 gas Furthermore, Solidity's division operation also includes a division-by-0 prevention which is bypassed using shifting.
Recommendation:
Change the functions visibility to external to save gas.
Proof Of Concept:
The optimizer was turned on and set to 10000 runs
Description:
OpenZeppelin uint256 and bool comparison :
Booleans are more expensive than uint256 or any type that takes up a full word because each write operation emits an extra SLOAD to first read the slot's contents, replace the bits taken up by the boolean, and then write back. This is the compiler's defense against contract upgrades and pointer aliasing, and it cannot be disabled.The values being non-zero value makes deployment a bit more expensive.
Recommendation:
Use uint256(1) and uint256(2) instead of bool
Proof Of Concept:
The optimizer was turned on and set to 10000 runs
contractGasTestisDSTest{Contract0c0;Contract1c1;functionsetUp()public{c0=newContract0();c1=newContract1();}functiontestGas()public{c0._setPolicyPermissions(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4,79,true);c1._setPolicyPermissions(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4,79,2);}}contractContract0{mapping(address=>mapping(uint256=>bool))publicmodulePermissions;errorboolcheck();function_setPolicyPermissions(addressaddr_,uint256id,boollog)external{modulePermissions[addr_][id]=log;if(modulePermissions[addr_][id]=false)revertboolcheck();}}contractContract1{mapping(address=>mapping(uint256=>uint256))publicmodulePermissions;errorboolcheck();// Use uint256 instead of bool (1 = false , 2 = true) function_setPolicyPermissions(addressaddr_,uint256id,uint256log)external{modulePermissions[addr_][id]==log;if(modulePermissions[addr_][id]==1)revertboolcheck();}}
Description:
Newer versions of the Solidity compiler will check for integer overflows and underflows automatically. This provides safety but increases gas costs. When an unsigned integer is guaranteed to never overflow, the unchecked feature of Solidity can be used to save gas costs. There is no need for -= received safemath check in this function, there is no possibility of underflow, the first operations of the function do these checks
Description:
If a function modifier or require such as onlyOwner-admin is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are CALLVALUE(2), DUP1(3), ISZERO(3), PUSH2(3), JUMPI(10), PUSH1(3), DUP1(3), REVERT(0), JUMPDEST(1), POP(2), which costs an average of about 24 gas per call to the function, in addition to the extra deployment cost
Recommendation:
Functions guaranteed to revert when called by normal users can be marked payable (for only onlyowner or admin functions)
Proof Of Concept:
The optimizer was turned on and set to 10000 runs
11 - Function Ordering via Method ID [per gas 22 instance]
Context:
All Contracts
Description:
Contracts most called functions could simply save gas by function ordering via Method ID. Calling a function at runtime will be cheaper if the function is positioned earlier in the order (has a relatively lower Method ID) because 22 gas are added to the cost of a function for every position that came before it. The caller can save on gas if you prioritize most called functions.
Recommendation:
Find a lower method ID name for the most called functions for example Call() vs. Call1() is cheaper by 22 gas
For example, the function IDs in the Operator.sol contract will be the most used; A lower method ID may be given
Description:
You can cut out 10 opcodes in the creation-time EVM bytecode if you declare a constructor payable. Making the constructor payable eliminates the need for an initial check of msg.value == 0 and saves 13 gas on deployment with no security risks.
Description:
One can save gas by caching the array length (in stack) and using that set variable in the loop. Replace state variable reads and writes within loops with local variable reads and writes. This is done by assigning state variable values to new local variables, reading and/or writing the local variables in a loop, then after the loop assigning any changed local variables to their equivalent state variables.
Recommendation:
Simply do something like so before the for loop: uint length = variable.length Then add length in place of variable.length in the for loop.
Proof Of Concept:
The optimizer was turned on and set to 10000 runs
Gas Optimizations List
short-circuit
moderepayLoan
function for gas earningsinstructionsId
value.Shifting
cheaper thandivision
uint256
instead ofbool
in mappings is more gas efficienttoggleBeat
architecture frombool
touint256
saves gas-= received
[85 gas per use + ~15000 gas saved during deployment cost ]payable
<x> += <y>
costs more gas than<x> = <x> + <y>
for state variablespayable
if
private
rather thanpublic
forconstans
, saves gasaddress(0)
>
instead of>=
is more gas efficient1- Sort Solidity operations using short-circuit mode [2111 gas saved]
Context:
RANGE.sol#L221
Operator.sol#L739-L741
Description:
Short-circuiting is a solidity contract development model that uses
OR/AND
logic to sequence different cost operations. It puts low gas cost operations in the front and high gas cost operations in the back, so that if the front is low If the cost operation is feasible, you can skip (short-circuit) the subsequent high-cost Ethereum virtual machine operation.Proof Of Concept:
The optimizer was turned on and set to 10000 runs
Operator.sol#L739-L741 : [ Min 2000 Gas Saved ]
RANGE.sol#L221 : [ 2111 Gas Saved (Poc is given below) ]
Gas Report:
2- Update on
repayLoan
function for gas earnings [~1000 gas]Context:
TRSRY.sol#L105-L119
Description:
In the
repayLoan
function, gas is saved if transactions that consume gas but are not necessary are removed safeTransferFrom. Since thesafeTransferFrom
function does all balance and return success checks, there is no need for an additional check. So if we removed tobalanceOf
and other math. totaly ~1000 gas saved (Get the balance of the account it will cost 400 units of gas)Current Code
Recomendation code:
3 – Gas improvement on returning
instructionsId
value [~200 gas saved]Context:
INSTR.sol#L42
Recommendation:
instructionsId
in function returns and delete INSTR.sol#L78 can save gasProof Of Concept:
The optimizer was turned on and set to 10000 runs
INSTR.sol#L78
Recomendation code:
4 - Shifting cheaper than division [146 gas per instance]
Context:
Operator.sol#L372
Operator.sol#L427
Description:
A division by 2 can be calculated by shifting one to the right. While the
DIV
opcode uses5 gas
, theSHR
opcode only uses3 gas
Furthermore, Solidity's division operation also includes a division-by-0 prevention which is bypassed using shifting.Recommendation:
Change the functions visibility to external to save gas.
Proof Of Concept:
The optimizer was turned on and set to 10000 runs
Gas Report
5 - Using
uint256
instead ofbool
in mappings is more gas efficient [146 gas per instance]Context:
Kernel.sol#L181
Kernel.sol#L194
Kernel.sol#L197
BondCallback.sol#L24
Governance.sol#L105
Governance.sol#L117
Description:
OpenZeppelin uint256 and bool comparison :
Booleans are more expensive than uint256 or any type that takes up a full word because each write operation emits an extra SLOAD to first read the slot's contents, replace the bits taken up by the boolean, and then write back. This is the compiler's defense against contract upgrades and pointer aliasing, and it cannot be disabled.The values being non-zero value makes deployment a bit more expensive.
Recommendation:
Use uint256(1) and uint256(2) instead of bool
Proof Of Concept:
The optimizer was turned on and set to 10000 runs
Gas Report
6- Converting
toggleBeat
architecture frombool
touint256
saves gas [130 gas per instance]Context:
Heart.sol#L135-L137
Operator.sol#L624-L627
Current Code
Recomendation code:
Proof Of Concept:
Proof of Concept Gas Report
7 – Gas can be saved by changing the way the constructor defines its arguments. [94 gas per use]
Context:
TRSRY.sol#L17
MINTR.sol#L8
RANGE.sol#L16
PRICE.sol#L22
VOTES.sol#L11
INSTR.sol#L10
Description:
When the constructor is inherited, the constructor arguments in the contract we inherit can be updated in two ways.
1 - Either specify directly in the inheritance list. (New use with Gas Optimization)
2- Or via a "modifier" of the derived constructor. (standard use)
In the contexts mentioned above, we get gas saved with this usage
Proof Of Concept:
The optimizer was turned on and set to 10000 runs
Gas Report
8 - Unchecked decrement can be used in
-= received
[85 gas per use + ~15000 gas saved during deployment cost]Context:
TRSRY.sol#L116
Description:
Newer versions of the Solidity compiler will check for integer overflows and underflows automatically. This provides safety but increases gas costs. When an unsigned integer is guaranteed to never overflow, the unchecked feature of Solidity can be used to save gas costs. There is no need for
-= received
safemath check in this function, there is no possibility of underflow, the first operations of the function do these checksYou can see exactly this example in transmission11 in solmate ERC20 contract:
https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol#L99-L105
Current Code
Recomendation code:
Proof Of Concept:
Proof of Concept Gas Report
9 - Use assembly to write address storage values [33 gas per instance]
Context:
Heart.sol#L144-L145
Kernel.sol#L76-L77
Operator.sol#L119-L120
Operator.sol#L593-L594
BondCallback.sol#L43-L44
Proof Of Concept:
The optimizer was turned on and set to 10000 runs
Gas Report
10 - Functions Guaranteed to Revert When Callled By Normal Users Can Be Marked Payable [24 gas per instance]
Context:
Kernel.sol#L235
Kernel.sol#L439
Kernel.sol#L451
BondCallback.sol#L190
BondCallback.sol#L152
Heart.sol#L130
Heart.sol#L135
Heart.sol#L140
Heart.sol#L150
Description:
If a function modifier or require such as onlyOwner-admin is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are CALLVALUE(2), DUP1(3), ISZERO(3), PUSH2(3), JUMPI(10), PUSH1(3), DUP1(3), REVERT(0), JUMPDEST(1), POP(2), which costs an average of about 24 gas per call to the function, in addition to the extra deployment cost
Recommendation:
Functions guaranteed to revert when called by normal users can be marked payable (for only
onlyowner
oradmin
functions)Proof Of Concept:
The optimizer was turned on and set to 10000 runs
Gas Report
11 - Function Ordering via Method ID [per gas 22 instance]
Context:
All Contracts
Description:
Contracts most called functions could simply save gas by function ordering via Method ID. Calling a function at runtime will be cheaper if the function is positioned earlier in the order (has a relatively lower Method ID) because 22 gas are added to the cost of a function for every position that came before it. The caller can save on gas if you prioritize most called functions.
Recommendation:
Find a lower
method ID
name for the most called functions for example Call() vs. Call1() is cheaper by22 gas
For example, the function IDs in the
Operator.sol
contract will be the most used; A lower method ID may be givenProof of Consept:
https://coinsbench.com/advanced-gas-optimizations-tips-for-solidity-85c47f413dc5
Operator.sol function names can be named and sorted according to METHOD ID
12 -
x += y
costs more gas thanx = x + y
for state variables [16 gas per instance]Context:
PRICE.sol#L136
PRICE.sol#L138
TRSRY.sol#L96-L97
TRSRY.sol#L131
VOTES.sol#L58
BondCallback.sol#L143-L144
Governance.sol#L198
Governance.sol#L252-L254
Heart.sol#L103
Description:
x += y
costs more gas thanx = x + y
for state variablesProof Of Concept:
The optimizer was turned on and set to 10000 runs
Gas Report
13 - Setting The Constructor To Payable [13 gas per instance]
Context:
Kernel.sol#L217, TRSRY.sol#L45, MINTR.sol#L15
RANGE.sol#L77, PRICE.sol#L22, VOTES.sol#L16
INSTR.sol#L20, TreasuryCustodian.sol#L24
Operator.sol#L92, BondCallback.sol#L38, Heart.sol#L54
PriceConfig.sol#L15, Governance.sol#L59, VoterRegistration.sol#L16
Description:
You can cut out 10 opcodes in the creation-time EVM bytecode if you declare a constructor payable. Making the constructor payable eliminates the need for an initial check of
msg.value == 0
and saves13 gas
on deployment with no security risks.Recommendation:
Set the constructor to
payable
Proof Of Concept:
https://forum.openzeppelin.com/t/a-collection-of-gas-optimisation-tricks/19966/5?u=pcaversaccio
The optimizer was turned on and set to 10000 runs
Gas Report
14 - Catching The Array Length Prior To Loop [ 13 gas per 6 arrays instance]
Context:
Governance.sol#L278
Description:
One can save gas by caching the array length (in stack) and using that set variable in the loop. Replace state variable reads and writes within loops with local variable reads and writes. This is done by assigning state variable values to new local variables, reading and/or writing the local variables in a loop, then after the loop assigning any changed local variables to their equivalent state variables.
Recommendation:
Simply do something like so before the for loop:
uint length = variable.length
Then add length in place ofvariable.length
in the for loop.Proof Of Concept:
The optimizer was turned on and set to 10000 runs
Gas Report
15 – Direct definition of boolean literals consumes more gas When we use
if
[9 gas per instance]Context:
Governance.sol#L223-L224
Governance.sol#L306
Description:
Direct definition of boolean literals consumes more gas When we use
if
Proof Of Concept
The optimizer was turned on and set to 10000 runs
use for GasTest : Governance.sol#L223-L224
Gas Report
16 - Using
private
rather thanpublic
forconstans
, saves gas [7 gas per instance]Context:
Governance.sol#L121
Governance.sol#L124
Governance.sol#L127
Governance.sol#L130
Governance.sol#L133
Governance.sol#L137
RANGE.sol#L65
Operator.sol#L89
Proof Of Concept
The optimizer was turned on and set to 10000 runs
Gas Report
17 - Use assembly to check for
address(0)
[6 gas per instance]Context:
BondCallback.sol#L191
Proof Of Concept:
The optimizer was turned on and set to 10000 runs
Gas Report:
18 - Using
>
instead of>=
is more gas efficient [3 gas per instance]Context:
Operator.sol#L486
Proof Of Concept
The optimizer was turned on and set to 10000 runs
use for GasTest : Operator.sol#L486
Gas Report
The text was updated successfully, but these errors were encountered: