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
@@ -19,253 +19,275 @@ exports.EXAMPLES = {
19
19
  "blind-auction": {
20
20
  contract: "contracts/advanced/BlindAuction.sol",
21
21
  test: "test/advanced/BlindAuction.ts",
22
- description: "Blind Auction with encrypted bids - only the winning price is revealed",
22
+ description: "Blind auction where bids remain encrypted until the end. Bidders submit encrypted amounts. The contract finds the highest bid using FHE.gt and FHE.select without ever decrypting losing bids. Only the winning bid amount is revealed after the auction closes. Losing bids remain private forever, ensuring true bid confidentiality.",
23
23
  category: "Advanced",
24
24
  docsOutput: "docs/advanced/blind-auction.md",
25
- title: "Blind Auction",
25
+ title: "Blind Auction"
26
26
  },
27
27
  "encrypted-escrow": {
28
28
  contract: "contracts/advanced/EncryptedEscrow.sol",
29
29
  test: "test/advanced/EncryptedEscrow.ts",
30
- description: "Encrypted Escrow service - amounts hidden until release!",
30
+ description: "Confidential escrow service with hidden transaction amounts. Buyer and seller agree on encrypted escrow amount. Funds are held securely until conditions are met. Amount remains hidden from public view until release or refund. Includes arbiter for dispute resolution. Perfect for high-value transactions requiring privacy.",
31
31
  category: "Advanced",
32
32
  docsOutput: "docs/advanced/encrypted-escrow.md",
33
- title: "Encrypted Escrow",
33
+ title: "Encrypted Escrow"
34
34
  },
35
35
  "hidden-voting": {
36
36
  contract: "contracts/advanced/HiddenVoting.sol",
37
37
  test: "test/advanced/HiddenVoting.ts",
38
- description: "Hidden Voting with encrypted ballots and homomorphic tallying",
38
+ description: "Private voting system with homomorphic vote tallying. Voters submit encrypted ballots (Yes/No). Votes are tallied using homomorphic addition WITHOUT decrypting individual ballots. Only the final tally is revealed - individual votes remain private forever. Perfect for DAO governance, elections, or any scenario requiring ballot secrecy.",
39
39
  category: "Advanced",
40
40
  docsOutput: "docs/advanced/hidden-voting.md",
41
- title: "Hidden Voting",
41
+ title: "Hidden Voting"
42
42
  },
43
43
  "private-kyc": {
44
44
  contract: "contracts/advanced/PrivateKYC.sol",
45
45
  test: "test/advanced/PrivateKYC.ts",
46
- description: "Private KYC - verify identity without revealing personal data!",
46
+ description: "Privacy-preserving identity verification using predicate proofs. Users submit encrypted personal data (age, country, credit score). Contract can verify predicates like \"Is user 18+?\" or \"Good credit?\" without learning the actual values. Returns encrypted booleans that prove compliance without revealing sensitive information. Revolutionary for KYC/AML compliance while preserving user privacy.",
47
47
  category: "Advanced",
48
48
  docsOutput: "docs/advanced/private-kyc.md",
49
- title: "Private KYC",
49
+ title: "Private KYC"
50
50
  },
51
51
  "private-payroll": {
52
52
  contract: "contracts/advanced/PrivatePayroll.sol",
53
53
  test: "test/advanced/PrivatePayroll.ts",
54
- description: "Private Payroll system - salaries stay encrypted, only employees see their own!",
54
+ description: "Confidential payroll system with encrypted salaries. Employers can add employees with encrypted salary amounts. Each employee can decrypt only their own salary - other salaries remain hidden. Demonstrates selective decryption permissions where different users see different encrypted values. Perfect for privacy-preserving HR systems.",
55
55
  category: "Advanced",
56
56
  docsOutput: "docs/advanced/private-payroll.md",
57
- title: "Private Payroll",
57
+ title: "Private Payroll"
58
58
  },
59
59
  "public-decrypt-multiple-values": {
60
60
  contract: "contracts/basic/decryption/PublicDecryptMultipleValues.sol",
61
61
  test: "test/basic/decryption/PublicDecryptMultipleValues.ts",
62
- description: "Implements a simple 8-sided Die Roll game demonstrating public, permissionless decryption",
62
+ description: "Highest die roll game with public decryption of multiple values. Two players roll encrypted 8-sided dice, results are made publicly decryptable. Demonstrates handling multiple encrypted values in checkSignatures() where ORDER MATTERS - the cts[] array must match the order of values in the ABI-encoded result.",
63
63
  category: "Basic - Decryption",
64
64
  docsOutput: "docs/basic/decryption/public-decrypt-multiple-values.md",
65
- title: "Public Decrypt Multiple Values",
65
+ title: "Public Decrypt Multiple Values"
66
66
  },
67
67
  "public-decrypt-single-value": {
68
68
  contract: "contracts/basic/decryption/PublicDecryptSingleValue.sol",
69
69
  test: "test/basic/decryption/PublicDecryptSingleValue.ts",
70
- description: "Implements a simple Heads or Tails game demonstrating public, permissionless decryption",
70
+ description: "Heads or Tails game with public, permissionless decryption. Demonstrates makePubliclyDecryptable() which allows ANYONE to decrypt the result (not just allowed users). Perfect for public game results, lottery winners, or voting tallies. Uses FHE.randEbool() for fair randomness and KMS-verified decryption proofs.",
71
71
  category: "Basic - Decryption",
72
72
  docsOutput: "docs/basic/decryption/public-decrypt-single-value.md",
73
- title: "Public Decrypt Single Value",
73
+ title: "Public Decrypt Single Value"
74
74
  },
75
75
  "user-decrypt-multiple-values": {
76
76
  contract: "contracts/basic/decryption/UserDecryptMultipleValues.sol",
77
77
  test: "test/basic/decryption/UserDecryptMultipleValues.ts",
78
- description: "Demonstrates user decryption of multiple encrypted values",
78
+ description: "Decrypting multiple encrypted values of different types for a user. Shows how to handle ebool, euint32, and euint64 in one contract. Each value requires individual permission grants - there's no batching for permissions (unlike input proofs). Demonstrates the pattern of granting allowThis() for each value separately.",
79
79
  category: "Basic - Decryption",
80
80
  docsOutput: "docs/basic/decryption/user-decrypt-multiple-values.md",
81
- title: "User Decrypt Multiple Values",
81
+ title: "User Decrypt Multiple Values"
82
82
  },
83
83
  "user-decrypt-single-value": {
84
84
  contract: "contracts/basic/decryption/UserDecryptSingleValue.sol",
85
85
  test: "test/basic/decryption/UserDecryptSingleValue.ts",
86
- description: "Demonstrates the FHE decryption mechanism and highlights common pitfalls",
86
+ description: "User-controlled decryption with proper permission management. Demonstrates the critical two-step permission pattern: allowThis() grants the contract permission to store/compute, while allow() grants the user permission to decrypt. Missing either step causes decryption to fail. Includes examples of both correct and incorrect patterns.",
87
87
  category: "Basic - Decryption",
88
88
  docsOutput: "docs/basic/decryption/user-decrypt-single-value.md",
89
- title: "User Decrypt Single Value",
89
+ title: "User Decrypt Single Value"
90
90
  },
91
91
  "encrypt-multiple-values": {
92
92
  contract: "contracts/basic/encryption/EncryptMultipleValues.sol",
93
93
  test: "test/basic/encryption/EncryptMultipleValues.ts",
94
- description: "Encrypting and handling multiple values in a single transaction efficiently.",
94
+ description: "Efficient handling of multiple encrypted values in one transaction. Demonstrates batched input validation where a single proof covers multiple encrypted values (ebool, euint32, eaddress), saving ~50k gas per additional value compared to separate proofs.",
95
95
  category: "Basic - Encryption",
96
96
  docsOutput: "docs/basic/encryption/encrypt-multiple-values.md",
97
- title: "Encrypt Multiple Values",
97
+ title: "Encrypt Multiple Values"
98
98
  },
99
99
  "encrypt-single-value": {
100
100
  contract: "contracts/basic/encryption/EncryptSingleValue.sol",
101
101
  test: "test/basic/encryption/EncryptSingleValue.ts",
102
- description: "FHE encryption mechanism with single values, including common pitfalls and best practices for developers.",
102
+ description: "Single value encryption with proof validation. Shows how to receive encrypted data from users, validate proofs, and grant proper permissions. Includes examples of common mistakes and the correct permission pattern (allowThis + allow).",
103
103
  category: "Basic - Encryption",
104
104
  docsOutput: "docs/basic/encryption/encrypt-single-value.md",
105
- title: "Encrypt Single Value",
105
+ title: "Encrypt Single Value"
106
106
  },
107
107
  "fhe-counter": {
108
108
  contract: "contracts/basic/encryption/FHECounter.sol",
109
109
  test: "test/basic/encryption/FHECounter.ts",
110
- description: "Confidential counter implementation using FHEVM, compared with a standard counter to highlight encryption benefits.",
110
+ description: "Confidential counter with encrypted increment/decrement operations. Demonstrates the complete FHE workflow: encryption, computation, and permission management. The counter value remains private, only accessible through decryption by authorized users.",
111
111
  category: "Basic - Encryption",
112
112
  docsOutput: "docs/basic/encryption/fhe-counter.md",
113
- title: "FHE Counter",
113
+ title: "FHE Counter"
114
114
  },
115
115
  "fhe-add": {
116
116
  contract: "contracts/basic/fhe-operations/FHEAdd.sol",
117
117
  test: "test/basic/fhe-operations/FHEAdd.ts",
118
- description: "Simple example: adding two encrypted values (a + b)",
118
+ description: "Introduction to homomorphic addition on encrypted values. Demonstrates the most fundamental FHE operation: adding two encrypted numbers without decrypting them. Shows the complete flow from receiving encrypted inputs, performing the addition, and granting permissions for both contract storage and user decryption.",
119
119
  category: "Basic - FHE Operations",
120
120
  docsOutput: "docs/basic/fhe-operations/fhe-add.md",
121
- title: "FHE Add",
121
+ title: "FHE Add"
122
122
  },
123
123
  "fhe-arithmetic": {
124
124
  contract: "contracts/basic/fhe-operations/FHEArithmetic.sol",
125
125
  test: "test/basic/fhe-operations/FHEArithmetic.ts",
126
- description: "Demonstrates all FHE arithmetic operations on encrypted integers",
126
+ description: "Complete suite of FHE arithmetic operations on encrypted values. Covers all basic math: addition, subtraction, multiplication, division, remainder (modulo), minimum, and maximum. Includes gas cost comparisons and important limitations (e.g., division/remainder only work with plaintext divisors, not encrypted divisors).",
127
127
  category: "Basic - FHE Operations",
128
128
  docsOutput: "docs/basic/fhe-operations/fhe-arithmetic.md",
129
- title: "FHE Arithmetic",
129
+ title: "FHE Arithmetic"
130
130
  },
131
131
  "fhe-comparison": {
132
132
  contract: "contracts/basic/fhe-operations/FHEComparison.sol",
133
133
  test: "test/basic/fhe-operations/FHEComparison.ts",
134
- description: "Demonstrates all FHE comparison operations on encrypted integers",
134
+ description: "Complete guide to encrypted comparisons and conditional selection. Covers all comparison operators (eq, ne, gt, lt, ge, le) that return encrypted booleans (ebool), and demonstrates FHE.select for branching without information leakage. Critical for implementing logic like \"find maximum\" or \"check threshold\" without revealing values.",
135
135
  category: "Basic - FHE Operations",
136
136
  docsOutput: "docs/basic/fhe-operations/fhe-comparison.md",
137
- title: "FHE Comparison",
137
+ title: "FHE Comparison"
138
138
  },
139
139
  "fhe-if-then-else": {
140
140
  contract: "contracts/basic/fhe-operations/FHEIfThenElse.sol",
141
141
  test: "test/basic/fhe-operations/FHEIfThenElse.ts",
142
- description: "Demonstrates conditional logic: max(a, b) using encrypted comparison",
142
+ description: "Conditional logic without information leakage using FHE.select. Demonstrates how to implement if-then-else logic on encrypted values (computing max of two numbers). Using regular if/else would decrypt and leak which branch was taken. FHE.select evaluates BOTH branches and picks one based on the encrypted condition, preserving privacy.",
143
143
  category: "Basic - FHE Operations",
144
144
  docsOutput: "docs/basic/fhe-operations/fhe-if-then-else.md",
145
- title: "FHE If Then Else",
145
+ title: "FHE If Then Else"
146
146
  },
147
147
  "fhe-access-control": {
148
148
  contract: "contracts/concepts/FHEAccessControl.sol",
149
149
  test: "test/concepts/FHEAccessControl.ts",
150
- description: "Critical access control patterns in FHEVM: FHE.allow, FHE.allowThis, FHE.allowTransient. Includes common mistakes and correct implementations.",
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
151
  category: "Concepts",
152
152
  docsOutput: "docs/concepts/fhe-access-control.md",
153
- title: "FHE Access Control",
154
- },
155
- "fhe-anti-patterns": {
156
- contract: "contracts/concepts/FHEAntiPatterns.sol",
157
- test: "test/concepts/FHEAntiPatterns.ts",
158
- description: "Common FHE mistakes and their correct alternatives. Covers: branching, permissions, require/revert, re-encryption, loops, noise, and deprecated APIs.",
159
- category: "Concepts",
160
- docsOutput: "docs/concepts/fhe-anti-patterns.md",
161
- title: "FHE Anti Patterns",
153
+ title: "FHE Access Control"
162
154
  },
163
155
  "fhe-handles": {
164
156
  contract: "contracts/concepts/FHEHandles.sol",
165
157
  test: "test/concepts/FHEHandles.ts",
166
- description: "Understanding FHE handles: creation, computation, immutability, and symbolic execution in mock mode.",
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.",
167
159
  category: "Concepts",
168
160
  docsOutput: "docs/concepts/fhe-handles.md",
169
- title: "FHE Handles",
161
+ title: "FHE Handles"
170
162
  },
171
163
  "fhe-input-proof": {
172
164
  contract: "contracts/concepts/FHEInputProof.sol",
173
165
  test: "test/concepts/FHEInputProof.ts",
174
- description: "Explains input proof validation in FHEVM: what proofs are, why they are needed, and how to use them correctly with single and batched inputs.",
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.",
175
167
  category: "Concepts",
176
168
  docsOutput: "docs/concepts/fhe-input-proof.md",
177
- title: "FHE Input Proof",
169
+ title: "FHE Input Proof"
170
+ },
171
+ "control-flow": {
172
+ contract: "contracts/concepts/antipatterns/ControlFlow.sol",
173
+ test: "test/concepts/antipatterns/ControlFlow.ts",
174
+ description: "Control flow anti-patterns in FHE development. Demonstrates common mistakes when using conditional logic and loops with encrypted values.",
175
+ category: "Concepts - Antipatterns",
176
+ docsOutput: "docs/concepts/antipatterns/control-flow.md",
177
+ title: "Control Flow"
178
+ },
179
+ "operations-gas-noise": {
180
+ contract: "contracts/concepts/antipatterns/OperationsGasNoise.sol",
181
+ test: "test/concepts/antipatterns/OperationsGasNoise.ts",
182
+ description: "Operations, gas, and noise anti-patterns in FHE development. Demonstrates performance issues, side-channel leaks, and inefficient encrypted computation patterns.",
183
+ category: "Concepts - Antipatterns",
184
+ docsOutput: "docs/concepts/antipatterns/operations-gas-noise.md",
185
+ title: "Operations Gas Noise"
186
+ },
187
+ "permissions": {
188
+ contract: "contracts/concepts/antipatterns/Permissions.sol",
189
+ test: "test/concepts/antipatterns/Permissions.ts",
190
+ description: "Permission management anti-patterns in FHE development. Demonstrates common mistakes with allowThis, allow, and permission propagation across transfers and contracts.",
191
+ category: "Concepts - Antipatterns",
192
+ docsOutput: "docs/concepts/antipatterns/permissions.md",
193
+ title: "Permissions"
178
194
  },
179
195
  "encrypted-lottery": {
180
196
  contract: "contracts/gaming/EncryptedLottery.sol",
181
197
  test: "test/gaming/EncryptedLottery.ts",
182
- description: "Encrypted Lottery with private ticket numbers - fair and verifiable!",
198
+ description: "Provably fair lottery with encrypted ticket numbers. Players buy tickets with encrypted numbers. Winning number is generated using FHE randomness. Winner is determined by comparing encrypted values without revealing losing tickets. Ensures fairness and privacy - no one can see ticket numbers before the draw.",
183
199
  category: "Gaming",
184
200
  docsOutput: "docs/gaming/encrypted-lottery.md",
185
- title: "Encrypted Lottery",
201
+ title: "Encrypted Lottery"
186
202
  },
187
203
  "encrypted-poker": {
188
204
  contract: "contracts/gaming/EncryptedPoker.sol",
189
205
  test: "test/gaming/EncryptedPoker.ts",
190
- description: "Encrypted Poker - Texas Hold'em with hidden hole cards!",
206
+ description: "On-chain Texas Hold'em poker with encrypted hole cards. Two players receive encrypted hole cards that remain hidden throughout the game. Hand strength is computed using FHE operations. Winner is determined by comparing encrypted hand strengths. Demonstrates complex game logic with multiple encrypted states and conditional operations.",
191
207
  category: "Gaming",
192
208
  docsOutput: "docs/gaming/encrypted-poker.md",
193
- title: "Encrypted Poker",
209
+ title: "Encrypted Poker"
194
210
  },
195
211
  "rock-paper-scissors": {
196
212
  contract: "contracts/gaming/RockPaperScissors.sol",
197
213
  test: "test/gaming/RockPaperScissors.ts",
198
- description: "Rock-Paper-Scissors game with encrypted moves - fair play guaranteed!",
214
+ description: "Fair Rock-Paper-Scissors game with encrypted moves. Players submit encrypted moves (0=Rock, 1=Paper, 2=Scissors) ensuring neither player can see the other's choice before committing. Winner is determined using FHE operations and revealed publicly. No trusted third party needed - cryptography guarantees fairness.",
199
215
  category: "Gaming",
200
216
  docsOutput: "docs/gaming/rock-paper-scissors.md",
201
- title: "Rock Paper Scissors",
217
+ title: "Rock Paper Scissors"
202
218
  },
203
- erc7984: {
219
+ "erc7984": {
204
220
  contract: "contracts/openzeppelin/ERC7984.sol",
205
221
  test: "test/openzeppelin/ERC7984.ts",
206
222
  npmDependencies: {
207
223
  "@openzeppelin/contracts": "^5.4.0",
208
- "@openzeppelin/confidential-contracts": "^0.3.0",
224
+ "@openzeppelin/confidential-contracts": "^0.3.0"
209
225
  },
210
- description: "Confidential token using OpenZeppelin's ERC7984 standard",
226
+ description: "Confidential ERC20-compatible token using OpenZeppelin's ERC7984 standard. Implements a fully private token where balances and transfer amounts are encrypted. Compatible with standard ERC20 interfaces but with FHE under the hood. Supports both visible minting (owner knows amount) and confidential minting (fully private). Foundation for building private DeFi applications.",
211
227
  category: "Openzeppelin",
212
228
  docsOutput: "docs/openzeppelin/erc7984.md",
213
- title: "ERC7984",
229
+ title: "ERC7984"
214
230
  },
215
231
  "erc7984-erc20-wrapper": {
216
232
  contract: "contracts/openzeppelin/ERC7984ERC20Wrapper.sol",
217
233
  test: "test/openzeppelin/ERC7984ERC20Wrapper.ts",
218
234
  npmDependencies: {
219
235
  "@openzeppelin/contracts": "^5.4.0",
220
- "@openzeppelin/confidential-contracts": "^0.3.0",
236
+ "@openzeppelin/confidential-contracts": "^0.3.0"
221
237
  },
222
- dependencies: ["contracts/openzeppelin/mocks/ERC20Mock.sol"],
223
- description: "Wraps ERC20 tokens into confidential ERC7984 tokens",
238
+ dependencies: [
239
+ "contracts/openzeppelin/mocks/ERC20Mock.sol"
240
+ ],
241
+ description: "Bridge between public ERC20 and confidential ERC7984 tokens. Allows users to wrap regular ERC20 tokens into privacy-preserving ERC7984 tokens (public → private) and unwrap them back (private → public). Wrapping is instant, unwrapping requires decryption proof from KMS. Essential for bringing existing tokens into the confidential ecosystem.",
224
242
  category: "Openzeppelin",
225
243
  docsOutput: "docs/openzeppelin/erc7984-erc20-wrapper.md",
226
- title: "ERC7984 ERC20 Wrapper",
244
+ title: "ERC7984 ERC20 Wrapper"
227
245
  },
228
246
  "swap-erc7984-to-erc20": {
229
247
  contract: "contracts/openzeppelin/SwapERC7984ToERC20.sol",
230
248
  test: "test/openzeppelin/SwapERC7984ToERC20.ts",
231
249
  npmDependencies: {
232
250
  "@openzeppelin/contracts": "^5.4.0",
233
- "@openzeppelin/confidential-contracts": "^0.3.0",
251
+ "@openzeppelin/confidential-contracts": "^0.3.0"
234
252
  },
235
253
  dependencies: [
236
254
  "contracts/openzeppelin/mocks/ERC20Mock.sol",
237
- "contracts/openzeppelin/ERC7984.sol",
255
+ "contracts/openzeppelin/ERC7984.sol"
238
256
  ],
239
- description: "Swap confidential ERC7984 tokens to regular ERC20 tokens",
257
+ description: "Atomic swap from confidential ERC7984 to public ERC20 tokens. Two-step process: (1) Initiate swap with encrypted amount, request decryption from KMS. (2) Finalize swap with decryption proof, receive ERC20 tokens. Demonstrates the FHEVM v0.9 public decryption flow with makePubliclyDecryptable() and checkSignatures() for trustless swaps.",
240
258
  category: "Openzeppelin",
241
259
  docsOutput: "docs/openzeppelin/swap-erc7984-to-erc20.md",
242
- title: "Swap ERC7984 To ERC20",
260
+ title: "Swap ERC7984 To ERC20"
243
261
  },
244
262
  "swap-erc7984-to-erc7984": {
245
263
  contract: "contracts/openzeppelin/SwapERC7984ToERC7984.sol",
246
264
  test: "test/openzeppelin/SwapERC7984ToERC7984.ts",
247
265
  npmDependencies: {
248
- "@openzeppelin/confidential-contracts": "^0.3.0",
266
+ "@openzeppelin/confidential-contracts": "^0.3.0"
249
267
  },
250
- dependencies: ["contracts/openzeppelin/ERC7984.sol"],
251
- description: "Fully confidential swap between two ERC7984 tokens",
268
+ dependencies: [
269
+ "contracts/openzeppelin/ERC7984.sol"
270
+ ],
271
+ description: "Fully private atomic swap between two confidential ERC7984 tokens. Both input and output amounts remain encrypted throughout the entire swap process. No decryption needed - amounts stay private from start to finish. Perfect for confidential DEX operations where trade sizes must remain hidden. The ultimate privacy-preserving token exchange.",
252
272
  category: "Openzeppelin",
253
273
  docsOutput: "docs/openzeppelin/swap-erc7984-to-erc7984.md",
254
- title: "Swap ERC7984 To ERC7984",
274
+ title: "Swap ERC7984 To ERC7984"
255
275
  },
256
276
  "vesting-wallet": {
257
277
  contract: "contracts/openzeppelin/VestingWallet.sol",
258
278
  test: "test/openzeppelin/VestingWallet.ts",
259
279
  npmDependencies: {
260
280
  "@openzeppelin/contracts": "^5.4.0",
261
- "@openzeppelin/confidential-contracts": "^0.3.0",
281
+ "@openzeppelin/confidential-contracts": "^0.3.0"
262
282
  },
263
- dependencies: ["contracts/openzeppelin/ERC7984.sol"],
264
- description: "Linear vesting wallet for ERC7984 tokens - amounts stay encrypted!",
283
+ dependencies: [
284
+ "contracts/openzeppelin/ERC7984.sol"
285
+ ],
286
+ description: "Time-locked vesting wallet with fully encrypted token amounts. Implements linear vesting for ERC7984 confidential tokens. Vesting schedule, amounts, and release calculations all happen on encrypted values using FHE operations. Beneficiary can release vested tokens over time without revealing the total allocation or vesting progress to observers.",
265
287
  category: "Openzeppelin",
266
288
  docsOutput: "docs/openzeppelin/vesting-wallet.md",
267
- title: "Vesting Wallet",
268
- },
289
+ title: "Vesting Wallet"
290
+ }
269
291
  };
