Skip to main content

Diamond Module

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

This module provides core internal functions and storage management for diamond proxies.

Key Features
  • Provides functions for diamond proxy operations.
  • Manages diamond storage using a dedicated storage slot ("erc8153.diamond").
  • Supports facet registration and retrieval through internal mechanisms.

Storage

State Variables

PropertyTypeDescriptionDIAMOND_STORAGE_POSITIONbytes32Storage slot position for the diamond. 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;
}

Functions

getDiamondStorage

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

Returns:

PropertyTypeDescriptionsDiamondStorageThe DiamondStorage struct in storage.

diamondFallback

This is the core dispatch path used by the diamond proxy pattern. The fallback function is used to route unmatched calls to the facet registered for the called selector (msg.sig) in diamond storage.

function diamondFallback() ;

Execution Flow:

Execution Context

delegatecall executes facet code in the diamond's context.

State writes happen inside the diamond storage, and msg.sender/msg.value are preserved from the original external call.


addFacets

Registers one or more facets to a diamond. For each facet, selectors are discovered by calling exportSelectors(). Each selector is then mapped to the facet in diamond storage.

Reverts if any selector is already registered on the diamond.

function addFacets(address[] memory _facets) ;

Parameters:

PropertyTypeDescription_facetsaddress[]The facet addresses to add. Each must implement IFacet and return selectors from exportSelectors().

importSelectors

Retrieves the function selectors exposed by a facet by calling its exportSelectors(). Validates the returned ABI-encoded bytes (offset, length, and that the payload length is a multiple of 4) and returns the packed selectors without copying (zero-copy decode).

Used internally by addFacets.
function importSelectors(address _facet) view returns (bytes memory selectors);

Parameters:

PropertyTypeDescription_facetaddressContract address implementing exportSelectors() that returns ABI-encoded bytes of 4-byte function selectors.

Returns:

PropertyTypeDescriptionselectorsbytesPacked 4-byte function selectors (length is a multiple of 4). Same memory layout as returned by exportSelectors(); may point into the staticcall return buffer.

at

Returns the 4-byte function selector at the given index in a packed bytes array of selectors (e.g. from importSelectors or other selector packing).

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

Parameters:

PropertyTypeDescriptionselectorsbytesPacked array of 4-byte function selectors (length must be a multiple of 4).indexuint256Zero-based index of the selector to read (0 = first selector, 1 = second, etc.).

Returns:

PropertyTypeDescriptionselectorbytes4The function selector at the given index.

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

Integration Notes

This module interacts directly with the diamond's shared storage at the DIAMOND_STORAGE_POSITION, which is identified by keccak256("erc8153.diamond"). All functions within this module read from and write to this shared storage.

Changes to the facetList or other storage elements are immediately visible to any facet that accesses the same storage slot.

Last updated:

Newsletter

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

No spam. Unsubscribe anytime.