As we all know, there are many factors that determine a good smart contract, such as:
-
Security: it has minimal/zero vulnerability so they cannot be exploited by an adversary. Immune to Attacks.
-
Cost: how much in total a
(a) smart contract deployment costs, (b) running/invoking each function of it costs.
-
Correctness: it executes as it has been planned.
In this question, I'd like to focus on the cost of a smart contract.
Question 1: How to make a cost-effective smart contract?
Question 2: How to avoid using some expensive functions and what are the alternatives? In other words, are there any functions well-known to be more expensive than other operations and can we replace them with better ones?
Question 3: In general, what are the good practice of writing a smart contract with minimal cost?
In short: How can we save gas : ether : money?
Best Answer
In Ethereum, transactions cost gas and hence ether. The gas consumption of a transaction depends on the opcodes that the EVM has to execute. The gas cost for each Opcode can be found as explained in this question. Few common opcodes and gas are,
This is a concern when it comes to smart contracts as transactions are also involved and it's important to consider the gas cost when designing a contract.
Reducing the gas consumed by a contract is important in two situations,
Cost of deploying a contract
For this, most of the optimizations are done at compilation time as described in the documentation-faqs,
And the details of the optimizer can be found here.
Another way of reducing the size is by removing useless code. For example:
In above code, line 3 and 4 will never be executed and these type of useless code can be avoided by carefully going through the contract logic and that will reduce the size of the smart contract.
Cost to call the contract functions
When contracts' functions are called, for the execution of function it costs gas. Hence optimizing functions to use less gas is important. There can be many different ways of doing it when individual contract is considered. Here are few that might save gas during execution,
Expensive operations are the opcodes that has more gas values such as
SSTORE
. Below are some methods of reducing expensive operations.A) Use of Short Circuiting rules
So if a logical operation includes an expensive operation and a low cost operation, arranging in a way that the expensive operation can be short circuited will reduce gas at some executions.
If f(x) is low cost and g(y) is expensive, arranging logical operations
f(x) || g(y)
f(x) && g(y)
will save more gas if short circuited.
If
f(x)
has a considerably higher probability of returning false compared tog(y)
, arranging AND operations asf(x) && g(y)
might cause to save more gas in execution by short circuiting.If
f(x)
has a considerably higher probability of returning true compared tog(y)
, arranging OR operations asf(x) || g(y)
might cause to save more gas in execution by short circuiting.B) expensive operations in a loop
eg:
In the above code, since
sum
storage variable is read and written every time inside the loop, storage operations that are expensive take place at every iteration. This can be avoided by introducing a local variable as follows to save gas.loop combining
loop-1 and loop-2 can be combined and gas can be saved,
and a few more loop patterns can be found here.
From Docs,
and
having a fixed length always saves gas. Refer to this question as well.
Removing useless code as explained earlier under contract deployment will save gas even when functions are executed, if that can be done inside functions.
Not using libraries when implementing the functionality is cheaper for simple usages.
Calling library for simple usages may be costly. If the functionality is simple and feasible to implement inside the contract as it avoids the step of calling the library. execution cost for the functionality only will still be the same for both.
Using visibility
external
for the functions only accessed externally forces to usecalldata
as the parameter location and this saves some gas when the function executes.Using
memory
variables within functions locally when possible saves gas of accessing thestorage
.These are some ways of saving gas and there may be many other methods depending on the requirements.