270
292
  // =============================================================================
271
293
  // Category Configurations
@@ -293,7 +315,7 @@ exports.CATEGORIES = {
293
315
  {
294
316
  sol: "contracts/advanced/PrivatePayroll.sol",
295
317
  test: "test/advanced/PrivatePayroll.ts",
296
- },
318
+ }
297
319
  ],
298
320
  },
299
321
  basicdecryption: {
@@ -314,7 +336,7 @@ exports.CATEGORIES = {
314
336
  {
315
337
  sol: "contracts/basic/decryption/UserDecryptSingleValue.sol",
316
338
  test: "test/basic/decryption/UserDecryptSingleValue.ts",
317
- },
339
+ }
318
340
  ],
319
341
  },
320
342
  basicencryption: {
@@ -331,7 +353,7 @@ exports.CATEGORIES = {
331
353
  {
332
354
  sol: "contracts/basic/encryption/FHECounter.sol",
333
355
  test: "test/basic/encryption/FHECounter.ts",
334
- },
356
+ }
335
357
  ],
336
358
  },
337
359
  basicfheoperations: {
@@ -352,7 +374,7 @@ exports.CATEGORIES = {
352
374
  {
353
375
  sol: "contracts/basic/fhe-operations/FHEIfThenElse.sol",
354
376
  test: "test/basic/fhe-operations/FHEIfThenElse.ts",
355
- },
377
+ }
356
378
  ],
