Skip to main content

Diamond Upgrade Facet

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

Key Features
  • 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.

Storage

State Variables

PropertyTypeDescription
DIAMOND_STORAGE_POSITIONbytes32Diamond storage slot position in the proxy (Value: keccak256("erc8153.diamond"))
OWNER_STORAGE_POSITIONbytes32Owner storage slot position in the proxy (Value: keccak256("erc173.owner"))

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:
1
Add Facets
Attach new facet contracts and register their function selectors.
2
Replace Facets
Swap existing selectors to point to updated facet implementations.
3
Remove Facets
Unregister selectors that are no longer needed in the diamond.

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 wallet. This facet is configure to use the unique owner, use the Upgrade Module to wrap around your own access control logic.
  • Always verify facet logic contracts are immutable and trusted before using it inside a diamond.
  • 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: this function mutates the diamond’s selector routing and facet list.

Although this facet protected by Owner checks, it can optionally execute an unrestricted delegatecall after facet updates. Allowing changes to the diamond storage.

That being said, make sure to provide verified and trusted contract addresses to avoid any unwanted changes or vulnerabilities

Last updated:

Newsletter

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

No spam. Unsubscribe anytime.