Skip to main content

Diamond Upgrade Facet

@perfect-abstractions/compose/diamond/DiamondUpgradeFacet.sol

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

Storage​

State Variables​

PropertyTypeDescriptionDIAMOND_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

Events​

Emitted when a facet is added to a diamond.

The function selectors this facet handles can be retrieved by calling IFacet(_facet).exportSelectors()

Signature:
event FacetAdded(address indexed _facet);
Parameters:
PropertyTypeDescription_facetaddressThe address of the facet that handles function calls to the diamond.

Emitted when a facet is removed from a diamond.

The function selectors this facet handles can be retrieved by calling IFacet(_facet).exportSelectors()

Signature:
event FacetRemoved(address indexed _facet);
Parameters:
PropertyTypeDescription_facetaddressThe address of the facet that previously handled function calls to the diamond.

Emitted when an existing facet is replaced with a new facet.

The function selectors handled by these facets can be retrieved by calling:

Signature:
event FacetReplaced(address indexed _oldFacet, address indexed _newFacet);
Parameters:
PropertyTypeDescription_oldFacetaddressThe address of the facet that previously handled function calls to the diamond._newFacetaddressThe address of the facet that now handles function calls to the diamond.

Emitted when a diamond's constructor function or function from a facet makes a delegatecall.

Signature:
event DiamondDelegateCall(address indexed _delegate, bytes _delegateCalldata);
Parameters:
PropertyTypeDescription_delegateaddressThe contract that was delegatecalled._delegateCalldatabytesThe function call, including function selector and any arguments.

Emitted to record information about a diamond. This event records any arbitrary metadata.

The format of _tag and _data are not specified by the standard.

Signature:
event DiamondMetadata(bytes32 indexed _tag, bytes _data);
Parameters:
PropertyTypeDescription_tagbytes32Arbitrary metadata, such as a release version._databytesArbitrary metadata.

Errors​

Best Practices​

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.