1+ // SPDX-License-Identifier: MIT
2+ pragma solidity >= 0.8.30 ;
3+
4+ // The functions in DiamondLoupeFacet MUST be added to a diamond.
5+ // The EIP-2535 Diamond standard requires these functions.
6+ contract DiamondLoupeFacet {
7+
8+ bytes32 constant DIAMOND_STORAGE_POSITION = keccak256 ("compose.diamond " );
9+
10+ /// @notice Data stored for each function selector
11+ /// @dev Facet address of function selector
12+ /// Position of selector in the 'bytes4[] selectors' array
13+ struct FacetAndPosition {
14+ address facet;
15+ uint16 position;
16+ }
17+
18+ /// @custom:storage-location erc8042:compose.diamond
19+ struct DiamondStorage {
20+ mapping (bytes4 functionSelector = > FacetAndPosition) facetAndPosition;
21+ // Array of all function selectors that can be called in the diamond
22+ bytes4 [] selectors;
23+ }
24+
25+ function getStorage () internal pure returns (DiamondStorage storage s ) {
26+ bytes32 position = DIAMOND_STORAGE_POSITION;
27+ assembly {
28+ s.slot := position
29+ }
30+ }
31+
32+ /// @notice Struct to hold facet address and its function selectors
33+ struct Facet {
34+ address facet;
35+ bytes4 [] functionSelectors;
36+ }
37+
38+ /// @notice Gets all facets and their selectors.
39+ /// @return allFacets Facet
40+ function facets () external view returns (Facet[] memory allFacets ) {
41+ DiamondStorage storage s = getStorage ();
42+ uint256 selectorCount = s.selectors.length ;
43+ // create an array set to the maximum size possible
44+ allFacets = new Facet [](selectorCount);
45+ // create an array for counting the number of selectors for each facet
46+ uint16 [] memory numFacetSelectors = new uint16 [](selectorCount);
47+ // total number of facets
48+ uint256 numFacets;
49+ // loop through function selectors
50+ for (uint256 selectorIndex; selectorIndex < selectorCount; selectorIndex++ ) {
51+ bytes4 selector = s.selectors[selectorIndex];
52+ address facetAddress_ = s.facetAndPosition[selector].facet;
53+ bool continueLoop = false ;
54+ // find the functionSelectors array for selector and add selector to it
55+ for (uint256 facetIndex; facetIndex < numFacets; facetIndex++ ) {
56+ if (allFacets[facetIndex].facet == facetAddress_) {
57+ allFacets[facetIndex].functionSelectors[numFacetSelectors[facetIndex]] = selector;
58+ numFacetSelectors[facetIndex]++ ;
59+ continueLoop = true ;
60+ break ;
61+ }
62+ }
63+ // if functionSelectors array exists for selector then continue loop
64+ if (continueLoop) {
65+ continueLoop = false ;
66+ continue ;
67+ }
68+ // create a new functionSelectors array for selector
69+ allFacets[numFacets].facet = facetAddress_;
70+ allFacets[numFacets].functionSelectors = new bytes4 [](selectorCount);
71+ allFacets[numFacets].functionSelectors[0 ] = selector;
72+ numFacetSelectors[numFacets] = 1 ;
73+ numFacets++ ;
74+ }
75+ for (uint256 facetIndex; facetIndex < numFacets; facetIndex++ ) {
76+ uint256 numSelectors = numFacetSelectors[facetIndex];
77+ bytes4 [] memory selectors = allFacets[facetIndex].functionSelectors;
78+ // setting the number of selectors
79+ assembly ("memory-safe" ) {
80+ mstore (selectors, numSelectors)
81+ }
82+ }
83+ // setting the number of facets
84+ assembly ("memory-safe" ) {
85+ mstore (allFacets, numFacets)
86+ }
87+ }
88+
89+ /// @notice Gets all the function selectors supported by a specific facet.
90+ /// @param _facet The facet address.
91+ /// @return facetSelectors The function selectors associated with a facet address.
92+ function facetFunctionSelectors (address _facet ) external view returns (bytes4 [] memory facetSelectors ) {
93+ DiamondStorage storage s = getStorage ();
94+ uint256 selectorCount = s.selectors.length ;
95+ uint256 numSelectors;
96+ facetSelectors = new bytes4 [](selectorCount);
97+ // loop through function selectors
98+ for (uint256 selectorIndex; selectorIndex < selectorCount; selectorIndex++ ) {
99+ bytes4 selector = s.selectors[selectorIndex];
100+ address facetAddress_ = s.facetAndPosition[selector].facet;
101+ if (_facet == facetAddress_) {
102+ facetSelectors[numSelectors] = selector;
103+ numSelectors++ ;
104+ }
105+ }
106+ // Set the number of selectors in the array
107+ assembly ("memory-safe" ){
108+ mstore (facetSelectors, numSelectors)
109+ }
110+ }
111+
112+ /// @notice Get all the facet addresses used by a diamond.
113+ /// @return allFacets The facet addresses.
114+ function facetAddresses () external view returns (address [] memory allFacets ) {
115+ DiamondStorage storage s = getStorage ();
116+ uint256 selectorCount = s.selectors.length ;
117+ // create an array set to the maximum size possible
118+ allFacets = new address [](selectorCount);
119+ uint256 numFacets;
120+ // loop through function selectors
121+ for (uint256 selectorIndex; selectorIndex < selectorCount; selectorIndex++ ) {
122+ bytes4 selector = s.selectors[selectorIndex];
123+ address facetAddress_ = s.facetAndPosition[selector].facet;
124+ bool continueLoop = false ;
125+ // see if we have collected the address already and break out of loop if we have
126+ for (uint256 facetIndex; facetIndex < numFacets; facetIndex++ ) {
127+ if (facetAddress_ == allFacets[facetIndex]) {
128+ continueLoop = true ;
129+ break ;
130+ }
131+ }
132+ // continue loop if we already have the address
133+ if (continueLoop) {
134+ continueLoop = false ;
135+ continue ;
136+ }
137+ // include address
138+ allFacets[numFacets] = facetAddress_;
139+ numFacets++ ;
140+ }
141+ // Set the number of facet addresses in the array
142+ assembly ("memory-safe" ) {
143+ mstore (allFacets, numFacets)
144+ }
145+ }
146+
147+ /// @notice Gets the facet address that supports the given selector.
148+ /// @dev If facet is not found return address(0).
149+ /// @param _functionSelector The function selector.
150+ /// @return facet The facet address.
151+ function facetAddress (bytes4 _functionSelector ) external view returns (address facet ) {
152+ DiamondStorage storage s = getStorage ();
153+ facet = s.facetAndPosition[_functionSelector].facet;
154+ }
155+ }
0 commit comments