357
379
  },
358
380
  concepts: {
@@ -362,10 +384,6 @@ exports.CATEGORIES = {
362
384
  sol: "contracts/concepts/FHEAccessControl.sol",
363
385
  test: "test/concepts/FHEAccessControl.ts",
364
386
  },
365
- {
366
- sol: "contracts/concepts/FHEAntiPatterns.sol",
367
- test: "test/concepts/FHEAntiPatterns.ts",
368
- },
369
387
  {
370
388
  sol: "contracts/concepts/FHEHandles.sol",
371
389
  test: "test/concepts/FHEHandles.ts",
@@ -373,7 +391,24 @@ exports.CATEGORIES = {
373
391
  {
374
392
  sol: "contracts/concepts/FHEInputProof.sol",
375
393
  test: "test/concepts/FHEInputProof.ts",
394
+ }
395
+ ],
396
+ },
397
+ conceptsantipatterns: {
398
+ name: "Concepts - Antipatterns Examples",
399
+ contracts: [
400
+ {
401
+ sol: "contracts/concepts/antipatterns/ControlFlow.sol",
402
+ test: "test/concepts/antipatterns/ControlFlow.ts",
376
403
  },
404
+ {
405
+ sol: "contracts/concepts/antipatterns/OperationsGasNoise.sol",
406
+ test: "test/concepts/antipatterns/OperationsGasNoise.ts",
407
+ },
408
+ {
409
+ sol: "contracts/concepts/antipatterns/Permissions.sol",
410
+ test: "test/concepts/antipatterns/Permissions.ts",
411
+ }
377
412
  ],
378
413
  },
379
414
  gaming: {
@@ -390,7 +425,7 @@ exports.CATEGORIES = {
390
425
  {
391
426
  sol: "contracts/gaming/RockPaperScissors.sol",
392
427
  test: "test/gaming/RockPaperScissors.ts",
393
- },
428
+ }
394
429
  ],
395
430
  },
