Skip to content

Instantly share code, notes, and snippets.

@shingonu
Last active April 19, 2019 10:28
Show Gist options
  • Save shingonu/c51c62fe30a565ddf8247f9a44da5de9 to your computer and use it in GitHub Desktop.
Save shingonu/c51c62fe30a565ddf8247f9a44da5de9 to your computer and use it in GitHub Desktop.

Solidity Types

Value Types

  • bool
  • int / uint
    • int8 to int256 in steps of 8
    • uint8 to uint256 in steps of 8
  • fixed / ufixed
    • fixedMxN / ufixedMxN : M must be divisible by 8 and goes from 8 to 256 bits. N must be between 0 and 80.
  • address
  • bytes1, bytes2, bytes3, ..., bytes32

aliases:

  • int is alias for int256
  • uint is alias for uint256
  • fixed is alias for fixed128x18
  • ufixed is alias for ufixed128x18
  • byte is alias for bytes1

Reference Types

  • arrays
    • bytes: Dynamically-sized byte array.
    • string: Dynamically-sized UTF-8-encoded string.
  • structs

Data location

Complex types, i.e. types which do not always fit into 256 bits have to be handled more carefully than the value-types. Since copying them can be quite expensive, we have to think about whether we want them to be stored in memory (which is not persisting) or storage (where the state variables are held).

Every complex type, i.e. arrays and structs, has an additional annotation, the "data location", about whether it is stored in memory or in storage.

Only complex data types (arrays and structs) default to storage inside functions, while all others default to memory.

  • memory
    • A byte-array
    • Contiguous
    • Starts off zero-size, but can be expanded in 32-byte chunks by simply accessing or storing memory at indices greater than its current size
    • Not persisted across external function calls
  • storage
    • A key/value store where keys and values are both 32 bytes
    • Sparse
    • Persisted
  • calldata
    • Not modifiable.
    • Not persisted.
    • Function arguments are stored.
    • Behaves mostly like memory.

Depending on the context, there is always a default, but it can be overridden by appending either storage or memory to the type. The default for function parameters (including return parameters) is memory, the default for local variables(complex type) is storage and the location is forced to storage for state variables (obviously).

Only complex data types (arrays and structs) default to storage inside functions, while all others default to memory.

Storage is a key/value store where keys and values are both 32 bytes. Memory is a byte-array. Memory starts off zero-size, but can be expanded in 32-byte chunks by simply accessing or storing memory at indices greater than its current size.

  • Forced data location:
    • parameters (not return) of external functions: calldata
    • state variables: storage
  • Default data location:
    • parameters (also return) of functions: memory
    • all other local variables: storage
    • literal array and string: storage(assigned to state variable) / memory(assigned to local variable)

Assignments between storage and memory always create an independent copy.

pragma solidity ^0.4.21;

contract DataLocation {
  int[] myArray = [0, 0]; // ok: storage = storage
  string myString= "Solidity"; // ok: storage = storage

  function DataLocation(uint index, int value){
    myArray[index] = value;
    
    int[] myArray2 = myArray; // ok: storage = storage
    uint16[3] memory myArray3= [1, 2, 9999]; // ok: memory = memory
    uint8[2] myArray4= [1,2]; // error: storage = memory
    
    string myString2= myString; // ok: storage = storage
    string memory myString3= "ABCDE"; // ok: memory = memory
    myString3= "XYZ"; // ok: memory = memory
    string myString4= "Example"; // error: storage = memory
  }
}

Array literals are always statically-sized memory arrays.

Complex local variables are not "held in storage" at all, they are always a reference to some state variable. This is the case in the below example of a complex local variable:

contract Thingy {
    uint256[] stateArray;
    function doStuff() public {

        // By default solidity will create the below as a `storage reference`
        // This is the same as declaring as:
        // uint256[] storage localReference = stateArray;
        // This is essentially a pointer to the state variable's storage location

        uint256[] localReference = stateArray;

        // If it is required that the array only exists locally,
        // one must explicitly state that the variable is to be
        // held in memory

        uint256[] memory memArray = new uint256[](5);
    }
}

Due to the difference in the implementation of storage and memory, local complex variables (declared memory) must have a compile-time fixed size. Storage variables can be of dynamic size

reference

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment