Greetings dear readers!
We continue our series of educational articles and today we’ll look at some specific tips for optimizing gas in the development of smart contracts on Solidity!
In Solidity, some data types have a higher gas cost than others. And that is what is often required of a smart contract developer and that’s why you should understand the gas utilization of the available data types; — in order to choose the most efficient one according to your needs. For the purposes of this article, we refer to uint8-uint248 and int8-int248 types as “short types”.
With all said, the main reason to use short types in Solidity is to save gas when working with storage due to tightly packed variables, structure fields and array elements. The following will be our observations — only dry facts, tricks and the best life-hacks shared by our best auditors. Let’s get started!
By the way, there are some vacant slots now so if your project needs an audit — feel free to write to us, visit our public reports page here.
Solidity compiler tightly packs short types (if possible) to reduce storage footprint of storage variables, struct fields, array elements;
Short types require more opcodes and gas in all other cases (calldata, memory, stack).
Overflows happen more often;
Solidity 0.8 and SafeMath do not check for overflows during type casts;
Short types behave differently for abi.encodePacked and other abi.encode* calls.
Using short types only to reduce storage footprint;
Local variables, return values, function and event parameters should be uint256 or int256
Converting uint256 values to shorter types right before you write them to storage. Utilize libs like a SafeCast; — they have a pretty good syntax;
When you read short type value from storage, convert it to uint256 immediately
Utilizing storage location when possible: function foo(MyStruct storage ms, uint32[] storage array) internal {…}
Read individual fields or elements if you don’t need the whole structure or array: uint256 value = uint256(ms.field) + uint256(array[i]);
Solidity ABI encoder puts every value into a separate slot, i.e. the size of calldata or returndata remains the same.
The compiler often inserts additional opcodes — it may inflate the size of the contract.
We hope that this article was informative and useful for you! Thank you for reading!
What instruments should we review? What would you be interested in reading about?
Please leave your comments, we will be happy to answer them, and the best answers and questions may be included in the next article!
Thanks to Alexander Seleznev!