|
| 1 | +// SPDX-License-Identifier: MIT |
| 2 | +pragma solidity >=0.8.30; |
| 3 | + |
| 4 | +contract ComposeDiamond { |
| 5 | + bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("compose.diamond"); |
| 6 | + |
| 7 | + /// @notice Data stored for each function selector. |
| 8 | + /// @dev Facet address of function selector. |
| 9 | + /// Position of selector in the 'bytes4[] selectors' array. |
| 10 | + struct FacetAndPosition { |
| 11 | + address facet; |
| 12 | + uint32 position; |
| 13 | + } |
| 14 | + |
| 15 | + /// @custom:storage-location erc8042:compose.diamond |
| 16 | + struct DiamondStorage { |
| 17 | + mapping(bytes4 functionSelector => FacetAndPosition) facetAndPosition; |
| 18 | + } |
| 19 | + |
| 20 | + function getStorage() internal pure returns (DiamondStorage storage s) { |
| 21 | + bytes32 position = DIAMOND_STORAGE_POSITION; |
| 22 | + assembly { |
| 23 | + s.slot := position |
| 24 | + } |
| 25 | + } |
| 26 | + |
| 27 | + error FunctionNotFound(bytes4 _selector); |
| 28 | + |
| 29 | + // Find facet for function that is called and execute the |
| 30 | + // function if a facet is found and return any value. |
| 31 | + fallback() external payable { |
| 32 | + DiamondStorage storage s = getStorage(); |
| 33 | + // get facet from function selector |
| 34 | + address facet = s.facetAndPosition[msg.sig].facet; |
| 35 | + if (facet == address(0)) { |
| 36 | + revert FunctionNotFound(msg.sig); |
| 37 | + } |
| 38 | + // Execute external function from facet using delegatecall and return any value. |
| 39 | + assembly { |
| 40 | + // copy function selector and any arguments |
| 41 | + calldatacopy(0, 0, calldatasize()) |
| 42 | + // execute function call using the facet |
| 43 | + let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) |
| 44 | + // get any return value |
| 45 | + returndatacopy(0, 0, returndatasize()) |
| 46 | + // return any return value or error back to the caller |
| 47 | + switch result |
| 48 | + case 0 { |
| 49 | + revert(0, returndatasize()) |
| 50 | + } |
| 51 | + default { |
| 52 | + return(0, returndatasize()) |
| 53 | + } |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + receive() external payable {} |
| 58 | +} |
0 commit comments