create-fhevm-example 1.4.5 → 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/README.md +3 -4
- 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/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 +76 -2
- package/dist/scripts/commands/generate-config.js +13 -2
- 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 +96 -67
- package/dist/scripts/shared/utils.d.ts.map +1 -1
- package/dist/scripts/shared/utils.js +5 -4
- package/package.json +1 -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 -300
- package/test/concepts/FHEAntiPatterns.ts +0 -111
- /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
|
@@ -58,7 +58,7 @@ const utils_1 = require("../shared/utils");
|
|
|
58
58
|
function detectHardhatProject(targetDir) {
|
|
59
59
|
const packageJsonPath = path.join(targetDir, "package.json");
|
|
60
60
|
const hardhatConfigTs = path.join(targetDir, "hardhat.config.ts");
|
|
61
|
-
const hardhatConfigJs = path.join(targetDir, "hardhat.config");
|
|
61
|
+
const hardhatConfigJs = path.join(targetDir, "hardhat.config.js");
|
|
62
62
|
if (!fs.existsSync(packageJsonPath)) {
|
|
63
63
|
return false;
|
|
64
64
|
}
|
|
@@ -106,7 +106,7 @@ function updateHardhatConfig(targetDir) {
|
|
|
106
106
|
? configPathJs
|
|
107
107
|
: null;
|
|
108
108
|
if (!actualPath) {
|
|
109
|
-
throw new Error(
|
|
109
|
+
throw new Error(utils_1.ERROR_MESSAGES.CONFIG_NOT_FOUND);
|
|
110
110
|
}
|
|
111
111
|
let content = fs.readFileSync(actualPath, "utf-8");
|
|
112
112
|
if (content.includes("@fhevm/hardhat-plugin")) {
|
|
@@ -139,12 +139,12 @@ function updateHardhatConfig(targetDir) {
|
|
|
139
139
|
function addExampleFiles(exampleName, targetDir) {
|
|
140
140
|
const example = config_1.EXAMPLES[exampleName];
|
|
141
141
|
if (!example) {
|
|
142
|
-
throw new Error(
|
|
142
|
+
throw new Error(utils_1.ERROR_MESSAGES.UNKNOWN_EXAMPLE(exampleName));
|
|
143
143
|
}
|
|
144
144
|
const rootDir = (0, utils_1.getRootDir)();
|
|
145
145
|
const contractName = (0, utils_1.getContractName)(example.contract);
|
|
146
146
|
if (!contractName) {
|
|
147
|
-
throw new Error(
|
|
147
|
+
throw new Error(utils_1.ERROR_MESSAGES.CONTRACT_NAME_FAILED);
|
|
148
148
|
}
|
|
149
149
|
const contractSource = path.join(rootDir, example.contract);
|
|
150
150
|
const testSource = path.join(rootDir, example.test);
|
|
@@ -154,15 +154,9 @@ function addExampleFiles(exampleName, targetDir) {
|
|
|
154
154
|
if (!fs.existsSync(contractsDir)) {
|
|
155
155
|
fs.mkdirSync(contractsDir, { recursive: true });
|
|
156
156
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
p.log.success(`Overwritten: ${contractName}.sol`);
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
fs.copyFileSync(contractSource, contractDest);
|
|
164
|
-
p.log.success(`Added: ${contractName}.sol`);
|
|
165
|
-
}
|
|
157
|
+
const isContractOverwrite = fs.existsSync(contractDest);
|
|
158
|
+
fs.copyFileSync(contractSource, contractDest);
|
|
159
|
+
p.log.success(`${isContractOverwrite ? "Overwritten" : "Added"}: ${contractName}.sol`);
|
|
166
160
|
// Handle test file
|
|
167
161
|
const testFileName = path.basename(example.test);
|
|
168
162
|
const testDest = path.join(targetDir, "test", testFileName);
|
|
@@ -170,14 +164,9 @@ function addExampleFiles(exampleName, targetDir) {
|
|
|
170
164
|
if (!fs.existsSync(testDir)) {
|
|
171
165
|
fs.mkdirSync(testDir, { recursive: true });
|
|
172
166
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
fs.copyFileSync(testSource, testDest);
|
|
179
|
-
p.log.success(`Added: ${testFileName}`);
|
|
180
|
-
}
|
|
167
|
+
const isTestOverwrite = fs.existsSync(testDest);
|
|
168
|
+
fs.copyFileSync(testSource, testDest);
|
|
169
|
+
p.log.success(`${isTestOverwrite ? "Overwritten" : "Added"}: ${testFileName}`);
|
|
181
170
|
// Handle contract dependencies
|
|
182
171
|
if (example.dependencies) {
|
|
183
172
|
p.log.message("");
|
|
@@ -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) {
|
|
@@ -162,4 +233,7 @@ async function main() {
|
|
|
162
233
|
p.outro(picocolors_1.default.green("✅ All checks passed! You are ready to develop. 🚀"));
|
|
163
234
|
}
|
|
164
235
|
}
|
|
165
|
-
main().catch(
|
|
236
|
+
main().catch((err) => {
|
|
237
|
+
console.error(err);
|
|
238
|
+
process.exit(1);
|
|
239
|
+
});
|
|
@@ -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
|
],
|
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,
|
|
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"}
|
|
@@ -144,36 +144,52 @@ exports.EXAMPLES = {
|
|
|
144
144
|
docsOutput: "docs/basic/fhe-operations/fhe-if-then-else.md",
|
|
145
145
|
title: "FHE If Then Else"
|
|
146
146
|
},
|
|
147
|
+
"control-flow": {
|
|
148
|
+
contract: "contracts/concepts/antipatterns/ControlFlow.sol",
|
|
149
|
+
test: "test/concepts/antipatterns/ControlFlow.ts",
|
|
150
|
+
description: "Control flow anti-patterns in FHE development. Demonstrates common mistakes when using conditional logic and loops with encrypted values.",
|
|
151
|
+
category: "Concepts - Antipatterns",
|
|
152
|
+
docsOutput: "docs/concepts/antipatterns/control-flow.md",
|
|
153
|
+
title: "Control Flow"
|
|
154
|
+
},
|
|
155
|
+
"operations-gas-noise": {
|
|
156
|
+
contract: "contracts/concepts/antipatterns/OperationsGasNoise.sol",
|
|
157
|
+
test: "test/concepts/antipatterns/OperationsGasNoise.ts",
|
|
158
|
+
description: "Operations, gas, and noise anti-patterns in FHE development. Demonstrates performance issues, side-channel leaks, and inefficient encrypted computation patterns.",
|
|
159
|
+
category: "Concepts - Antipatterns",
|
|
160
|
+
docsOutput: "docs/concepts/antipatterns/operations-gas-noise.md",
|
|
161
|
+
title: "Operations Gas Noise"
|
|
162
|
+
},
|
|
163
|
+
"permissions": {
|
|
164
|
+
contract: "contracts/concepts/antipatterns/Permissions.sol",
|
|
165
|
+
test: "test/concepts/antipatterns/Permissions.ts",
|
|
166
|
+
description: "Permission management anti-patterns in FHE development. Demonstrates common mistakes with allowThis, allow, and permission propagation across transfers and contracts.",
|
|
167
|
+
category: "Concepts - Antipatterns",
|
|
168
|
+
docsOutput: "docs/concepts/antipatterns/permissions.md",
|
|
169
|
+
title: "Permissions"
|
|
170
|
+
},
|
|
147
171
|
"fhe-access-control": {
|
|
148
|
-
contract: "contracts/concepts/FHEAccessControl.sol",
|
|
149
|
-
test: "test/concepts/FHEAccessControl.ts",
|
|
172
|
+
contract: "contracts/concepts/core/FHEAccessControl.sol",
|
|
173
|
+
test: "test/concepts/core/FHEAccessControl.ts",
|
|
150
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.",
|
|
151
|
-
category: "Concepts",
|
|
152
|
-
docsOutput: "docs/concepts/fhe-access-control.md",
|
|
175
|
+
category: "Concepts - Core",
|
|
176
|
+
docsOutput: "docs/concepts/core/fhe-access-control.md",
|
|
153
177
|
title: "FHE Access Control"
|
|
154
178
|
},
|
|
155
|
-
"fhe-anti-patterns": {
|
|
156
|
-
contract: "contracts/concepts/FHEAntiPatterns.sol",
|
|
157
|
-
test: "test/concepts/FHEAntiPatterns.ts",
|
|
158
|
-
description: "Comprehensive guide to FHE anti-patterns and their solutions. Covers 9 critical mistakes: using if/else on encrypted values, incorrect permission patterns, require() statements that leak info, unbounded loops, noise accumulation, and deprecated APIs. Each pattern shows both ❌ WRONG and ✅ CORRECT implementations.",
|
|
159
|
-
category: "Concepts",
|
|
160
|
-
docsOutput: "docs/concepts/fhe-anti-patterns.md",
|
|
161
|
-
title: "FHE Anti Patterns"
|
|
162
|
-
},
|
|
163
179
|
"fhe-handles": {
|
|
164
|
-
contract: "contracts/concepts/FHEHandles.sol",
|
|
165
|
-
test: "test/concepts/FHEHandles.ts",
|
|
180
|
+
contract: "contracts/concepts/core/FHEHandles.sol",
|
|
181
|
+
test: "test/concepts/core/FHEHandles.ts",
|
|
166
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.",
|
|
167
|
-
category: "Concepts",
|
|
168
|
-
docsOutput: "docs/concepts/fhe-handles.md",
|
|
183
|
+
category: "Concepts - Core",
|
|
184
|
+
docsOutput: "docs/concepts/core/fhe-handles.md",
|
|
169
185
|
title: "FHE Handles"
|
|
170
186
|
},
|
|
171
187
|
"fhe-input-proof": {
|
|
172
|
-
contract: "contracts/concepts/FHEInputProof.sol",
|
|
173
|
-
test: "test/concepts/FHEInputProof.ts",
|
|
188
|
+
contract: "contracts/concepts/core/FHEInputProof.sol",
|
|
189
|
+
test: "test/concepts/core/FHEInputProof.ts",
|
|
174
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.",
|
|
175
|
-
category: "Concepts",
|
|
176
|
-
docsOutput: "docs/concepts/fhe-input-proof.md",
|
|
191
|
+
category: "Concepts - Core",
|
|
192
|
+
docsOutput: "docs/concepts/core/fhe-input-proof.md",
|
|
177
193
|
title: "FHE Input Proof"
|
|
178
194
|
},
|
|
179
195
|
"encrypted-lottery": {
|
|
@@ -277,33 +293,25 @@ exports.EXAMPLES = {
|
|
|
277
293
|
// Category Configurations
|
|
278
294
|
// =============================================================================
|
|
279
295
|
exports.CATEGORIES = {
|
|
280
|
-
|
|
281
|
-
name: "
|
|
296
|
+
basicencryption: {
|
|
297
|
+
name: "Basic - Encryption",
|
|
282
298
|
contracts: [
|
|
283
299
|
{
|
|
284
|
-
sol: "contracts/
|
|
285
|
-
test: "test/
|
|
286
|
-
},
|
|
287
|
-
{
|
|
288
|
-
sol: "contracts/advanced/EncryptedEscrow.sol",
|
|
289
|
-
test: "test/advanced/EncryptedEscrow.ts",
|
|
290
|
-
},
|
|
291
|
-
{
|
|
292
|
-
sol: "contracts/advanced/HiddenVoting.sol",
|
|
293
|
-
test: "test/advanced/HiddenVoting.ts",
|
|
300
|
+
sol: "contracts/basic/encryption/EncryptMultipleValues.sol",
|
|
301
|
+
test: "test/basic/encryption/EncryptMultipleValues.ts",
|
|
294
302
|
},
|
|
295
303
|
{
|
|
296
|
-
sol: "contracts/
|
|
297
|
-
test: "test/
|
|
304
|
+
sol: "contracts/basic/encryption/EncryptSingleValue.sol",
|
|
305
|
+
test: "test/basic/encryption/EncryptSingleValue.ts",
|
|
298
306
|
},
|
|
299
307
|
{
|
|
300
|
-
sol: "contracts/
|
|
301
|
-
test: "test/
|
|
308
|
+
sol: "contracts/basic/encryption/FHECounter.sol",
|
|
309
|
+
test: "test/basic/encryption/FHECounter.ts",
|
|
302
310
|
}
|
|
303
311
|
],
|
|
304
312
|
},
|
|
305
313
|
basicdecryption: {
|
|
306
|
-
name: "Basic - Decryption
|
|
314
|
+
name: "Basic - Decryption",
|
|
307
315
|
contracts: [
|
|
308
316
|
{
|
|
309
317
|
sol: "contracts/basic/decryption/PublicDecryptMultipleValues.sol",
|
|
@@ -323,25 +331,8 @@ exports.CATEGORIES = {
|
|
|
323
331
|
}
|
|
324
332
|
],
|
|
325
333
|
},
|
|
326
|
-
basicencryption: {
|
|
327
|
-
name: "Basic - Encryption Examples",
|
|
328
|
-
contracts: [
|
|
329
|
-
{
|
|
330
|
-
sol: "contracts/basic/encryption/EncryptMultipleValues.sol",
|
|
331
|
-
test: "test/basic/encryption/EncryptMultipleValues.ts",
|
|
332
|
-
},
|
|
333
|
-
{
|
|
334
|
-
sol: "contracts/basic/encryption/EncryptSingleValue.sol",
|
|
335
|
-
test: "test/basic/encryption/EncryptSingleValue.ts",
|
|
336
|
-
},
|
|
337
|
-
{
|
|
338
|
-
sol: "contracts/basic/encryption/FHECounter.sol",
|
|
339
|
-
test: "test/basic/encryption/FHECounter.ts",
|
|
340
|
-
}
|
|
341
|
-
],
|
|
342
|
-
},
|
|
343
334
|
basicfheoperations: {
|
|
344
|
-
name: "Basic - FHE Operations
|
|
335
|
+
name: "Basic - FHE Operations",
|
|
345
336
|
contracts: [
|
|
346
337
|
{
|
|
347
338
|
sol: "contracts/basic/fhe-operations/FHEAdd.sol",
|
|
@@ -361,29 +352,42 @@ exports.CATEGORIES = {
|
|
|
361
352
|
}
|
|
362
353
|
],
|
|
363
354
|
},
|
|
364
|
-
|
|
365
|
-
name: "Concepts
|
|
355
|
+
conceptscore: {
|
|
356
|
+
name: "Concepts - Core",
|
|
366
357
|
contracts: [
|
|
367
358
|
{
|
|
368
|
-
sol: "contracts/concepts/FHEAccessControl.sol",
|
|
369
|
-
test: "test/concepts/FHEAccessControl.ts",
|
|
359
|
+
sol: "contracts/concepts/core/FHEAccessControl.sol",
|
|
360
|
+
test: "test/concepts/core/FHEAccessControl.ts",
|
|
370
361
|
},
|
|
371
362
|
{
|
|
372
|
-
sol: "contracts/concepts/
|
|
373
|
-
test: "test/concepts/
|
|
363
|
+
sol: "contracts/concepts/core/FHEHandles.sol",
|
|
364
|
+
test: "test/concepts/core/FHEHandles.ts",
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
sol: "contracts/concepts/core/FHEInputProof.sol",
|
|
368
|
+
test: "test/concepts/core/FHEInputProof.ts",
|
|
369
|
+
}
|
|
370
|
+
],
|
|
371
|
+
},
|
|
372
|
+
conceptsantipatterns: {
|
|
373
|
+
name: "Concepts - Antipatterns",
|
|
374
|
+
contracts: [
|
|
375
|
+
{
|
|
376
|
+
sol: "contracts/concepts/antipatterns/ControlFlow.sol",
|
|
377
|
+
test: "test/concepts/antipatterns/ControlFlow.ts",
|
|
374
378
|
},
|
|
375
379
|
{
|
|
376
|
-
sol: "contracts/concepts/
|
|
377
|
-
test: "test/concepts/
|
|
380
|
+
sol: "contracts/concepts/antipatterns/OperationsGasNoise.sol",
|
|
381
|
+
test: "test/concepts/antipatterns/OperationsGasNoise.ts",
|
|
378
382
|
},
|
|
379
383
|
{
|
|
380
|
-
sol: "contracts/concepts/
|
|
381
|
-
test: "test/concepts/
|
|
384
|
+
sol: "contracts/concepts/antipatterns/Permissions.sol",
|
|
385
|
+
test: "test/concepts/antipatterns/Permissions.ts",
|
|
382
386
|
}
|
|
383
387
|
],
|
|
384
388
|
},
|
|
385
389
|
gaming: {
|
|
386
|
-
name: "Gaming
|
|
390
|
+
name: "Gaming",
|
|
387
391
|
contracts: [
|
|
388
392
|
{
|
|
389
393
|
sol: "contracts/gaming/EncryptedLottery.sol",
|
|
@@ -399,8 +403,33 @@ exports.CATEGORIES = {
|
|
|
399
403
|
}
|
|
400
404
|
],
|
|
401
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
|
+
},
|
|
402
431
|
openzeppelin: {
|
|
403
|
-
name: "Openzeppelin
|
|
432
|
+
name: "Openzeppelin",
|
|
404
433
|
contracts: [
|
|
405
434
|
{
|
|
406
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"}
|
|
@@ -108,18 +108,19 @@ exports.FHEVM_DEPENDENCIES = {
|
|
|
108
108
|
"@fhevm/solidity": "^0.9.1",
|
|
109
109
|
},
|
|
110
110
|
devDependencies: {
|
|
111
|
-
"@fhevm/hardhat-plugin": "^0.3.0-
|
|
112
|
-
"@zama-fhe/relayer-sdk": "^0.3.0-
|
|
111
|
+
"@fhevm/hardhat-plugin": "^0.3.0-3",
|
|
112
|
+
"@zama-fhe/relayer-sdk": "^0.3.0-6",
|
|
113
113
|
},
|
|
114
114
|
};
|
|
115
115
|
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
|
|