Skip to main content

Diamond Upgrade Facet

Orchestrates upgrade functionality, enabling the addition, replacement, and removal of facets.

Key Features
  • Manages facet lifecycle (add, replace, remove) within a diamond.
  • Owner-gated upgrade entrypoint (ERC-173 owner).
  • Optional delegatecall for post-upgrade initialization/state migration.
  • Updates selector routing so subsequent calls dispatch to the new facet.
  • Emits events for all facet changes and delegate calls.

Storage

State Variables

PropertyTypeDescription
OWNER_STORAGE_POSITIONbytes32Diamond storage slot position for this module (Value: keccak256("erc173.owner"))
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;
}

Owner Storage

Definition
/** storage-location: erc8042:erc173.owner */
struct OwnerStorage {
address owner;
}

FacetReplacement

Definition
struct FacetReplacement {
address oldFacet;
address newFacet;
}

Functions

upgradeDiamond

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

Execution order is always: addFacets, replaceFacets, removeFacets

Then, if _delegate != address(0), the diamond performs a delegatecall 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
Facet Requirement

Facets must implement exportSelectors() in order to make their selectors discoverable by diamonds. Only the exported selectors will be added to the diamond.

interface IFacet {
function exportSelectors() external pure returns (bytes memory);
}

See Facet-Based Diamond EIP-8153 for more details.

Events

Errors

Best Practices

  • Ensure all diamond upgrade operations are performed by authorized accounts.
  • 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 (delegate contract + calldata).

Security Considerations

The upgradeDiamond function is critical: it mutates the diamond’s selector routing and facet linked list.

It is protected by Owner checks, and it optionally executes an unrestricted delegatecall after facet updates. Treat _delegate and _delegateCalldata as fully trusted: that code can modify diamond storage and may introduce complex control flow.

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.