How Diamond Storage Works
Tags: ethereum, smartcontracts
Published: 2020-09-18 12:57:03

Diamond storage is a contract storage strategy that is used in [proxy contract patterns](https://blog.openzeppelin.com/proxy-patterns/) and [diamonds](https://eips.ethereum.org/EIPS/eip-2535).

It greatly simplifies organizing and using state variables in proxy contracts and diamonds.

Diamond storage relies on Solidity structs that contain sets of state variables that are easy to read and write.

A struct can be defined with state variables and then used in a particular position in contract storage.  The position can be determined by a hash of a unique string. The string acts like a namespace for the struct. For example a diamond storage string for a struct could be `com.mycompany.projectx.mystruct`.  That will look familiar to you if you have used programming languages that use namespaces.

Namespaces are used in some programming languages to package data and code together as separate reusable units. Diamond storage packages sets of state variables as separate, reusable data units in contract storage. 

Let's look at a simple example of diamond storage: 

```solidity
library MyStructStorage {
  bytes32 constant MYSTRUCT_POSITION = 
    keccak256("com.mycompany.projectx.mystruct");

  struct MyStruct {
    uint var1;
    bytes var2;
    mapping (address => uint) var3;
  }

  function myStructStorage()
    internal 
    pure 
    returns (MyStruct storage mystruct) 
  {
    bytes32 position = MYSTRUCT_POSITION;
    assembly {
      mystruct.slot := position
    }
  }
}
```

The diamond storage defined above can be used like this:

```solidity
function myFunction()
  external
{
  MyStructStorage.MyStruct storage mystruct =
    MyStructStorage.myStructStorage();

  mystruct.var1 = 10;
  uint var3 = mystruct.var3[address(this)];

  // etc
}
```

Instead of using a hash of a string other schemes can be used to create random positions in contract storage. Here is a scheme that could be used:
```Solidity
bytes32 constant MYSTRUCT_POSITION = 
    keccak256(abi.encodePacked(
      ERC1155.interfaceId, 
      ERC1155.name, 
      address(this)
    ));
```

Diamond storage is easy to use correctly, but like any tool it needs to be used correctly.

Don't make these mistakes:

1. Do not use the same namespace string for different structs.  Because the two structs will overwrite each other in storage.

1. Don't do the following: Deploy a contract that uses a particular struct. Then upgrade your contract with a modified version of the struct that is stored at the same location and with new state variables added or state variables removed in the beginning or middle. This is similar to storing two different structs at the same location in contract storage. However it is safe to add new state variables to the end of structs that are already being used.

1. Don't put structs directly in structs unless you are sure you won't want to add new state variables to the end of the inner structs.  You won't be able to add new state variables to inner structs in upgrades.  But you can put structs in mappings, and still extend the structs in the future. To understand this more read about how state variables are laid out in contract storage here: https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html

These mistakes are easy to avoid by being aware of them and keeping track of what namespaced strings are used. Also a naming convention can be used to give structs unique strings.


Here are some additional references that cover diamond storage:

* [Understanding Diamonds on Ethereum](https://dev.to/mudgen/understanding-diamonds-on-ethereum-1fb)
* [Solidity Libraries Can't Have State Variables -- Oh Yes They Can!](https://dev.to/mudgen/solidity-libraries-can-t-have-state-variables-oh-yes-they-can-3ke9)
* [New Storage Layout For Proxy Contracts and Diamonds](https://medium.com/1milliondevs/new-storage-layout-for-proxy-contracts-and-diamonds-98d01d0eadb)
* [EIP-2535: Diamond Standard](https://eips.ethereum.org/EIPS/eip-2535)

Diamond storage is also called common storage. Smart contract developer [Jules Goddard](https://medium.com/@plaxion) writes about it:

* [Smart Contracts Sharing Common Data](https://medium.com/coinmonks/smart-contracts-sharing-common-data-777310263ac0)
* [Sharing Common Data Using Libraries](https://medium.com/coinmonks/sharing-common-data-using-libraries-6573857d328c)