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.
Files changed (48) hide show
  1. package/README.md +3 -4
  2. package/contracts/advanced/BlindAuction.sol +5 -1
  3. package/contracts/advanced/EncryptedEscrow.sol +5 -1
  4. package/contracts/advanced/HiddenVoting.sol +5 -1
  5. package/contracts/advanced/PrivateKYC.sol +6 -1
  6. package/contracts/advanced/PrivatePayroll.sol +5 -1
  7. package/contracts/basic/decryption/PublicDecryptMultipleValues.sol +11 -5
  8. package/contracts/basic/decryption/PublicDecryptSingleValue.sol +11 -5
  9. package/contracts/basic/decryption/UserDecryptMultipleValues.sol +5 -1
  10. package/contracts/basic/decryption/UserDecryptSingleValue.sol +5 -1
  11. package/contracts/basic/encryption/EncryptMultipleValues.sol +4 -1
  12. package/contracts/basic/encryption/EncryptSingleValue.sol +6 -2
  13. package/contracts/basic/encryption/FHECounter.sol +4 -1
  14. package/contracts/basic/fhe-operations/FHEAdd.sol +5 -1
  15. package/contracts/basic/fhe-operations/FHEArithmetic.sol +5 -1
  16. package/contracts/basic/fhe-operations/FHEComparison.sol +5 -1
  17. package/contracts/basic/fhe-operations/FHEIfThenElse.sol +5 -1
  18. package/contracts/concepts/FHEAccessControl.sol +8 -3
  19. package/contracts/concepts/FHEHandles.sol +5 -1
  20. package/contracts/concepts/FHEInputProof.sol +5 -1
  21. package/contracts/concepts/antipatterns/ControlFlow.sol +160 -0
  22. package/contracts/concepts/antipatterns/OperationsGasNoise.sol +190 -0
  23. package/contracts/concepts/antipatterns/Permissions.sol +254 -0
  24. package/contracts/gaming/EncryptedLottery.sol +5 -1
  25. package/contracts/gaming/EncryptedPoker.sol +5 -1
  26. package/contracts/gaming/RockPaperScissors.sol +5 -1
  27. package/contracts/openzeppelin/ERC7984.sol +6 -1
  28. package/contracts/openzeppelin/ERC7984ERC20Wrapper.sol +5 -1
  29. package/contracts/openzeppelin/SwapERC7984ToERC20.sol +5 -1
  30. package/contracts/openzeppelin/SwapERC7984ToERC7984.sol +5 -1
  31. package/contracts/openzeppelin/VestingWallet.sol +6 -1
  32. package/dist/scripts/commands/add-mode.d.ts.map +1 -1
  33. package/dist/scripts/commands/add-mode.js +10 -21
  34. package/dist/scripts/commands/doctor.js +4 -1
  35. package/dist/scripts/commands/generate-config.js +18 -3
  36. package/dist/scripts/commands/generate-docs.js +4 -1
  37. package/dist/scripts/index.js +43 -24
  38. package/dist/scripts/shared/builders.d.ts.map +1 -1
  39. package/dist/scripts/shared/builders.js +8 -14
  40. package/dist/scripts/shared/config.d.ts.map +1 -1
  41. package/dist/scripts/shared/config.js +119 -84
  42. package/dist/scripts/shared/utils.js +2 -2
  43. package/package.json +1 -1
  44. package/test/concepts/FHEAntiPatterns.ts +2 -1
  45. package/test/concepts/antipatterns/ControlFlow.ts +125 -0
  46. package/test/concepts/antipatterns/OperationsGasNoise.ts +187 -0
  47. package/test/concepts/antipatterns/Permissions.ts +327 -0
  48. 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
- const noticeRegex = /\/\*\*[\s\S]*?@notice\s+([^\n*]+)[\s\S]*?\*\/[\s\S]*?contract\s+\w+/;
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
- return match && match[1] ? match[1].trim() : null;
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}"
@@ -187,5 +187,8 @@ async function main() {
187
187
  }
188
188
  const isMainModule = process.argv[1]?.includes("generate-docs");
189
189
  if (isMainModule) {
190
- main().catch(console.error);
190
+ main().catch((err) => {
191
+ console.error(err);
192
+ process.exit(1);
193
+ });
191
194
  }
@@ -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 (p.isCancel(mode)) {
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 (p.isCancel(category)) {
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 (p.isCancel(example)) {
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 (p.isCancel(category)) {
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 (p.isCancel(projectName)) {
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 (p.isCancel(outputDir)) {
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 (p.isCancel(shouldInstall)) {
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
- else if (arg === "-h") {
222
- parsed["help"] = true;
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;AA6DH;;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,CAuEf"}
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, fails silently)
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
- // Git init is optional
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
- for (const depPath of allContractDeps) {
213
- const depFullPath = path.join(rootDir, depPath);
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+QlD,CAAC;AAMF,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAoJrD,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"}
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"}