Skip to content

Commit ab3ea9a

Browse files
committed
deploy script: tinkering with facet deploy implementation
1 parent c56120e commit ab3ea9a

File tree

5 files changed

+278
-66
lines changed

5 files changed

+278
-66
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ docs/
1212

1313
# Dotenv file
1414
.env
15+
16+
#js
17+
node_modules/

package-lock.json

Lines changed: 122 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "my-foundry-project",
3+
"version": "1.0.0",
4+
"description": "**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**",
5+
"main": "index.js",
6+
"directories": {
7+
"lib": "lib",
8+
"test": "test"
9+
},
10+
"type":"module",
11+
"scripts": {
12+
"test": "echo \"Error: no test specified\" && exit 1"
13+
},
14+
"author": "",
15+
"license": "ISC",
16+
"dependencies": {
17+
"ethers": "^6.15.0"
18+
}
19+
}

script/DeployMain.s.sol

Lines changed: 86 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,28 @@ pragma solidity ^0.8.20;
44
import {Script} from "forge-std/Script.sol";
55
import {console2} from "forge-std/console2.sol";
66
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
87

98
contract DeployDiamond is Script {
109
// Configurable list: Add new facet names here (e.g., "MarketplaceFacet")
1110
string[] public facetNames = [
1211
"DiamondCutFacet",
1312
"DiamondLoupeFacet",
1413
"OwnershipFacet",
15-
"ERC20Facet"
14+
"ERC20Facet",
15+
"ERC2771Recipient"
1616
// Add "MarketplaceFacet" here for auto-inclusion
1717
];
1818

19+
// Parallel list: Subdirectories for each facet (in same order as facetNames)
20+
string[] public subdirs = [
21+
"Diamond",
22+
"Diamond",
23+
"Ownership",
24+
"ERC20",
25+
"ERC2771Recipient"
26+
// Add corresponding subdir for new facets
27+
];
28+
1929
function setUp() public {} // Optional setup
2030

2131
function run() public {
@@ -30,7 +40,8 @@ contract DeployDiamond is Script {
3040

3141
// Step 3: Deploy Diamond (adapt to your DiamondDeploy logic)
3242
// address diamond = address(new DiamondDeploy(facetCuts));
33-
// ... (e.g., cut the diamond, transfer ownership)
43+
// IDiamondCut(address(diamond)).diamondCut(facetCuts, IDiamondCut.DiamondCutFunctionType.Add, ""); // Initial cut
44+
// OwnershipFacet(address(diamond)).transferOwnership(msg.sender); // Example
3445

3546
// Optional: Persist selectors to JSON for reuse
3647
_persistSelectors(facetCuts);
@@ -39,51 +50,19 @@ contract DeployDiamond is Script {
3950
}
4051

4152
/// @dev Builds FacetCut[] by dynamically fetching selectors and deploying facets.
53+
/// Now stack-safe: Loop has minimal locals; heavy work delegated.
4254
function _buildFacetCuts() internal returns (IDiamondCut.FacetCut[] memory cuts) {
4355
uint256 numFacets = facetNames.length;
4456
cuts = new IDiamondCut.FacetCut[](numFacets);
4557

4658
for (uint256 i = 0; i < numFacets; ++i) {
4759
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);
60+
string memory subdir = subdirs[i]; // Fetch corresponding subdir
61+
string memory contractId = string.concat("src/facets/", subdir, "/", name, ".sol:", name);
8162

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
63+
// Delegate to sub-functions to avoid stack bloat
64+
bytes4[] memory selectors = _getSelectors(contractId);
65+
bytes memory bytecode = _getBytecode(contractId);
8766
address facetAddr = _deployCode(bytecode);
8867

8968
// Build cut (Add action; adjust if Replace/Remove needed)
@@ -97,6 +76,55 @@ contract DeployDiamond is Script {
9776
}
9877
}
9978

79+
/// @dev Fetches and parses method selectors via FFI.
80+
function _getSelectors(string memory contractId) internal returns (bytes4[] memory selectors) {
81+
string[] memory inspectCmd = new string[](5);
82+
inspectCmd[0] = "forge";
83+
inspectCmd[1] = "inspect";
84+
inspectCmd[2] = contractId;
85+
inspectCmd[3] = "methodIdentifiers";
86+
inspectCmd[4] = "--json";
87+
88+
bytes memory outputBytes = vm.ffi(inspectCmd);
89+
string memory json = string(outputBytes);
90+
91+
// Parse JSON: Root is { "sig": "sel", ... } → ".*" selects all values as string[] of hex selectors (no "0x")
92+
bytes memory selBytes = vm.parseJson(json, ".*");
93+
string[] memory selStrings = abi.decode(selBytes, (string[]));
94+
95+
// Edge case: No selectors (e.g., abstract contract)
96+
if (selStrings.length == 0) {
97+
selectors = new bytes4[](0);
98+
return selectors;
99+
}
100+
101+
selectors = new bytes4[](selStrings.length);
102+
for (uint256 j = 0; j < selStrings.length; ++j) {
103+
// Prepend "0x" since forge inspect outputs raw hex without prefix
104+
string memory hexWithPrefix = string.concat("0x", selStrings[j]);
105+
console2.log("Parsed selector hex: %s", hexWithPrefix); // Debug: Confirm prepending
106+
// vm.parseBytes32 converts "0x..." hex string to bytes32; cast to bytes4 (first 4 bytes)
107+
selectors[j] = bytes4(vm.parseBytes32(hexWithPrefix));
108+
console2.log("Selector %d: %s", j, hexWithPrefix); // Debug: Log each selector
109+
}
110+
}
111+
112+
/// @dev Fetches bytecode via FFI.
113+
function _getBytecode(string memory contractId) internal returns (bytes memory bytecode) {
114+
string[] memory bytecodeCmd = new string[](5);
115+
bytecodeCmd[0] = "forge";
116+
bytecodeCmd[1] = "inspect";
117+
bytecodeCmd[2] = contractId;
118+
bytecodeCmd[3] = "bytecode";
119+
bytecodeCmd[4] = "--json";
120+
121+
bytes memory outputBytes = vm.ffi(bytecodeCmd);
122+
string memory bytecodeJson = string(outputBytes);
123+
124+
string memory bytecodeStr = abi.decode(vm.parseJson(bytecodeJson, ".bytecode"), (string));
125+
bytecode = vm.parseBytes(bytecodeStr);
126+
}
127+
100128
/// @dev Deploys raw creation bytecode (assumes no constructor args).
101129
function _deployCode(bytes memory code) internal returns (address addr) {
102130
assembly {
@@ -112,22 +140,17 @@ contract DeployDiamond is Script {
112140
string memory root = vm.projectRoot();
113141
string memory filePath = string.concat(root, "/facet-selectors.json");
114142

115-
// Manual JSON build (simple; use forge-std/StdJson.sol for complex structs)
143+
// Build JSON manually (simple array of objects)
116144
string memory jsonContent = '{"facets": [';
117145
for (uint256 i = 0; i < cuts.length; ++i) {
118-
string memory name = facetNames[i]; // Map back via index
146+
string memory name = facetNames[i]; // Map back via index
119147
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, ",");
148+
bytes4[] memory selectors = cuts[i].functionSelectors;
149+
for (uint256 j = 0; j < selectors.length; ++j) {
150+
jsonContent = string.concat(jsonContent, '"', _toHexString(selectors[j]), '"');
151+
if (j < selectors.length - 1) jsonContent = string.concat(jsonContent, ",");
129152
}
130-
jsonContent = string.concat(jsonContent, ']}}');
153+
jsonContent = string.concat(jsonContent, ']}');
131154
if (i < cuts.length - 1) jsonContent = string.concat(jsonContent, ",");
132155
}
133156
jsonContent = string.concat(jsonContent, ']}');
@@ -136,25 +159,22 @@ contract DeployDiamond is Script {
136159
console2.log("Persisted selectors to %s", filePath);
137160
}
138161

139-
// Helper: bytes4 to hex string (adapt from forge-std/Test.sol)
162+
// Helper: bytes4 to hex string (e.g., "0xa9059cbb")
140163
function _toHexString(bytes4 value) internal pure returns (string memory) {
141-
bytes memory str = new bytes(10);
142-
str[0] = "0";
143-
str[1] = "x";
164+
bytes memory str = new bytes(10); // "0x" + 8 hex chars
165+
str[0] = bytes1(uint8(48)); // '0'
166+
str[1] = bytes1(uint8(120)); // 'x'
167+
uint256 temp = uint256(uint32(value));
144168
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);
169+
uint8 byteVal = uint8(temp >> (8 * (3 - i)));
170+
str[2 + i * 2] = _toHexDigit(uint8(byteVal >> 4));
171+
str[3 + i * 2] = _toHexDigit(uint8(byteVal & 0x0f));
148172
}
149173
return string(str);
150174
}
151175

152176
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);
177+
uint8 c = digit < 10 ? uint8(48 + digit) : uint8(97 + digit - 10); // '0'-'9', 'a'-'f'
178+
return bytes1(c);
159179
}
160180
}

0 commit comments

Comments
 (0)