1+ // SPDX-License-Identifier: MIT
2+ pragma solidity ^ 0.8.20 ;
3+
4+ import {Script} from "forge-std/Script.sol " ;
5+ import {console2} from "forge-std/console2.sol " ;
6+ import {IDiamondCut} from "../src/facets/Diamond/IDiamondCut.sol " ; // Adjust to your imports
7+ import {DiamondCutFacet} from "../src/facets/Diamond/DiamondCutFacet.sol " ; // Example; not used directly
8+
9+ contract DeployDiamond is Script {
10+ // Configurable list: Add new facet names here (e.g., "MarketplaceFacet")
11+ string [] public facetNames = [
12+ "DiamondCutFacet " ,
13+ "DiamondLoupeFacet " ,
14+ "OwnershipFacet " ,
15+ "ERC20Facet "
16+ // Add "MarketplaceFacet" here for auto-inclusion
17+ ];
18+
19+ function setUp () public {} // Optional setup
20+
21+ function run () public {
22+ vm.startBroadcast ();
23+
24+ // Step 1: Dynamically deploy facets and build FacetCut[]
25+ IDiamondCut.FacetCut[] memory facetCuts = _buildFacetCuts ();
26+
27+ // Step 2: Your existing Registry registration (pseudo-code; adapt as needed)
28+ // Registry registry = new Registry();
29+ // registry.registerFacets(facetCuts);
30+
31+ // Step 3: Deploy Diamond (adapt to your DiamondDeploy logic)
32+ // address diamond = address(new DiamondDeploy(facetCuts));
33+ // ... (e.g., cut the diamond, transfer ownership)
34+
35+ // Optional: Persist selectors to JSON for reuse
36+ _persistSelectors (facetCuts);
37+
38+ vm.stopBroadcast ();
39+ }
40+
41+ /// @dev Builds FacetCut[] by dynamically fetching selectors and deploying facets.
42+ function _buildFacetCuts () internal returns (IDiamondCut.FacetCut[] memory cuts ) {
43+ uint256 numFacets = facetNames.length ;
44+ cuts = new IDiamondCut.FacetCut [](numFacets);
45+
46+ for (uint256 i = 0 ; i < numFacets; ++ i) {
47+ string memory name = facetNames[i];
48+ string memory contractId = string .concat ("src/facets/ " , name, ".sol: " , name);
49+
50+ // Fetch methodIdentifiers JSON
51+ string [] memory inspectCmd = new string [](5 );
52+ inspectCmd[0 ] = "forge " ;
53+ inspectCmd[1 ] = "inspect " ;
54+ inspectCmd[2 ] = contractId;
55+ inspectCmd[3 ] = "methodIdentifiers " ;
56+ inspectCmd[4 ] = "--json " ;
57+
58+ bytes memory outputBytes = vm.ffi (inspectCmd);
59+ string memory json = string (outputBytes);
60+
61+ // Parse all selector hex strings (e.g., ["0xa9059cbb", ...])
62+ bytes memory selBytes = vm.parseJson (json, ".methodIdentifiers.[] " );
63+ string [] memory selStrings = abi.decode (selBytes, (string []));
64+
65+ // Convert to bytes4[]
66+ bytes4 [] memory selectors = new bytes4 [](selStrings.length );
67+ for (uint256 j = 0 ; j < selStrings.length ; ++ j) {
68+ selectors[j] = bytes4 (vm.parseBytes32 (selStrings[j]));
69+ }
70+
71+ // Fetch bytecode JSON for deployment
72+ string [] memory bytecodeCmd = new string [](5 );
73+ bytecodeCmd[0 ] = "forge " ;
74+ bytecodeCmd[1 ] = "inspect " ;
75+ bytecodeCmd[2 ] = contractId;
76+ bytecodeCmd[3 ] = "bytecode " ;
77+ bytecodeCmd[4 ] = "--json " ;
78+
79+ bytes memory bytecodeOutputBytes = vm.ffi (bytecodeCmd);
80+ string memory bytecodeJson = string (bytecodeOutputBytes);
81+
82+ // Parse bytecode hex string (e.g., "0x6080604052...")
83+ string memory bytecodeStr = abi.decode (vm.parseJson (bytecodeJson, ".bytecode " ), (string ));
84+ bytes memory bytecode = vm.parseBytes (bytecodeStr); // Handles full hex
85+
86+ // Deploy facet
87+ address facetAddr = _deployCode (bytecode);
88+
89+ // Build cut (Add action; adjust if Replace/Remove needed)
90+ cuts[i] = IDiamondCut.FacetCut ({
91+ facetAddress: facetAddr,
92+ action: IDiamondCut.FacetCutAction.Add,
93+ functionSelectors: selectors
94+ });
95+
96+ console2.log ("Deployed %s at %s with %d selectors " , name, facetAddr, selectors.length );
97+ }
98+ }
99+
100+ /// @dev Deploys raw creation bytecode (assumes no constructor args).
101+ function _deployCode (bytes memory code ) internal returns (address addr ) {
102+ assembly {
103+ addr := create (0 , add (code, 0x20 ), mload (code))
104+ if iszero (extcodesize (addr)) {
105+ revert (0 , 0 )
106+ }
107+ }
108+ }
109+
110+ /// @dev Optional: Persist all selectors to JSON (e.g., for tests or reuse).
111+ function _persistSelectors (IDiamondCut.FacetCut[] memory cuts ) internal {
112+ string memory root = vm.projectRoot ();
113+ string memory filePath = string .concat (root, "/facet-selectors.json " );
114+
115+ // Manual JSON build (simple; use forge-std/StdJson.sol for complex structs)
116+ string memory jsonContent = '{"facets": [ ' ;
117+ for (uint256 i = 0 ; i < cuts.length ; ++ i) {
118+ string memory name = facetNames[i]; // Map back via index
119+ jsonContent = string .concat (jsonContent, '{"name":" ' , name, '","selectors":[ ' );
120+ for (uint256 j = 0 ; j < cuts[i].functionSelectors.length ; ++ j) {
121+ // Convert bytes4 back to hex string for JSON
122+ bytes memory selHex = new bytes (10 ); // "0x" + 8 hex chars
123+ selHex[0 ] = bytes1 (hex "30 " ); // '0'
124+ selHex[1 ] = bytes1 (hex "78 " ); // 'x'
125+ // ... (assembly or loop to append hex; simplified here)
126+ // Full impl: Use toHexString from forge-std/Test.sol
127+ jsonContent = string .concat (jsonContent, '"0x ' , _toHexString (cuts[i].functionSelectors[j]), '" ' );
128+ if (j < cuts[i].functionSelectors.length - 1 ) jsonContent = string .concat (jsonContent, ", " );
129+ }
130+ jsonContent = string .concat (jsonContent, ']}} ' );
131+ if (i < cuts.length - 1 ) jsonContent = string .concat (jsonContent, ", " );
132+ }
133+ jsonContent = string .concat (jsonContent, ']} ' );
134+
135+ vm.writeFile (filePath, jsonContent);
136+ console2.log ("Persisted selectors to %s " , filePath);
137+ }
138+
139+ // Helper: bytes4 to hex string (adapt from forge-std/Test.sol)
140+ function _toHexString (bytes4 value ) internal pure returns (string memory ) {
141+ bytes memory str = new bytes (10 );
142+ str[0 ] = "0 " ;
143+ str[1 ] = "x " ;
144+ for (uint256 i = 0 ; i < 4 ; ++ i) {
145+ uint8 _byte = uint8 (uint32 (value) >> (8 * (3 - i)));
146+ str[2 + i * 2 ] = _toHexDigit (_byte >> 4 );
147+ str[3 + i * 2 ] = _toHexDigit (_byte & 0x0f );
148+ }
149+ return string (str);
150+ }
151+
152+ function _toHexDigit (uint8 digit ) internal pure returns (bytes1 ) {
153+ if (digit < 10 ) return bytes1 (char (uint8 (48 + digit)));
154+ return bytes1 (char (uint8 (97 + digit - 10 )));
155+ }
156+
157+ function char (uint8 b ) internal pure returns (bytes1 ) {
158+ return bytes1 (b);
159+ }
160+ }
0 commit comments