7

So I learned very early in my Solidity reading that we should be smart about memory allocation, specifically regarding the proper usage of uint variables. This means properly assigning uint8, uint16, uint32, uint64, uint256 based on the size of the values, so that variables could fit into 32 byte groupings.

However, in every reputable contract I look at, I see none of these practices being employed. They're all using uint256 variables to assign very small values of 20 or 200 or 10000. These variables are constants, and will never be changed. So what is the point of using uint256 for such small values? Why not use uint8 and uint16 for them to save space?

I'd chalk this up to bad code, but I see it everywhere in the largest and most reputable ERC721 contracts. Is there something I'm missing?

1
  • 1
    EVM storage and stack slots are of site 32 bytes. You would only lose small amount of gas by casting to uintX.
    – k06a
    Commented Oct 26, 2021 at 18:52

2 Answers 2

5

Edited Answer

The reason people like using uint256 for most calculation is that OpenZeppelin has a SafeMath library for uint256 that prevent number overflow for sol version < 0.8.

Additional casting will cost gas, so it's more efficient to keep number as uint256, and do math calculation all in uint256, instead of reading a shorter bit number and cast it to uint256.

Storage cost optimization you can do

The compiler automatically pack smaller numbers into a 256 bit size storage slot according to the rules here. If you have multiple variables that don't require full 256 bits, you can define them in order to benefit from this batch read or store. After Berlin hardfork, accessing the same storage slot twice in the same tx is cheaper than 2 different slots, so you can save quite some gas by designing our memory layout for sure.

Using struct

I think a relatively neat way to manage memory layout is by using struct, because each struct will start from a new storage slots, so it's easier to manage what can be batch into a single SSTORE or SLOAD, you can also design different struct to suit your business logic better.

A good example can be found with Ribbon finance's code base here. This can save a lot of gas when u wish to write a bunch of variables in the function call

3
  • 2
    It is not necessary to use struct nor optimizer to benefit from storage packing. docs.soliditylang.org/en/v0.8.9/internals/… Commented Oct 25, 2021 at 14:32
  • interesting, I didn't know that. Do you know by any chance would it automatically optimize SSTORE? if I update the 2 variables one after another, would it be packed into 1 SSTORE? Commented Oct 25, 2021 at 15:00
  • Yes, please see that link as for layout. For batching SSTORE this is unspecified in documentation, but I have seen it in the wild. Commented Oct 26, 2021 at 4:15
1

A problem with "short" uint/int type is that they aren't natively supported by the EVM so the compiler generates longer bytecode to operate them.

Also compatibility with libraries and EIP. Many libraries, like OpenZeppelin, are written for uint256, also most EIP only use other types when explicitly needed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.