Skip to content

Commit 5d41eb1

Browse files
committed
Added DiamondLoupeFacet
1 parent a871299 commit 5d41eb1

File tree

2 files changed

+160
-5
lines changed

2 files changed

+160
-5
lines changed

src/diamond/DiamondLoupeFacet.sol

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
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+
}

src/diamond/LibDiamond.sol

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,21 @@ library LibDiamond {
2525
}
2626

2727
/// @custom:storage-location erc8042:compose.diamond
28-
struct Storage {
28+
struct DiamondStorage {
2929
mapping(bytes4 functionSelector => FacetAndPosition) facetAndPosition;
3030
// Array of all function selectors that can be called in the diamond
3131
bytes4[] selectors;
3232
}
3333

34-
function getStorage() internal pure returns (Storage storage s) {
34+
function getStorage() internal pure returns (DiamondStorage storage s) {
3535
bytes32 position = DIAMOND_STORAGE_POSITION;
3636
assembly {
3737
s.slot := position
3838
}
3939
}
4040

4141
function addFunctions(address _facet, bytes4[] calldata _functionSelectors) internal {
42-
Storage storage s = getStorage();
42+
DiamondStorage storage s = getStorage();
4343
if (_facet.code.length == 0) {
4444
revert NoBytecodeAtAddress(_facet, "LibDiamond: Add facet has no code");
4545
}
@@ -58,7 +58,7 @@ library LibDiamond {
5858
}
5959

6060
function replaceFunctions(address _facet, bytes4[] calldata _functionSelectors) internal {
61-
Storage storage s = getStorage();
61+
DiamondStorage storage s = getStorage();
6262
if (_facet.code.length == 0) {
6363
revert NoBytecodeAtAddress(_facet, "LibDiamond: Replace facet has no code");
6464
}
@@ -81,7 +81,7 @@ library LibDiamond {
8181
}
8282

8383
function removeFunctions(address _facet, bytes4[] calldata _functionSelectors) internal {
84-
Storage storage s = getStorage();
84+
DiamondStorage storage s = getStorage();
8585
uint256 selectorCount = s.selectors.length;
8686
if (_facet != address(0)) {
8787
revert RemoveFacetAddressMustBeZeroAddress(_facet);

0 commit comments

Comments
 (0)