create-fhevm-example 1.4.4 → 1.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -4
- package/contracts/advanced/BlindAuction.sol +5 -1
- package/contracts/advanced/EncryptedEscrow.sol +5 -1
- package/contracts/advanced/HiddenVoting.sol +5 -1
- package/contracts/advanced/PrivateKYC.sol +6 -1
- package/contracts/advanced/PrivatePayroll.sol +5 -1
- package/contracts/basic/decryption/PublicDecryptMultipleValues.sol +11 -5
- package/contracts/basic/decryption/PublicDecryptSingleValue.sol +11 -5
- package/contracts/basic/decryption/UserDecryptMultipleValues.sol +5 -1
- package/contracts/basic/decryption/UserDecryptSingleValue.sol +5 -1
- package/contracts/basic/encryption/EncryptMultipleValues.sol +4 -1
- package/contracts/basic/encryption/EncryptSingleValue.sol +6 -2
- package/contracts/basic/encryption/FHECounter.sol +4 -1
- package/contracts/basic/fhe-operations/FHEAdd.sol +5 -1
- package/contracts/basic/fhe-operations/FHEArithmetic.sol +5 -1
- package/contracts/basic/fhe-operations/FHEComparison.sol +5 -1
- package/contracts/basic/fhe-operations/FHEIfThenElse.sol +5 -1
- package/contracts/concepts/FHEAccessControl.sol +8 -3
- package/contracts/concepts/FHEHandles.sol +5 -1
- package/contracts/concepts/FHEInputProof.sol +5 -1
- package/contracts/concepts/antipatterns/ControlFlow.sol +160 -0
- package/contracts/concepts/antipatterns/OperationsGasNoise.sol +190 -0
- package/contracts/concepts/antipatterns/Permissions.sol +254 -0
- package/contracts/gaming/EncryptedLottery.sol +5 -1
- package/contracts/gaming/EncryptedPoker.sol +5 -1
- package/contracts/gaming/RockPaperScissors.sol +5 -1
- package/contracts/openzeppelin/ERC7984.sol +6 -1
- package/contracts/openzeppelin/ERC7984ERC20Wrapper.sol +5 -1
- package/contracts/openzeppelin/SwapERC7984ToERC20.sol +5 -1
- package/contracts/openzeppelin/SwapERC7984ToERC7984.sol +5 -1
- package/contracts/openzeppelin/VestingWallet.sol +6 -1
- package/dist/scripts/commands/add-mode.d.ts.map +1 -1
- package/dist/scripts/commands/add-mode.js +10 -21
- package/dist/scripts/commands/doctor.js +4 -1
- package/dist/scripts/commands/generate-config.js +18 -3
- package/dist/scripts/commands/generate-docs.js +4 -1
- package/dist/scripts/index.js +43 -24
- package/dist/scripts/shared/builders.d.ts.map +1 -1
- package/dist/scripts/shared/builders.js +8 -14
- package/dist/scripts/shared/config.d.ts.map +1 -1
- package/dist/scripts/shared/config.js +119 -84
- package/dist/scripts/shared/utils.js +2 -2
- package/package.json +1 -1
- package/test/concepts/FHEAntiPatterns.ts +2 -1
- package/test/concepts/antipatterns/ControlFlow.ts +125 -0
- package/test/concepts/antipatterns/OperationsGasNoise.ts +187 -0
- package/test/concepts/antipatterns/Permissions.ts +327 -0
- package/contracts/concepts/FHEAntiPatterns.sol +0 -296
|
@@ -56,9 +56,24 @@ const OUTPUT_FILE = path.join(ROOT_DIR, "scripts/shared/config.ts");
|
|
|
56
56
|
// =============================================================================
|
|
57
57
|
function extractNotice(contractPath) {
|
|
58
58
|
const content = fs.readFileSync(contractPath, "utf-8");
|
|
59
|
-
|
|
59
|
+
// Match @notice and capture everything until @dev or end of comment block
|
|
60
|
+
const noticeRegex = /\/\*\*[\s\S]*?@notice\s+([\s\S]*?)(?:@dev|@param|\*\/)/;
|
|
60
61
|
const match = content.match(noticeRegex);
|
|
61
|
-
|
|
62
|
+
if (!match || !match[1]) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
// Clean up the extracted text:
|
|
66
|
+
// 1. Remove leading asterisks and whitespace from each line
|
|
67
|
+
// 2. Join lines with space
|
|
68
|
+
// 3. Collapse multiple spaces
|
|
69
|
+
const cleaned = match[1]
|
|
70
|
+
.split("\n")
|
|
71
|
+
.map((line) => line.replace(/^\s*\*\s?/, "").trim())
|
|
72
|
+
.filter((line) => line.length > 0)
|
|
73
|
+
.join(" ")
|
|
74
|
+
.replace(/\s+/g, " ")
|
|
75
|
+
.trim();
|
|
76
|
+
return cleaned || null;
|
|
62
77
|
}
|
|
63
78
|
function readExistingConfig() {
|
|
64
79
|
try {
|
|
@@ -160,7 +175,7 @@ function generateExamplesConfig(contracts) {
|
|
|
160
175
|
contract: "${c.contractPath}",
|
|
161
176
|
test: "${c.testPath}",${npmDepsField}${depsField}
|
|
162
177
|
description:
|
|
163
|
-
"${c.description}",
|
|
178
|
+
"${c.description.replace(/"/g, '\\"')}",
|
|
164
179
|
category: "${c.category}",
|
|
165
180
|
docsOutput: "${c.docsOutput}",
|
|
166
181
|
title: "${c.title}"
|
package/dist/scripts/index.js
CHANGED
|
@@ -56,6 +56,17 @@ const builders_1 = require("./shared/builders");
|
|
|
56
56
|
const ui_1 = require("./shared/ui");
|
|
57
57
|
const add_mode_1 = require("./commands/add-mode");
|
|
58
58
|
const generate_docs_1 = require("./commands/generate-docs");
|
|
59
|
+
// =============================================================================
|
|
60
|
+
// INTERACTIVE MODE
|
|
61
|
+
// =============================================================================
|
|
62
|
+
/** Helper to check if user cancelled and show message */
|
|
63
|
+
function checkCancel(value) {
|
|
64
|
+
if (p.isCancel(value)) {
|
|
65
|
+
p.cancel("Operation cancelled.");
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
59
70
|
/** Prompts user to select mode and returns project configuration */
|
|
60
71
|
async function getProjectConfig() {
|
|
61
72
|
// Build options - docs only available in local dev mode
|
|
@@ -83,22 +94,16 @@ async function getProjectConfig() {
|
|
|
83
94
|
message: "What would you like to create?",
|
|
84
95
|
options,
|
|
85
96
|
});
|
|
86
|
-
if (
|
|
87
|
-
p.cancel("Operation cancelled.");
|
|
97
|
+
if (checkCancel(mode))
|
|
88
98
|
return null;
|
|
89
|
-
}
|
|
90
99
|
let name;
|
|
91
100
|
if (mode === "single") {
|
|
92
101
|
const category = await (0, ui_1.promptSelectCategory)();
|
|
93
|
-
if (
|
|
94
|
-
p.cancel("Operation cancelled.");
|
|
102
|
+
if (checkCancel(category))
|
|
95
103
|
return null;
|
|
96
|
-
}
|
|
97
104
|
const example = await (0, ui_1.promptSelectExampleFromCategory)(category);
|
|
98
|
-
if (
|
|
99
|
-
p.cancel("Operation cancelled.");
|
|
105
|
+
if (checkCancel(example))
|
|
100
106
|
return null;
|
|
101
|
-
}
|
|
102
107
|
name = example;
|
|
103
108
|
}
|
|
104
109
|
else if (mode === "docs") {
|
|
@@ -108,10 +113,8 @@ async function getProjectConfig() {
|
|
|
108
113
|
}
|
|
109
114
|
else {
|
|
110
115
|
const category = await (0, ui_1.promptSelectCategoryProject)();
|
|
111
|
-
if (
|
|
112
|
-
p.cancel("Operation cancelled.");
|
|
116
|
+
if (checkCancel(category))
|
|
113
117
|
return null;
|
|
114
|
-
}
|
|
115
118
|
name = category;
|
|
116
119
|
}
|
|
117
120
|
const projectName = await p.text({
|
|
@@ -119,27 +122,21 @@ async function getProjectConfig() {
|
|
|
119
122
|
placeholder: `my-${name}-project`,
|
|
120
123
|
defaultValue: `my-${name}-project`,
|
|
121
124
|
});
|
|
122
|
-
if (
|
|
123
|
-
p.cancel("Operation cancelled.");
|
|
125
|
+
if (checkCancel(projectName))
|
|
124
126
|
return null;
|
|
125
|
-
}
|
|
126
127
|
const outputDir = await p.text({
|
|
127
128
|
message: "Output directory:",
|
|
128
129
|
placeholder: `./${projectName}`,
|
|
129
130
|
defaultValue: `./${projectName}`,
|
|
130
131
|
});
|
|
131
|
-
if (
|
|
132
|
-
p.cancel("Operation cancelled.");
|
|
132
|
+
if (checkCancel(outputDir))
|
|
133
133
|
return null;
|
|
134
|
-
}
|
|
135
134
|
const shouldInstall = await p.confirm({
|
|
136
135
|
message: "Install dependencies and run tests?",
|
|
137
136
|
initialValue: false,
|
|
138
137
|
});
|
|
139
|
-
if (
|
|
140
|
-
p.cancel("Operation cancelled.");
|
|
138
|
+
if (checkCancel(shouldInstall))
|
|
141
139
|
return null;
|
|
142
|
-
}
|
|
143
140
|
return {
|
|
144
141
|
mode: mode,
|
|
145
142
|
name,
|
|
@@ -205,12 +202,22 @@ async function runInteractiveMode() {
|
|
|
205
202
|
}
|
|
206
203
|
function parseArgs(args) {
|
|
207
204
|
const parsed = {};
|
|
205
|
+
// Short flag mappings
|
|
206
|
+
const shortFlags = {
|
|
207
|
+
"-e": "example",
|
|
208
|
+
"-c": "category",
|
|
209
|
+
"-o": "output",
|
|
210
|
+
"-a": "add",
|
|
211
|
+
"-i": "install",
|
|
212
|
+
"-h": "help",
|
|
213
|
+
};
|
|
208
214
|
for (let i = 0; i < args.length; i++) {
|
|
209
215
|
const arg = args[i];
|
|
216
|
+
// Handle long flags (--example, --category, etc.)
|
|
210
217
|
if (arg.startsWith("--")) {
|
|
211
218
|
const key = arg.slice(2);
|
|
212
219
|
const nextArg = args[i + 1];
|
|
213
|
-
if (nextArg && !nextArg.startsWith("
|
|
220
|
+
if (nextArg && !nextArg.startsWith("-")) {
|
|
214
221
|
parsed[key] = nextArg;
|
|
215
222
|
i++;
|
|
216
223
|
}
|
|
@@ -218,8 +225,20 @@ function parseArgs(args) {
|
|
|
218
225
|
parsed[key] = true;
|
|
219
226
|
}
|
|
220
227
|
}
|
|
221
|
-
|
|
222
|
-
|
|
228
|
+
// Handle short flags (-e, -c, -o, -a, -i, -h)
|
|
229
|
+
else if (arg.startsWith("-") && shortFlags[arg]) {
|
|
230
|
+
const key = shortFlags[arg];
|
|
231
|
+
const nextArg = args[i + 1];
|
|
232
|
+
// Flags that take values: -e, -c, -o
|
|
233
|
+
if (["example", "category", "output"].includes(key) &&
|
|
234
|
+
nextArg &&
|
|
235
|
+
!nextArg.startsWith("-")) {
|
|
236
|
+
parsed[key] = nextArg;
|
|
237
|
+
i++;
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
parsed[key] = true;
|
|
241
|
+
}
|
|
223
242
|
}
|
|
224
243
|
}
|
|
225
244
|
return parsed;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builders.d.ts","sourceRoot":"","sources":["../../../scripts/shared/builders.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"builders.d.ts","sourceRoot":"","sources":["../../../scripts/shared/builders.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiEH;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,IAAI,CAkDN;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,IAAI,CAwEN;AAMD;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,MAAM,EAAE,EACtB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA6Df"}
|
|
@@ -69,7 +69,8 @@ function copyDependencies(dependencies, outputDir) {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
|
-
* Initializes git repository (optional,
|
|
72
|
+
* Initializes git repository (optional, logs warning if skipped)
|
|
73
|
+
* @returns true if git init succeeded, false otherwise
|
|
73
74
|
*/
|
|
74
75
|
function initGitRepo(outputDir) {
|
|
75
76
|
try {
|
|
@@ -77,9 +78,11 @@ function initGitRepo(outputDir) {
|
|
|
77
78
|
cwd: outputDir,
|
|
78
79
|
stdio: "ignore",
|
|
79
80
|
});
|
|
81
|
+
return true;
|
|
80
82
|
}
|
|
81
83
|
catch {
|
|
82
|
-
|
|
84
|
+
utils_1.log.dim(" ⚠️ Git initialization skipped (git not available)");
|
|
85
|
+
return false;
|
|
83
86
|
}
|
|
84
87
|
}
|
|
85
88
|
// =============================================================================
|
|
@@ -208,18 +211,9 @@ async function createLocalTestProject(exampleNames, outputDir) {
|
|
|
208
211
|
Object.assign(allNpmDeps, example.npmDependencies);
|
|
209
212
|
}
|
|
210
213
|
}
|
|
211
|
-
// 3. Copy dependencies
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (fs.existsSync(depFullPath)) {
|
|
215
|
-
const relativePath = depPath.replace(/^contracts\//, "");
|
|
216
|
-
const depDestPath = path.join(outputDir, "contracts", relativePath);
|
|
217
|
-
const depDestDir = path.dirname(depDestPath);
|
|
218
|
-
if (!fs.existsSync(depDestDir)) {
|
|
219
|
-
fs.mkdirSync(depDestDir, { recursive: true });
|
|
220
|
-
}
|
|
221
|
-
fs.copyFileSync(depFullPath, depDestPath);
|
|
222
|
-
}
|
|
214
|
+
// 3. Copy dependencies (reuse helper function)
|
|
215
|
+
if (allContractDeps.size > 0) {
|
|
216
|
+
copyDependencies(Array.from(allContractDeps), outputDir);
|
|
223
217
|
}
|
|
224
218
|
// 4. Finalize project
|
|
225
219
|
(0, generators_1.updateProjectPackageJson)(outputDir, "fhevm-test-project", `Testing ${exampleNames.length} examples`, Object.keys(allNpmDeps).length > 0 ? allNpmDeps : undefined);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../scripts/shared/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,uCAAuC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,SAAS,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD;AAMD,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CA+
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../scripts/shared/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,uCAAuC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,SAAS,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD;AAMD,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CA+SlD,CAAC;AAMF,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAiKrD,CAAC;AAMF;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAElE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAEpE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3D"}
|