Skip to main content

Diamond Upgrade Module

Module providing the internal functions to extend the diamond's upgrade functionality by adding, replacing, or removing facets.

Key Features
  • 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 DiamondMetadata for tagged upgrades and associated data.
Module Usage

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

PropertyTypeDescription
DIAMOND_STORAGE_POSITIONbytes32Diamond storage slot position for this module (Value: keccak256("erc8153.diamond"))

Diamond Storage

Definition
/** storage-location: erc8042:erc8153.diamond */
struct DiamondStorage {
mapping(bytes4 functionSelector => FacetNode) facetNodes;
FacetList facetList;
}

struct FacetList {
bytes4 headFacetNodeId;
bytes4 tailFacetNodeId;
uint32 facetCount;
uint32 selectorCount;
}

struct FacetNode {
address facet;
bytes4 prevFacetNodeId;
bytes4 nextFacetNodeId;
}

FacetReplacement

This struct is used to replace old facets with new facets.

Definition
struct FacetReplacement {
address oldFacet;
address newFacet;
}

Functions

getDiamondStorage

Returns a pointer to the module's diamond storage layout.

function getDiamondStorage() pure returns (DiamondStorage storage s);

upgradeDiamond

Upgrade the diamond by adding, replacing, and/or removing facets.

Execution order is always:

  1. addFacets(_addFacets)
  2. replaceFacets(_replaceFacets)
  3. removeFacets(_removeFacets)

Then, if _delegate != address(0), the diamond performs a delegatecall to _delegate with _delegateCalldata and emits DiamondDelegateCall.

function upgradeDiamond(
address[] calldata _addFacets,
FacetReplacement[] calldata _replaceFacets,
address[] calldata _removeFacets,
address _delegate,
bytes calldata _delegateCalldata,
bytes32 _tag,
bytes calldata _metadata
) external;

Parameters:

PropertyTypeDescription
_addFacetsaddress[]Facet addresses to add
_replaceFacetsFacetReplacement[](oldFacet, newFacet) pairs to replace
_removeFacetsaddress[]Facet addresses to remove
_delegateaddressOptional contract to delegatecall (address(0) to skip)
_delegateCalldatabytesOptional calldata to execute on _delegate
_tagbytes32Optional arbitrary metadata, such as release version
_metadatabytesOptional arbitrary metadata

addFacets

Adds new facets to a diamond and maps their exported selectors to the facet address.

function addFacets(address[] calldata _facets);

Parameters:

PropertyTypeDescription
_facetsaddress[]Facet addresses to add. Each facet must implement exportSelectors().

removeFacets

Removes facets from a diamond and unregisters the selectors they previously exported.

function removeFacets(address[] calldata _facets);

Parameters:

PropertyTypeDescription
_facetsaddress[]Facet addresses to remove.

replaceFacets

Replaces facets in a diamond using (oldFacet, newFacet) pairs.

function replaceFacets(FacetReplacement[] calldata _replaceFacets);

Parameters:

PropertyTypeDescription
_replaceFacetsFacetReplacement[](oldFacet, newFacet) pairs to replace old with new.

at

Reads the selector at index from a packed bytes array of selectors.

function at(bytes memory selectors, uint256 index) pure returns (bytes4 selector);

Parameters:

PropertyTypeDescription
selectorsbytesPacked array of 4-byte function selectors (length must be a multiple of 4).
indexuint256Zero-based index of the selector to read.

importSelectors

Discovers the function selectors exposed by _facet by calling its exportSelectors() implementation.

function importSelectors(address _facet) view returns (bytes memory selectors);

Parameters:

PropertyTypeDescription
_facetaddressFacet 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.

Was this helpful?
Last updated:

Newsletter

Get notified about releases, feature announcements, and technical deep-dives on building smart contracts with Compose.

No spam. Unsubscribe anytime.