A diamond implementation implements EIP-2535 Diamonds. These are diamond reference implementations.
Diamonds enable you to build efficient, powerful, flexible, modular contract systems.
Every diamond implementation implements the following:
- diamondCut function Standard function used to add/replace/remove functions on a diamond.
- Loupe functions Four standard functions used to show what functions and facets a diamond has.
There are three diamond reference/example implementations that have different benefits and disadvantages in terms of code complexity and gas costs. Here is a breakdown of the differences between the three implementations. The ratings (high, medium, low) are in relation to each other.
| Implementation | diamondCut complexity |
diamondCut gas cost |
loupe complexity |
loupe gas cost |
|---|---|---|---|---|
| diamond-1 | low | medium | medium | high |
| diamond-2 | high | low | high | high |
| diamond-3 | medium | high | low | low |
It is possible to choose one implementation and then in the future upgrade the diamond to switch to a different implementation.
All three implementations pass the same tests.
diamond-1 and diamond-2 use less gas to add/replace/remove functions.
diamond-3 uses less gas to call the diamond loupe functions.
diamond-1 and diamond-2 are implemented the same way except that diamond-2 is gas optimized. To understand how diamond-2 is implemented look at diamond-1 first.
Links to diamond reference implementation repositories:
- Has an
bytes4[] selectorsarray that stores the function selectors of a diamond. - Has a
mapping(bytes4 => FacetAddressAndSelectorPosition) facetAddressAndSelectorPositionmapping that maps each function selector to its facet address and its position in theselectorsarray.
It's facets, facetFunctionSelectors, facetAddresses loupe functions should not be called in on-chain transactions because their gas cost is too high. These functions should be called by off-chain software.
The facetAddress loupe function has a low fixed gas cost in all implementations and can be called in on-chain transactions.
diamond-2 is implemented the same way as diamond-1 except that the selectors array is implemented as a mapping of 32-byte storage slots and uses various gas-optimizations to reduce storage reads and writes.
This implementation is gas-optimized for adding/replacing/removing functions on a diamond.
It's facets, facetFunctionSelectors, facetAddresses loupe functions should not be called in on-chain transactions because their gas cost is too high. These functions should be called by off-chain software.
The facetAddress loupe function has a low gas cost in all implementations and can be called in on-chain transactions.
-
Has an
address[] facetAddressesarray that stores the facet addresses of a diamond. -
Has a
mapping(address => FacetFunctionSelectors) facetFunctionSelectorsmapping that maps each facet address to its array of function selectors and its position in thefacetAddressesarray. -
Has a
mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPositionmapping that maps each function selector to its facet address and its position in thefacetFunctionSelectors[facetAddress].functionSelectorsarray.
The standard loupe functions facets, facetFunctionSelectors, facetAddresses CAN be called in on-chain transactions. Note that if a diamond has a great many functions and/or facets these functions may still cause an out-of-gas error.
The facetAddress loupe function has a low fixed gas cost in all implementations and can be called in on-chain transactions.