ERC-8042 Diamond Storage

Final · Other · created 2025-10-11

Standardizes the diamond storage pattern that uses the keccak256 hash of a human-readable string as the storage location of a struct. It lets a single contract manage its storage divided into separate regions.

Why it is needed

Smart contracts keep their data in a space called storage. In a proxy structure, where several functional modules share one storage, different modules can write to the same location and overwrite each other's data. In March 2020 the Solidity compiler made it possible to place a struct at an arbitrary location in storage, which gave rise to the Diamond Storage pattern, where a readable string is hashed to determine the location, and it became widely used through ERC-2535 Diamonds. However, this approach was not a formal standard for a long time. ERC-7201, published in 2023, standardized a pattern with the same purpose but proposed a different calculation formula from the Diamond Storage already in use. As a result, existing implementations in production did not receive the protection of a standard. This standard codifies the simple, proven original method so that new projects can use it, and it also recognizes past implementations as compliant.

In depth

Storage location formula and identifier rules

A Diamond Storage identifier is a string containing only printable ASCII characters (0x20 through 0x7E). The storage location of the struct is determined by the keccak256 hash of this identifier. That is, the formula is the single expression erc8042(id) = keccak256(id), which in Solidity is written as keccak256(id). Unlike the multi-step formula of ERC-7201, the location comes from a single hash, so the calculation is simple and easy to verify.

Four recommendations

First, using a Solidity string literal is recommended. This is because the compiler enforces that only printable ASCII is allowed, and it is recommended to place it as a compile-time constant such as bytes32 constant STORAGE_POSITION = keccak256("myproject.erc721.registry"). Hexadecimal (\xNN) and Unicode (\uNNNN) escapes must not be used. Second, the identifier must be a unique, human-readable and meaningful string. A random string such as "car.fish.piano.run" is not a meaningful string. Third, Unicode literals (unicode"...") can contain invisible or non-ASCII characters, so they must not be used. Fourth, the space character (0x20) is discouraged because it can conflict with tools such as NatSpec tags.

NatSpec tag erc8042

It uses the @custom:storage-location <FORMULA_ID>:<NAMESPACE_ID> tag scheme defined by ERC-7201 as it is. The formula identifier erc8042 is defined as erc8042(id: string literal) = keccak256(id), and the annotation takes the form @custom:storage-location erc8042:<NAMESPACE_ID>. For example, @custom:storage-location erc8042:myproject.erc721.registry marks Diamond Storage rooted at the hash location of the identifier "myproject.erc721.registry". Tools can read this tag to determine where data lives in storage.

Comparison with ERC-7201

The namespace id in ERC-7201 only needs to contain no spaces and has no other restrictions, so random bytes can also be used. Its location formula is keccak256(abi.encode(uint256(keccak256(bytes(namespace id))) - 1)) & ~bytes32(uint256(0xff)). The first part avoids overlapping with the inputs that Solidity types produce with keccak256, which allows arbitrary byte ids, and the last part aligns the final location to a multiple of 256, leaving room for future gas optimizations. ERC-8042, by contrast, restricts the identifier to printable ASCII and derives the location with a single keccak256. If you want to use machine-generated random ids, ERC-7201 fits; if you want readable identifiers enforced as ASCII and a simple calculation, ERC-8042 fits.

Access pattern of the reference implementation

The reference implementation ERC721Registry sets keccak256("myproject.erc721.registry") as the constant STORAGE_POSITION and holds an erc721Contracts array and a registryLimit value in the ERC721RegistryStorage struct. When the getStorage() function runs s.slot := position in inline assembly to connect the struct to that slot, later functions read and write with ordinary struct access syntax such as getStorage().registryLimit. This pattern started out for proxies, but it can be used to organize storage and data access in any smart contract.

Backward compatibility

The Diamond Storage described by this standard has been used in practice for five years. This standard recognizes and standardizes all past uses of Diamond Storage that conform to the specification. Existing projects therefore become standard-compliant without changing their code.

Things to watch out for

Original ERC · ← ERCs