create-fhevm-example 1.4.6 → 1.4.7
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/dist/scripts/commands/doctor.js +72 -1
- package/dist/scripts/commands/generate-config.js +13 -2
- package/dist/scripts/shared/config.js +70 -70
- package/dist/scripts/shared/utils.d.ts.map +1 -1
- package/dist/scripts/shared/utils.js +3 -2
- package/package.json +1 -1
- package/test/concepts/FHEAntiPatterns.ts +0 -112
- /package/contracts/concepts/{FHEAccessControl.sol → core/FHEAccessControl.sol} +0 -0
- /package/contracts/concepts/{FHEHandles.sol → core/FHEHandles.sol} +0 -0
- /package/contracts/concepts/{FHEInputProof.sol → core/FHEInputProof.sol} +0 -0
- /package/test/concepts/{FHEAccessControl.ts → core/FHEAccessControl.ts} +0 -0
- /package/test/concepts/{FHEHandles.ts → core/FHEHandles.ts} +0 -0
- /package/test/concepts/{FHEInputProof.ts → core/FHEInputProof.ts} +0 -0
|
@@ -127,12 +127,83 @@ async function checkConfigIntegrity() {
|
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
+
async function checkSubmoduleStatus() {
|
|
131
|
+
const SUBMODULE_PATH = "fhevm-hardhat-template";
|
|
132
|
+
const SUBMODULE_URL = "https://github.com/zama-ai/fhevm-hardhat-template";
|
|
133
|
+
try {
|
|
134
|
+
// 1. Get local commit hash
|
|
135
|
+
const localStatus = (0, child_process_1.execSync)(`git submodule status ${SUBMODULE_PATH}`, {
|
|
136
|
+
stdio: "pipe",
|
|
137
|
+
encoding: "utf-8",
|
|
138
|
+
}).trim();
|
|
139
|
+
// git submodule status output: " 3e01a81bfca5f0857cba55a099e98863efc79bcb fhevm-hardhat-template (v0.2.0-2-g3e01a81)"
|
|
140
|
+
const localHash = localStatus.split(" ").filter((s) => s.length > 0)[0];
|
|
141
|
+
if (!localHash || localHash.length < 40) {
|
|
142
|
+
return {
|
|
143
|
+
name: "Submodule status",
|
|
144
|
+
status: "fail",
|
|
145
|
+
message: "Not initialized",
|
|
146
|
+
details: [
|
|
147
|
+
`Run ${picocolors_1.default.bold("git submodule update --init")} to initialize.`,
|
|
148
|
+
],
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
// 2. Get remote commit hash
|
|
152
|
+
// We use a timeout to not hang doctor script if internet is slow/down
|
|
153
|
+
const remoteInfo = (0, child_process_1.execSync)(`git ls-remote ${SUBMODULE_URL} HEAD`, {
|
|
154
|
+
stdio: "pipe",
|
|
155
|
+
encoding: "utf-8",
|
|
156
|
+
timeout: 5000, // 5 seconds timeout
|
|
157
|
+
}).trim();
|
|
158
|
+
const remoteHash = remoteInfo.split("\t")[0];
|
|
159
|
+
if (!remoteHash || remoteHash.length < 40) {
|
|
160
|
+
return {
|
|
161
|
+
name: "Submodule status",
|
|
162
|
+
status: "warn",
|
|
163
|
+
message: "Connection error",
|
|
164
|
+
details: ["Could not fetch remote status from GitHub."],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (localHash === remoteHash) {
|
|
168
|
+
return {
|
|
169
|
+
name: "Submodule status",
|
|
170
|
+
status: "success",
|
|
171
|
+
message: "Up to date",
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
return {
|
|
176
|
+
name: "Submodule status",
|
|
177
|
+
status: "warn",
|
|
178
|
+
message: "Update available",
|
|
179
|
+
details: [
|
|
180
|
+
`Local: ${picocolors_1.default.dim(localHash.slice(0, 7))}`,
|
|
181
|
+
`Remote: ${picocolors_1.default.dim(remoteHash.slice(0, 7))}`,
|
|
182
|
+
`Run ${picocolors_1.default.bold("git submodule update --remote --merge")} to update.`,
|
|
183
|
+
],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch (e) {
|
|
188
|
+
return {
|
|
189
|
+
name: "Submodule status",
|
|
190
|
+
status: "warn",
|
|
191
|
+
message: "Check skipped",
|
|
192
|
+
details: ["Git error or no internet connection."],
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
130
196
|
// =============================================================================
|
|
131
197
|
// Main
|
|
132
198
|
// =============================================================================
|
|
133
199
|
async function main() {
|
|
134
200
|
p.intro(picocolors_1.default.cyan("🩺 FHEVM Doctor"));
|
|
135
|
-
const checks = [
|
|
201
|
+
const checks = [
|
|
202
|
+
checkNodeVersion(),
|
|
203
|
+
checkGit(),
|
|
204
|
+
checkConfigIntegrity(),
|
|
205
|
+
checkSubmoduleStatus(),
|
|
206
|
+
];
|
|
136
207
|
const results = await Promise.all(checks);
|
|
137
208
|
let hasFailure = false;
|
|
138
209
|
for (const result of results) {
|
|
@@ -191,7 +191,18 @@ function generateCategoriesConfig(contracts) {
|
|
|
191
191
|
}
|
|
192
192
|
categoryMap[contract.category].push(contract);
|
|
193
193
|
}
|
|
194
|
-
const
|
|
194
|
+
const sortedEntries = Object.entries(categoryMap).sort(([catA], [catB]) => {
|
|
195
|
+
const idxA = utils_1.CATEGORY_ORDER.indexOf(catA);
|
|
196
|
+
const idxB = utils_1.CATEGORY_ORDER.indexOf(catB);
|
|
197
|
+
if (idxA !== -1 && idxB !== -1)
|
|
198
|
+
return idxA - idxB;
|
|
199
|
+
if (idxA !== -1)
|
|
200
|
+
return -1;
|
|
201
|
+
if (idxB !== -1)
|
|
202
|
+
return 1;
|
|
203
|
+
return catA.localeCompare(catB);
|
|
204
|
+
});
|
|
205
|
+
const categoryEntries = sortedEntries.map(([category, items]) => {
|
|
195
206
|
const categoryKey = category
|
|
196
207
|
.toLowerCase()
|
|
197
208
|
.replace(/\s+/g, "")
|
|
@@ -203,7 +214,7 @@ function generateCategoriesConfig(contracts) {
|
|
|
203
214
|
}`)
|
|
204
215
|
.join(",\n");
|
|
205
216
|
return ` ${categoryKey}: {
|
|
206
|
-
name: "${category}
|
|
217
|
+
name: "${category}",
|
|
207
218
|
contracts: [
|
|
208
219
|
${contracts}
|
|
209
220
|
],
|
|
@@ -144,30 +144,6 @@ exports.EXAMPLES = {
|
|
|
144
144
|
docsOutput: "docs/basic/fhe-operations/fhe-if-then-else.md",
|
|
145
145
|
title: "FHE If Then Else"
|
|
146
146
|
},
|
|
147
|
-
"fhe-access-control": {
|
|
148
|
-
contract: "contracts/concepts/FHEAccessControl.sol",
|
|
149
|
-
test: "test/concepts/FHEAccessControl.ts",
|
|
150
|
-
description: "Master class for FHE permission patterns and access control. Explains the three permission types: allow() for permanent access, allowThis() for contract operations, and allowTransient() for temporary cross-contract calls. Includes correct and incorrect usage examples to prevent common decryption failures.",
|
|
151
|
-
category: "Concepts",
|
|
152
|
-
docsOutput: "docs/concepts/fhe-access-control.md",
|
|
153
|
-
title: "FHE Access Control"
|
|
154
|
-
},
|
|
155
|
-
"fhe-handles": {
|
|
156
|
-
contract: "contracts/concepts/FHEHandles.sol",
|
|
157
|
-
test: "test/concepts/FHEHandles.ts",
|
|
158
|
-
description: "Deep dive into FHE handles: what they are and how they work. Explains that handles are uint256 pointers to encrypted data, demonstrates three creation methods (fromExternal, asEuint, operations), and emphasizes immutability - every operation creates a NEW handle. Includes gas cost comparisons for different operations.",
|
|
159
|
-
category: "Concepts",
|
|
160
|
-
docsOutput: "docs/concepts/fhe-handles.md",
|
|
161
|
-
title: "FHE Handles"
|
|
162
|
-
},
|
|
163
|
-
"fhe-input-proof": {
|
|
164
|
-
contract: "contracts/concepts/FHEInputProof.sol",
|
|
165
|
-
test: "test/concepts/FHEInputProof.ts",
|
|
166
|
-
description: "Input proof validation and batching strategies in FHEVM. Explains why proofs are essential (prevent garbage data, wrong types, and replay attacks) and demonstrates the gas-efficient batching pattern where one proof validates multiple encrypted inputs, saving ~50k gas per additional value.",
|
|
167
|
-
category: "Concepts",
|
|
168
|
-
docsOutput: "docs/concepts/fhe-input-proof.md",
|
|
169
|
-
title: "FHE Input Proof"
|
|
170
|
-
},
|
|
171
147
|
"control-flow": {
|
|
172
148
|
contract: "contracts/concepts/antipatterns/ControlFlow.sol",
|
|
173
149
|
test: "test/concepts/antipatterns/ControlFlow.ts",
|
|
@@ -192,6 +168,30 @@ exports.EXAMPLES = {
|
|
|
192
168
|
docsOutput: "docs/concepts/antipatterns/permissions.md",
|
|
193
169
|
title: "Permissions"
|
|
194
170
|
},
|
|
171
|
+
"fhe-access-control": {
|
|
172
|
+
contract: "contracts/concepts/core/FHEAccessControl.sol",
|
|
173
|
+
test: "test/concepts/core/FHEAccessControl.ts",
|
|
174
|
+
description: "Master class for FHE permission patterns and access control. Explains the three permission types: allow() for permanent access, allowThis() for contract operations, and allowTransient() for temporary cross-contract calls. Includes correct and incorrect usage examples to prevent common decryption failures.",
|
|
175
|
+
category: "Concepts - Core",
|
|
176
|
+
docsOutput: "docs/concepts/core/fhe-access-control.md",
|
|
177
|
+
title: "FHE Access Control"
|
|
178
|
+
},
|
|
179
|
+
"fhe-handles": {
|
|
180
|
+
contract: "contracts/concepts/core/FHEHandles.sol",
|
|
181
|
+
test: "test/concepts/core/FHEHandles.ts",
|
|
182
|
+
description: "Deep dive into FHE handles: what they are and how they work. Explains that handles are uint256 pointers to encrypted data, demonstrates three creation methods (fromExternal, asEuint, operations), and emphasizes immutability - every operation creates a NEW handle. Includes gas cost comparisons for different operations.",
|
|
183
|
+
category: "Concepts - Core",
|
|
184
|
+
docsOutput: "docs/concepts/core/fhe-handles.md",
|
|
185
|
+
title: "FHE Handles"
|
|
186
|
+
},
|
|
187
|
+
"fhe-input-proof": {
|
|
188
|
+
contract: "contracts/concepts/core/FHEInputProof.sol",
|
|
189
|
+
test: "test/concepts/core/FHEInputProof.ts",
|
|
190
|
+
description: "Input proof validation and batching strategies in FHEVM. Explains why proofs are essential (prevent garbage data, wrong types, and replay attacks) and demonstrates the gas-efficient batching pattern where one proof validates multiple encrypted inputs, saving ~50k gas per additional value.",
|
|
191
|
+
category: "Concepts - Core",
|
|
192
|
+
docsOutput: "docs/concepts/core/fhe-input-proof.md",
|
|
193
|
+
title: "FHE Input Proof"
|
|
194
|
+
},
|
|
195
195
|
"encrypted-lottery": {
|
|
196
196
|
contract: "contracts/gaming/EncryptedLottery.sol",
|
|
197
197
|
test: "test/gaming/EncryptedLottery.ts",
|
|
@@ -293,33 +293,25 @@ exports.EXAMPLES = {
|
|
|
293
293
|
// Category Configurations
|
|
294
294
|
// =============================================================================
|
|
295
295
|
exports.CATEGORIES = {
|
|
296
|
-
|
|
297
|
-
name: "
|
|
296
|
+
basicencryption: {
|
|
297
|
+
name: "Basic - Encryption",
|
|
298
298
|
contracts: [
|
|
299
299
|
{
|
|
300
|
-
sol: "contracts/
|
|
301
|
-
test: "test/
|
|
302
|
-
},
|
|
303
|
-
{
|
|
304
|
-
sol: "contracts/advanced/EncryptedEscrow.sol",
|
|
305
|
-
test: "test/advanced/EncryptedEscrow.ts",
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
sol: "contracts/advanced/HiddenVoting.sol",
|
|
309
|
-
test: "test/advanced/HiddenVoting.ts",
|
|
300
|
+
sol: "contracts/basic/encryption/EncryptMultipleValues.sol",
|
|
301
|
+
test: "test/basic/encryption/EncryptMultipleValues.ts",
|
|
310
302
|
},
|
|
311
303
|
{
|
|
312
|
-
sol: "contracts/
|
|
313
|
-
test: "test/
|
|
304
|
+
sol: "contracts/basic/encryption/EncryptSingleValue.sol",
|
|
305
|
+
test: "test/basic/encryption/EncryptSingleValue.ts",
|
|
314
306
|
},
|
|
315
307
|
{
|
|
316
|
-
sol: "contracts/
|
|
317
|
-
test: "test/
|
|
308
|
+
sol: "contracts/basic/encryption/FHECounter.sol",
|
|
309
|
+
test: "test/basic/encryption/FHECounter.ts",
|
|
318
310
|
}
|
|
319
311
|
],
|
|
320
312
|
},
|
|
321
313
|
basicdecryption: {
|
|
322
|
-
name: "Basic - Decryption
|
|
314
|
+
name: "Basic - Decryption",
|
|
323
315
|
contracts: [
|
|
324
316
|
{
|
|
325
317
|
sol: "contracts/basic/decryption/PublicDecryptMultipleValues.sol",
|
|
@@ -339,25 +331,8 @@ exports.CATEGORIES = {
|
|
|
339
331
|
}
|
|
340
332
|
],
|
|
341
333
|
},
|
|
342
|
-
basicencryption: {
|
|
343
|
-
name: "Basic - Encryption Examples",
|
|
344
|
-
contracts: [
|
|
345
|
-
{
|
|
346
|
-
sol: "contracts/basic/encryption/EncryptMultipleValues.sol",
|
|
347
|
-
test: "test/basic/encryption/EncryptMultipleValues.ts",
|
|
348
|
-
},
|
|
349
|
-
{
|
|
350
|
-
sol: "contracts/basic/encryption/EncryptSingleValue.sol",
|
|
351
|
-
test: "test/basic/encryption/EncryptSingleValue.ts",
|
|
352
|
-
},
|
|
353
|
-
{
|
|
354
|
-
sol: "contracts/basic/encryption/FHECounter.sol",
|
|
355
|
-
test: "test/basic/encryption/FHECounter.ts",
|
|
356
|
-
}
|
|
357
|
-
],
|
|
358
|
-
},
|
|
359
334
|
basicfheoperations: {
|
|
360
|
-
name: "Basic - FHE Operations
|
|
335
|
+
name: "Basic - FHE Operations",
|
|
361
336
|
contracts: [
|
|
362
337
|
{
|
|
363
338
|
sol: "contracts/basic/fhe-operations/FHEAdd.sol",
|
|
@@ -377,25 +352,25 @@ exports.CATEGORIES = {
|
|
|
377
352
|
}
|
|
378
353
|
],
|
|
379
354
|
},
|
|
380
|
-
|
|
381
|
-
name: "Concepts
|
|
355
|
+
conceptscore: {
|
|
356
|
+
name: "Concepts - Core",
|
|
382
357
|
contracts: [
|
|
383
358
|
{
|
|
384
|
-
sol: "contracts/concepts/FHEAccessControl.sol",
|
|
385
|
-
test: "test/concepts/FHEAccessControl.ts",
|
|
359
|
+
sol: "contracts/concepts/core/FHEAccessControl.sol",
|
|
360
|
+
test: "test/concepts/core/FHEAccessControl.ts",
|
|
386
361
|
},
|
|
387
362
|
{
|
|
388
|
-
sol: "contracts/concepts/FHEHandles.sol",
|
|
389
|
-
test: "test/concepts/FHEHandles.ts",
|
|
363
|
+
sol: "contracts/concepts/core/FHEHandles.sol",
|
|
364
|
+
test: "test/concepts/core/FHEHandles.ts",
|
|
390
365
|
},
|
|
391
366
|
{
|
|
392
|
-
sol: "contracts/concepts/FHEInputProof.sol",
|
|
393
|
-
test: "test/concepts/FHEInputProof.ts",
|
|
367
|
+
sol: "contracts/concepts/core/FHEInputProof.sol",
|
|
368
|
+
test: "test/concepts/core/FHEInputProof.ts",
|
|
394
369
|
}
|
|
395
370
|
],
|
|
396
371
|
},
|
|
397
372
|
conceptsantipatterns: {
|
|
398
|
-
name: "Concepts - Antipatterns
|
|
373
|
+
name: "Concepts - Antipatterns",
|
|
399
374
|
contracts: [
|
|
400
375
|
{
|
|
401
376
|
sol: "contracts/concepts/antipatterns/ControlFlow.sol",
|
|
@@ -412,7 +387,7 @@ exports.CATEGORIES = {
|
|
|
412
387
|
],
|
|
413
388
|
},
|
|
414
389
|
gaming: {
|
|
415
|
-
name: "Gaming
|
|
390
|
+
name: "Gaming",
|
|
416
391
|
contracts: [
|
|
417
392
|
{
|
|
418
393
|
sol: "contracts/gaming/EncryptedLottery.sol",
|
|
@@ -428,8 +403,33 @@ exports.CATEGORIES = {
|
|
|
428
403
|
}
|
|
429
404
|
],
|
|
430
405
|
},
|
|
406
|
+
advanced: {
|
|
407
|
+
name: "Advanced",
|
|
408
|
+
contracts: [
|
|
409
|
+
{
|
|
410
|
+
sol: "contracts/advanced/BlindAuction.sol",
|
|
411
|
+
test: "test/advanced/BlindAuction.ts",
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
sol: "contracts/advanced/EncryptedEscrow.sol",
|
|
415
|
+
test: "test/advanced/EncryptedEscrow.ts",
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
sol: "contracts/advanced/HiddenVoting.sol",
|
|
419
|
+
test: "test/advanced/HiddenVoting.ts",
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
sol: "contracts/advanced/PrivateKYC.sol",
|
|
423
|
+
test: "test/advanced/PrivateKYC.ts",
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
sol: "contracts/advanced/PrivatePayroll.sol",
|
|
427
|
+
test: "test/advanced/PrivatePayroll.ts",
|
|
428
|
+
}
|
|
429
|
+
],
|
|
430
|
+
},
|
|
431
431
|
openzeppelin: {
|
|
432
|
-
name: "Openzeppelin
|
|
432
|
+
name: "Openzeppelin",
|
|
433
433
|
contracts: [
|
|
434
434
|
{
|
|
435
435
|
sol: "contracts/openzeppelin/ERC7984.sol",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../scripts/shared/utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEhD,eAAO,MAAM,aAAa,iBAAO,CAAC;AAElC,qDAAqD;AACrD,eAAO,MAAM,iBAAiB,2BAA2B,CAAC;AAE1D,gDAAgD;AAChD,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,mDAAmD;AACnD,eAAO,MAAM,YAAY,UAQxB,CAAC;AAEF,wFAAwF;AACxF,eAAO,MAAM,iBAAiB,2QAyB7B,CAAC;AAEF,4CAA4C;AAC5C,eAAO,MAAM,kBAAkB;;;;;;;;;CAS9B,CAAC;AAEF,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../scripts/shared/utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEhD,eAAO,MAAM,aAAa,iBAAO,CAAC;AAElC,qDAAqD;AACrD,eAAO,MAAM,iBAAiB,2BAA2B,CAAC;AAE1D,gDAAgD;AAChD,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,mDAAmD;AACnD,eAAO,MAAM,YAAY,UAQxB,CAAC;AAEF,wFAAwF;AACxF,eAAO,MAAM,iBAAiB,2QAyB7B,CAAC;AAEF,4CAA4C;AAC5C,eAAO,MAAM,kBAAkB;;;;;;;;;CAS9B,CAAC;AAEF,eAAO,MAAM,cAAc,UAS1B,CAAC;AAEF,eAAO,MAAM,kBAAkB,yPAS9B,CAAC;AAEF,eAAO,MAAM,cAAc;;;4BAGD,MAAM;6BACL,MAAM;uBACZ,MAAM;;;;CAI1B,CAAC;AAMF,eAAO,MAAM,GAAG;mBACC,MAAM;iBACR,MAAM;gBACP,MAAM;eACP,MAAM;mBACF,MAAM;CACtB,CAAC;AAEF;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,SAAI,GAAG,KAAK,CAI/D;AAMD,sDAAsD;AACtD,wBAAgB,UAAU,IAAI,MAAM,CAUnC;AAED,uCAAuC;AACvC,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,oEAAoE;AACpE,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,WAAW,GAAE,MAAM,EAAiB,GACnC,IAAI,CAoBN;AAMD,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAKhE;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAK7D;AAED,wBAAgB,eAAe,CAAC,qBAAqB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAqB5E;AAMD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIlD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAInD;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAIhE"}
|
|
@@ -116,10 +116,11 @@ exports.CATEGORY_ORDER = [
|
|
|
116
116
|
"Basic - Encryption",
|
|
117
117
|
"Basic - Decryption",
|
|
118
118
|
"Basic - FHE Operations",
|
|
119
|
-
"Concepts",
|
|
119
|
+
"Concepts - Core",
|
|
120
|
+
"Concepts - Antipatterns",
|
|
120
121
|
"Gaming",
|
|
121
|
-
"Openzeppelin",
|
|
122
122
|
"Advanced",
|
|
123
|
+
"Openzeppelin",
|
|
123
124
|
];
|
|
124
125
|
exports.TEST_TYPES_CONTENT = `import type { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
|
|
125
126
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-fhevm-example",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.7",
|
|
4
4
|
"description": "Create FHEVM example projects with a single command - A comprehensive toolkit for building privacy-preserving smart contracts",
|
|
5
5
|
"bin": {
|
|
6
6
|
"create-fhevm-example": "./dist/scripts/index.js"
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
|
|
2
|
-
import { expect } from "chai";
|
|
3
|
-
import { ethers } from "hardhat";
|
|
4
|
-
import * as hre from "hardhat";
|
|
5
|
-
|
|
6
|
-
import { FHEAntiPatterns, FHEAntiPatterns__factory } from "../types";
|
|
7
|
-
import type { Signers } from "./types";
|
|
8
|
-
|
|
9
|
-
async function deployFixture() {
|
|
10
|
-
const factory = (await ethers.getContractFactory(
|
|
11
|
-
"FHEAntiPatterns"
|
|
12
|
-
)) as FHEAntiPatterns__factory;
|
|
13
|
-
const contract = (await factory.deploy()) as FHEAntiPatterns;
|
|
14
|
-
const contractAddress = await contract.getAddress();
|
|
15
|
-
return { contract, contractAddress };
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @notice Tests for FHE anti-patterns
|
|
20
|
-
* Demonstrates correct patterns for common FHE mistakes
|
|
21
|
-
*/
|
|
22
|
-
describe("FHEAntiPatterns", function () {
|
|
23
|
-
let contract: FHEAntiPatterns;
|
|
24
|
-
let contractAddress: string;
|
|
25
|
-
let signers: Signers;
|
|
26
|
-
|
|
27
|
-
before(async function () {
|
|
28
|
-
if (!hre.fhevm.isMock) {
|
|
29
|
-
console.warn(`This hardhat test suite cannot run on Sepolia Testnet`);
|
|
30
|
-
this.skip();
|
|
31
|
-
}
|
|
32
|
-
const ethSigners: HardhatEthersSigner[] = await ethers.getSigners();
|
|
33
|
-
signers = { owner: ethSigners[0], alice: ethSigners[1] };
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
beforeEach(async function () {
|
|
37
|
-
const deployment = await deployFixture();
|
|
38
|
-
contractAddress = deployment.contractAddress;
|
|
39
|
-
contract = deployment.contract;
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
describe("Initialization", function () {
|
|
43
|
-
it("should initialize with encrypted balance and threshold", async function () {
|
|
44
|
-
const fhevm = hre.fhevm;
|
|
45
|
-
const balance = 100;
|
|
46
|
-
const threshold = 50;
|
|
47
|
-
|
|
48
|
-
const input = await fhevm
|
|
49
|
-
.createEncryptedInput(contractAddress, signers.alice.address)
|
|
50
|
-
.add32(balance)
|
|
51
|
-
.add32(threshold)
|
|
52
|
-
.encrypt();
|
|
53
|
-
|
|
54
|
-
await contract
|
|
55
|
-
.connect(signers.alice)
|
|
56
|
-
.initialize(input.handles[0], input.handles[1], input.inputProof);
|
|
57
|
-
|
|
58
|
-
// Contract should now have encrypted values
|
|
59
|
-
// We can't directly verify values without decryption, but tx should succeed
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe("Correct Conditional Pattern", function () {
|
|
64
|
-
it("should handle conditional logic with FHE.select", async function () {
|
|
65
|
-
const fhevm = hre.fhevm;
|
|
66
|
-
|
|
67
|
-
// Initialize with balance=100, threshold=50
|
|
68
|
-
const input = await fhevm
|
|
69
|
-
.createEncryptedInput(contractAddress, signers.alice.address)
|
|
70
|
-
.add32(100) // balance
|
|
71
|
-
.add32(50) // threshold
|
|
72
|
-
.encrypt();
|
|
73
|
-
|
|
74
|
-
await contract
|
|
75
|
-
.connect(signers.alice)
|
|
76
|
-
.initialize(input.handles[0], input.handles[1], input.inputProof);
|
|
77
|
-
|
|
78
|
-
// Execute correct conditional - should not revert
|
|
79
|
-
await expect(contract.connect(signers.alice).correctConditional()).to.not
|
|
80
|
-
.be.reverted;
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
describe("Correct Computation Pattern", function () {
|
|
85
|
-
it("should compute with proper permission grants", async function () {
|
|
86
|
-
const fhevm = hre.fhevm;
|
|
87
|
-
|
|
88
|
-
const input = await fhevm
|
|
89
|
-
.createEncryptedInput(contractAddress, signers.alice.address)
|
|
90
|
-
.add32(50) // balance
|
|
91
|
-
.add32(25) // threshold
|
|
92
|
-
.encrypt();
|
|
93
|
-
|
|
94
|
-
await contract
|
|
95
|
-
.connect(signers.alice)
|
|
96
|
-
.initialize(input.handles[0], input.handles[1], input.inputProof);
|
|
97
|
-
|
|
98
|
-
// correctCompute grants proper permissions
|
|
99
|
-
await expect(contract.connect(signers.alice).correctCompute()).to.not.be
|
|
100
|
-
.reverted;
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
describe("Rules Reference", function () {
|
|
105
|
-
it("should return the key rules summary", async function () {
|
|
106
|
-
const rules = await contract.getRules();
|
|
107
|
-
expect(rules).to.include("FHE.select");
|
|
108
|
-
expect(rules).to.include("FHE.allowThis");
|
|
109
|
-
expect(rules).to.include("require/revert");
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|