Diamond Upgrade Module
Module providing the internal functions to extend the diamond's upgrade functionality by adding, replacing, or removing facets.
- Manages facet lifecycle (add, replace, remove) within a diamond.
- Updates selector routing so subsequent calls dispatch to the new facet.
- Emits events for all facet changes and any post-upgrade
delegatecall. - Emits
DiamondMetadatafor tagged upgrades and associated data.
Import this module into facets or shared setup code. Its functions are internal (including Solidity file-level helpers). Use them through your facet’s external entrypoints.
Storage follows the diamond slot layout in this file; any code using the same STORAGE_POSITION or related positions reads and writes shared state.
See Facets & Modules for more information.
Storage
State Variables
| Property | Type | Description |
|---|---|---|
DIAMOND_STORAGE_POSITION | bytes32 | Diamond storage slot position for this module (Value: keccak256("erc8153.diamond")) |
Diamond Storage
FacetReplacement
This struct is used to replace old facets with new facets.
Functions
getDiamondStorage
Returns a pointer to the module's diamond storage layout.
upgradeDiamond
Upgrade the diamond by adding, replacing, and/or removing facets.
Execution order is always:
addFacets(_addFacets)replaceFacets(_replaceFacets)removeFacets(_removeFacets)
Then, if _delegate != address(0), the diamond performs a delegatecall to _delegate with _delegateCalldata and emits DiamondDelegateCall.
Parameters:
| Property | Type | Description |
|---|---|---|
_addFacets | address[] | Facet addresses to add |
_replaceFacets | FacetReplacement[] | (oldFacet, newFacet) pairs to replace |
_removeFacets | address[] | Facet addresses to remove |
_delegate | address | Optional contract to delegatecall (address(0) to skip) |
_delegateCalldata | bytes | Optional calldata to execute on _delegate |
_tag | bytes32 | Optional arbitrary metadata, such as release version |
_metadata | bytes | Optional arbitrary metadata |
addFacets
Adds new facets to a diamond and maps their exported selectors to the facet address.
Parameters:
| Property | Type | Description |
|---|---|---|
_facets | address[] | Facet addresses to add. Each facet must implement exportSelectors(). |
removeFacets
Removes facets from a diamond and unregisters the selectors they previously exported.
Parameters:
| Property | Type | Description |
|---|---|---|
_facets | address[] | Facet addresses to remove. |
replaceFacets
Replaces facets in a diamond using (oldFacet, newFacet) pairs.
Parameters:
| Property | Type | Description |
|---|---|---|
_replaceFacets | FacetReplacement[] | (oldFacet, newFacet) pairs to replace old with new. |
at
Reads the selector at index from a packed bytes array of selectors.
Parameters:
| Property | Type | Description |
|---|---|---|
selectors | bytes | Packed array of 4-byte function selectors (length must be a multiple of 4). |
index | uint256 | Zero-based index of the selector to read. |
importSelectors
Discovers the function selectors exposed by _facet by calling its exportSelectors() implementation.
Parameters:
| Property | Type | Description |
|---|---|---|
_facet | address | Facet contract address that implements exportSelectors(). |
Events
Errors
Best Practices
- Diamonds upgrades should be considered as a critical operation and always ensure proper access control.
- Verify facet logic contracts are immutable and trusted before adding or replacing.
- Ensure each facet’s
exportSelectors()returns a valid packed selector list in deterministic order. - Carefully audit any optional post-upgrade
delegatecall(contract + calldata).
Security Considerations
The upgradeDiamond function is critical: this function mutates the diamond’s selector routing and facet linked list.
It optionally executes an unrestricted delegatecall after facet updates. Make sure _delegate and _delegateCalldata are fully trusted before calling it.
Shared Storage
This module writes to the diamond’s shared storage at DIAMOND_STORAGE_POSITION (conceptually keccak256("erc8153.diamond")).
Changes made through upgradeDiamond, addFacets, replaceFacets, and removeFacets are immediately visible to the diamond and all facet that access the shared storage.