396
431
  openzeppelin: {
@@ -415,9 +450,9 @@ exports.CATEGORIES = {
415
450
  {
416
451
  sol: "contracts/openzeppelin/VestingWallet.sol",
417
452
  test: "test/openzeppelin/VestingWallet.ts",
418
- },
453
+ }
419
454
  ],
420
- },
455
+ }
421
456
  };
422
457
  // =============================================================================
423
458
  // Helper Functions
@@ -108,8 +108,8 @@ exports.FHEVM_DEPENDENCIES = {
108
108
  "@fhevm/solidity": "^0.9.1",
109
109
  },
110
110
  devDependencies: {
111
- "@fhevm/hardhat-plugin": "^0.3.0-1",
112
- "@zama-fhe/relayer-sdk": "^0.3.0-5",
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 = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fhevm-example",
3
- "version": "1.4.4",
3
+ "version": "1.4.6",
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"
@@ -26,7 +26,8 @@ describe("FHEAntiPatterns", function () {
26
26
 
27
27
  before(async function () {
28
28
  if (!hre.fhevm.isMock) {
29
- throw new Error(`This hardhat test suite cannot run on Sepolia Testnet`);
29
+ console.warn(`This hardhat test suite cannot run on Sepolia Testnet`);
30
+ this.skip();
30
31
  }
31
32
  const ethSigners: HardhatEthersSigner[] = await ethers.getSigners();
32
33
  signers = { owner: ethSigners[0], alice: ethSigners[1] };
@@ -0,0 +1,125 @@
1
+ import {
2
+ FhevmType,
3
+ HardhatFhevmRuntimeEnvironment,
4
+ } from "@fhevm/hardhat-plugin";
5
+ import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
6
+ import { expect } from "chai";
7
+ import { ethers } from "hardhat";
8
+ import * as hre from "hardhat";
9
+
10
+ import {
11
+ FHEControlFlowAntiPatterns,
12
+ FHEControlFlowAntiPatterns__factory,
13
+ } from "../types";
14
+ import type { Signers } from "./types";
15
+
16
+ async function deployFixture() {
17
+ const factory = (await ethers.getContractFactory(
18
+ "FHEControlFlowAntiPatterns"
19
+ )) as FHEControlFlowAntiPatterns__factory;
20
+ const contract = (await factory.deploy()) as FHEControlFlowAntiPatterns;
21
+ const contractAddress = await contract.getAddress();
22
+ return { contract, contractAddress };
23
+ }
24
+
25
+ /**
26
+ * @notice Tests for FHE control flow anti-patterns
27
+ * Demonstrates wrong and correct patterns for conditional logic and loops
28
+ */
29
+ describe("FHEControlFlowAntiPatterns", function () {
30
+ let contract: FHEControlFlowAntiPatterns;
31
+ let contractAddress: string;
32
+ let signers: Signers;
33
+
34
+ before(async function () {
35
+ if (!hre.fhevm.isMock) {
36
+ throw new Error(`This hardhat test suite cannot run on Sepolia Testnet`);
37
+ }
38
+ const ethSigners: HardhatEthersSigner[] = await ethers.getSigners();
39
+ signers = { owner: ethSigners[0], alice: ethSigners[1] };
40
+ });
41
+
42
+ beforeEach(async function () {
43
+ const deployment = await deployFixture();
44
+ contractAddress = deployment.contractAddress;
45
+ contract = deployment.contract;
46
+
47
+ // Initialize contract with test values
48
+ const fhevm: HardhatFhevmRuntimeEnvironment = hre.fhevm;
49
+
50
+ // Create encrypted input for balance only (threshold is fixed at 100)
51
+ const input = await fhevm
52
+ .createEncryptedInput(contractAddress, signers.alice.address)
53
+ .add32(50) // balance
54
+ .encrypt();
55
+
56
+ await contract
57
+ .connect(signers.alice)
58
+ .initialize(input.handles[0], input.inputProof);
59
+ });
60
+
61
+ describe("Pattern 1: If/Else Branching", function () {
62
+ it("should execute correctConditional without leaking information", async function () {
63
+ const fhevm: HardhatFhevmRuntimeEnvironment = hre.fhevm;
64
+
65
+ await contract.connect(signers.alice).correctConditional();
66
+
67
+ const encrypted = await contract.getBalance();
68
+ const decrypted = await fhevm.userDecryptEuint(
69
+ FhevmType.euint32,
70
+ encrypted,
71
+ contractAddress,
72
+ signers.alice
73
+ );
74
+
75
+ // Balance (50) is not above threshold (100), so no penalty applied
76
+ expect(decrypted).to.equal(50);
77
+ });
78
+
79
+ it("wrongBranching should return placeholder value", async function () {
80
+ const result = await contract.wrongBranching.staticCall();
81
+ expect(result).to.equal(0);
82
+ });
83
+ });
84
+
85
+ describe("Pattern 2: Require/Revert", function () {
86
+ it("should return encrypted boolean for validation", async function () {
87
+ const fhevm: HardhatFhevmRuntimeEnvironment = hre.fhevm;
88
+
89
+ // Execute validation (stores result)
90
+ await contract.connect(signers.alice).correctValidation();
91
+
92
+ // Get result via getter
93
+ const encrypted = await contract.getValidationResult();
94
+ const decrypted = await fhevm.userDecryptEbool(
95
+ encrypted,
96
+ contractAddress,
97
+ signers.alice
98
+ );
99
+
100
+ // Balance (50) < 100, so should be false
101
+ expect(decrypted).to.equal(false);
102
+ });
103
+
104
+ it("wrongRequire should return explanation string", async function () {
105
+ const result = await contract.wrongRequire();
106
+ expect(result).to.include("doesn't work with encrypted values");
107
+ });
108
+ });
109
+
110
+ describe("Pattern 3: Encrypted Loop Iterations", function () {
111
+ it("should use fixed iterations with FHE.select", async function () {
112
+ const fhevm: HardhatFhevmRuntimeEnvironment = hre.fhevm;
113
+
114
+ await contract.connect(signers.alice).correctFixedIterations();
115
+
116
+ // Result should count up to min(balance, MAX_ITERATIONS)
117
+ // Balance is 50, MAX_ITERATIONS is 5, so result should be 5
118
+ });
119
+
120
+ it("wrongEncryptedLoop should return explanation string", async function () {
121
+ const result = await contract.wrongEncryptedLoop();
122
+ expect(result).to.include("Loop iterations leak");
123
+ });
124
+ });
125
+ });