create-fhevm-example 1.4.2 → 1.4.4

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 (28) hide show
  1. package/contracts/advanced/BlindAuction.sol +18 -57
  2. package/contracts/advanced/EncryptedEscrow.sol +2 -30
  3. package/contracts/advanced/HiddenVoting.sol +15 -54
  4. package/contracts/advanced/PrivateKYC.sol +3 -32
  5. package/contracts/advanced/PrivatePayroll.sol +4 -34
  6. package/contracts/basic/decryption/PublicDecryptMultipleValues.sol +9 -17
  7. package/contracts/basic/decryption/PublicDecryptSingleValue.sol +9 -16
  8. package/contracts/basic/decryption/UserDecryptMultipleValues.sol +7 -21
  9. package/contracts/basic/decryption/UserDecryptSingleValue.sol +11 -30
  10. package/contracts/basic/encryption/EncryptMultipleValues.sol +12 -21
  11. package/contracts/basic/encryption/EncryptSingleValue.sol +11 -17
  12. package/contracts/basic/encryption/FHECounter.sol +15 -16
  13. package/contracts/basic/fhe-operations/FHEAdd.sol +10 -16
  14. package/contracts/basic/fhe-operations/FHEArithmetic.sol +15 -31
  15. package/contracts/basic/fhe-operations/FHEComparison.sol +8 -29
  16. package/contracts/basic/fhe-operations/FHEIfThenElse.sol +4 -9
  17. package/contracts/concepts/FHEAccessControl.sol +23 -28
  18. package/contracts/concepts/FHEAntiPatterns.sol +4 -37
  19. package/contracts/concepts/FHEHandles.sol +10 -29
  20. package/contracts/concepts/FHEInputProof.sol +9 -33
  21. package/contracts/gaming/EncryptedLottery.sol +6 -37
  22. package/contracts/gaming/EncryptedPoker.sol +3 -33
  23. package/contracts/gaming/RockPaperScissors.sol +39 -64
  24. package/contracts/openzeppelin/VestingWallet.sol +8 -17
  25. package/dist/scripts/shared/generators.d.ts +12 -0
  26. package/dist/scripts/shared/generators.d.ts.map +1 -1
  27. package/dist/scripts/shared/generators.js +126 -2
  28. package/package.json +1 -1
@@ -13,23 +13,11 @@ import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
13
13
  /**
14
14
  * @notice Encrypted Lottery with private ticket numbers - fair and verifiable!
15
15
  *
16
- * @dev Demonstrates FHE random selection and encrypted matching:
17
- * - Players purchase tickets with encrypted numbers
18
- * - Winning number generated using block randomness + FHE
19
- * - Winners identified via FHE.eq without revealing ticket numbers
20
- * - Only winner's ticket revealed at end
21
- *
22
- * Flow:
23
- * 1. Lottery created with ticket price and duration
24
- * 2. Players buy tickets with encrypted numbers
25
- * 3. Owner draws winning number at end
26
- * 4. Winners can claim prizes
27
- *
28
- * ⚠️ IMPORTANT: Block randomness is predictable - use VRF in production!
16
+ * @dev Flow: buyTicket() startDrawing() checkAndClaim() → revealWinner()
17
+ * Gas: Loop in checkAndClaim can be expensive with many tickets!
18
+ * ⚠️ Block randomness is predictable - use VRF in production!
29
19
  */
30
20
  contract EncryptedLottery is ZamaEthereumConfig {
31
- // ==================== TYPES ====================
32
-
33
21
  enum LotteryState {
34
22
  Open, // Accepting tickets
35
23
  Drawing, // Drawing in progress
@@ -41,9 +29,6 @@ contract EncryptedLottery is ZamaEthereumConfig {
41
29
  euint64 number;
42
30
  }
43
31
 
44
- // ==================== STATE ====================
45
-
46
- /// Lottery owner
47
32
  address public owner;
48
33
 
49
34
  /// Current lottery state
@@ -73,9 +58,7 @@ contract EncryptedLottery is ZamaEthereumConfig {
73
58
  /// Lottery round number
74
59
  uint256 public roundNumber;
75
60
 
76
- // ==================== EVENTS ====================
77
-
78
- /// @notice Emitted when a ticket is purchased
61
+ /// Emitted when a ticket is purchased
79
62
  /// @param buyer Address of ticket buyer
80
63
  /// @param ticketIndex Index of the ticket
81
64
  event TicketPurchased(address indexed buyer, uint256 indexed ticketIndex);
@@ -94,18 +77,11 @@ contract EncryptedLottery is ZamaEthereumConfig {
94
77
  /// @param rollover Amount rolled to next round
95
78
  event NoWinner(uint256 indexed roundNumber, uint256 rollover);
96
79
 
97
- // ==================== MODIFIERS ====================
98
-
99
80
  modifier onlyOwner() {
100
81
  require(msg.sender == owner, "Only owner");
101
82
  _;
102
83
  }
103
84
 
104
- // ==================== CONSTRUCTOR ====================
105
-
106
- /// @notice Creates a new encrypted lottery
107
- /// @param _ticketPrice Price per ticket in wei
108
- /// @param _duration Duration in seconds
109
85
  constructor(uint256 _ticketPrice, uint256 _duration) {
110
86
  require(_ticketPrice > 0, "Ticket price must be > 0");
111
87
  require(_duration > 0, "Duration must be > 0");
@@ -117,9 +93,7 @@ contract EncryptedLottery is ZamaEthereumConfig {
117
93
  roundNumber = 1;
118
94
  }
119
95
 
120
- // ==================== TICKET PURCHASE ====================
121
-
122
- /// @notice Purchase a lottery ticket with an encrypted number
96
+ /// @notice Purchase a lottery ticket with encrypted number
123
97
  /// @param encryptedNumber Your encrypted ticket number
124
98
  /// @param inputProof Proof validating the encrypted input
125
99
  function buyTicket(
@@ -130,7 +104,7 @@ contract EncryptedLottery is ZamaEthereumConfig {
130
104
  require(block.timestamp < endTime, "Lottery ended");
131
105
  require(msg.value >= ticketPrice, "Insufficient payment");
132
106
 
133
- // 🔐 Convert external encrypted input
107
+ // Convert and store encrypted ticket number
134
108
  euint64 ticketNumber = FHE.fromExternal(encryptedNumber, inputProof);
135
109
 
136
110
  // ✅ Grant contract permission
@@ -146,8 +120,6 @@ contract EncryptedLottery is ZamaEthereumConfig {
146
120
  emit TicketPurchased(msg.sender, ticketIndex);
147
121
  }
148
122
 
149
- // ==================== DRAWING ====================
150
-
151
123
  /// @notice Start the drawing process
152
124
  /// @dev Only owner can call after lottery ends
153
125
  function startDrawing() external onlyOwner {
@@ -261,9 +233,6 @@ contract EncryptedLottery is ZamaEthereumConfig {
261
233
  // prizePool carries over if no winner
262
234
  }
263
235
 
264
- // ==================== VIEW FUNCTIONS ====================
265
-
266
- /// @notice Get total number of tickets sold
267
236
  function getTicketCount() external view returns (uint256) {
268
237
  return _tickets.length;
269
238
  }
@@ -13,23 +13,11 @@ import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
13
13
  /**
14
14
  * @notice Encrypted Poker - Texas Hold'em with hidden hole cards!
15
15
  *
16
- * @dev Demonstrates multi-player FHE game mechanics:
17
- * - Each player's hole cards remain encrypted until showdown
18
- * - Hand strength computed via FHE without revealing cards
19
- * - Winner determined by encrypted comparison
20
- * - Only winning hand revealed, loser's cards stay private
21
- *
22
- * Simplified rules for demo:
23
- * - 2 players (heads-up)
24
- * - Cards encoded as 1-13 (Ace=1, King=13)
25
- * - Hand strength = card1 + card2 (simplified for demo)
26
- * - Higher total wins
27
- *
28
- * ⚠️ IMPORTANT: Production poker would need proper hand rankings!
16
+ * @dev Flow: joinGame() bet()/fold() → showdown() → revealWinner()
17
+ * Hand strength = card1 + card2 (simplified for demo)
18
+ * ⚠️ Production needs proper hand rankings (flush, straight, etc.)
29
19
  */
30
20
  contract EncryptedPoker is ZamaEthereumConfig {
31
- // ==================== TYPES ====================
32
-
33
21
  enum GameState {
34
22
  WaitingForPlayers, // Waiting for 2 players
35
23
  CardsDealt, // Both players have cards
@@ -47,8 +35,6 @@ contract EncryptedPoker is ZamaEthereumConfig {
47
35
  bool folded;
48
36
  }
49
37
 
50
- // ==================== STATE ====================
51
-
52
38
  /// Game state
53
39
  GameState public state;
54
40
 
@@ -70,8 +56,6 @@ contract EncryptedPoker is ZamaEthereumConfig {
70
56
  /// Encrypted comparison result (true if player 0 wins)
71
57
  ebool private _player0Wins;
72
58
 
73
- // ==================== EVENTS ====================
74
-
75
59
  /// @notice Emitted when a player joins
76
60
  /// @param player Address of joining player
77
61
  /// @param seat Seat number (0 or 1)
@@ -97,8 +81,6 @@ contract EncryptedPoker is ZamaEthereumConfig {
97
81
  /// @param pot Total pot won
98
82
  event GameWon(address indexed winner, uint256 pot);
99
83
 
100
- // ==================== CONSTRUCTOR ====================
101
-
102
84
  /// @notice Creates a new poker game
103
85
  /// @param _minBet Minimum bet amount in wei
104
86
  constructor(uint256 _minBet) {
@@ -108,8 +90,6 @@ contract EncryptedPoker is ZamaEthereumConfig {
108
90
  state = GameState.WaitingForPlayers;
109
91
  }
110
92
 
111
- // ==================== JOIN GAME ====================
112
-
113
93
  /// @notice Join the game with encrypted hole cards
114
94
  /// @param encCard1 First encrypted card (1-13)
115
95
  /// @param encCard2 Second encrypted card (1-13)
@@ -173,8 +153,6 @@ contract EncryptedPoker is ZamaEthereumConfig {
173
153
  emit PlayerJoined(msg.sender, seat);
174
154
  }
175
155
 
176
- // ==================== BETTING ====================
177
-
178
156
  /// @notice Place a bet
179
157
  function bet() external payable {
180
158
  require(
@@ -220,8 +198,6 @@ contract EncryptedPoker is ZamaEthereumConfig {
220
198
  emit GameWon(winner, winnings);
221
199
  }
222
200
 
223
- // ==================== SHOWDOWN ====================
224
-
225
201
  /// @notice Initiate showdown - compare hands using FHE
226
202
  function showdown() external {
227
203
  require(
@@ -276,8 +252,6 @@ contract EncryptedPoker is ZamaEthereumConfig {
276
252
  emit GameWon(winner, winnings);
277
253
  }
278
254
 
279
- // ==================== RESET ====================
280
-
281
255
  /// @notice Reset for a new game
282
256
  function resetGame() external {
283
257
  require(state == GameState.Finished, "Game not finished");
@@ -290,8 +264,6 @@ contract EncryptedPoker is ZamaEthereumConfig {
290
264
  gameId++;
291
265
  }
292
266
 
293
- // ==================== VIEW FUNCTIONS ====================
294
-
295
267
  /// @notice Get game info
296
268
  function getGameInfo()
297
269
  external
@@ -327,8 +299,6 @@ contract EncryptedPoker is ZamaEthereumConfig {
327
299
  return (_players[seat].card1, _players[seat].card2);
328
300
  }
329
301
 
330
- // ==================== INTERNAL ====================
331
-
332
302
  function _getSeat(address player) internal view returns (uint8) {
333
303
  if (_players[0].addr == player) return 0;
334
304
  if (_players[1].addr == player) return 1;
@@ -1,39 +1,23 @@
1
1
  // SPDX-License-Identifier: BSD-3-Clause-Clear
2
2
  pragma solidity ^0.8.24;
3
3
 
4
- import {
5
- FHE,
6
- euint8,
7
- ebool,
8
- externalEuint8
9
- } from "@fhevm/solidity/lib/FHE.sol";
4
+ import {FHE, euint8, ebool, externalEuint8} from "@fhevm/solidity/lib/FHE.sol";
10
5
  import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
11
6
 
12
7
  /**
13
- * @notice Rock-Paper-Scissors game with encrypted moves - fair play guaranteed!
14
- *
15
- * @dev Demonstrates FHE commit-reveal pattern without trusted third party:
16
- * - Players submit encrypted moves (0=Rock, 1=Paper, 2=Scissors)
17
- * - FHE comparison determines winner without revealing moves
18
- * - Loser's move revealed only after game concludes
19
- *
20
- * Move encoding: 0 = Rock, 1 = Paper, 2 = Scissors
21
- * Win logic: (move1 - move2 + 3) % 3 → 1 = player1 wins, 2 = player2 wins
22
- *
23
- * ⚠️ IMPORTANT: Uses FHE.rem for modulo - computationally expensive but secure
8
+ * @notice Rock-Paper-Scissors game with encrypted moves - fair play guaranteed using FHE!
9
+
10
+ * @dev Commit-reveal pattern without trusted third party.
11
+ * Move encoding: 0=Rock, 1=Paper, 2=Scissors
12
+ * Gas: FHE.rem() is computationally expensive (~300k gas)
24
13
  */
25
14
  contract RockPaperScissors is ZamaEthereumConfig {
26
- // ==================== TYPES ====================
27
-
28
15
  enum GameState {
29
16
  WaitingForPlayers, // 0 or 1 player joined
30
- BothMoved, // Both players submitted moves
31
- Revealed // Winner determined and revealed
17
+ BothMoved, // Both players submitted moves
18
+ Revealed // Winner determined and revealed
32
19
  }
33
20
 
34
- // ==================== STATE ====================
35
-
36
- /// Player 1 address
37
21
  address public player1;
38
22
 
39
23
  /// Player 2 address
@@ -52,9 +36,7 @@ contract RockPaperScissors is ZamaEthereumConfig {
52
36
  /// Game ID for tracking multiple games
53
37
  uint256 public gameId;
54
38
 
55
- // ==================== EVENTS ====================
56
-
57
- /// @notice Emitted when a player joins
39
+ /// Emitted when a player joins
58
40
  /// @param player Address of joining player
59
41
  /// @param playerNumber 1 or 2
60
42
  event PlayerJoined(address indexed player, uint8 playerNumber);
@@ -67,34 +49,29 @@ contract RockPaperScissors is ZamaEthereumConfig {
67
49
  /// @param gameId Current game ID
68
50
  event GameResult(address indexed winner, uint256 indexed gameId);
69
51
 
70
- // ==================== CONSTRUCTOR ====================
71
-
72
- /// @notice Creates a new Rock-Paper-Scissors game
73
52
  constructor() {
74
53
  gameId = 1;
75
54
  state = GameState.WaitingForPlayers;
76
55
  }
77
56
 
78
- // ==================== PLAY FUNCTIONS ====================
79
-
80
57
  /// @notice Submit an encrypted move to play
81
58
  /// @dev Move must be 0 (Rock), 1 (Paper), or 2 (Scissors)
82
- /// @param encryptedMove Encrypted move value (0-2)
83
59
  /// @param inputProof Proof validating the encrypted input
84
60
  function play(
85
61
  externalEuint8 encryptedMove,
86
62
  bytes calldata inputProof
87
63
  ) external {
88
- require(state == GameState.WaitingForPlayers, "Game not accepting moves");
64
+ require(
65
+ state == GameState.WaitingForPlayers,
66
+ "Game not accepting moves"
67
+ );
89
68
  require(
90
69
  msg.sender != player1 && msg.sender != player2,
91
70
  "Already in this game"
92
71
  );
93
72
 
94
- // 🔐 Convert external encrypted input to internal euint8
73
+ // Convert and validate encrypted move
95
74
  euint8 move = FHE.fromExternal(encryptedMove, inputProof);
96
-
97
- // ✅ Grant contract permission to operate on this value
98
75
  FHE.allowThis(move);
99
76
 
100
77
  if (player1 == address(0)) {
@@ -117,31 +94,25 @@ contract RockPaperScissors is ZamaEthereumConfig {
117
94
  function determineWinner() external {
118
95
  require(state == GameState.BothMoved, "Not ready to determine winner");
119
96
 
120
- // 🎯 Winner calculation using FHE
121
- // Formula: (move1 - move2 + 3) % 3
122
- // Result: 0 = tie, 1 = player1 wins, 2 = player2 wins
123
-
124
- // Convert moves to computation: add 3 to avoid negative numbers
125
- // move1 + 3 - move2 = (move1 - move2 + 3)
126
- euint8 diff = FHE.add(FHE.add(_move1, FHE.asEuint8(3)), FHE.neg(_move2));
97
+ // Winner calculation: (move1 - move2 + 3) % 3
98
+ // 0=tie, 1=player1 wins, 2=player2 wins
99
+ euint8 diff = FHE.add(
100
+ FHE.add(_move1, FHE.asEuint8(3)),
101
+ FHE.neg(_move2)
102
+ );
127
103
 
128
- // Modulo 3 to get result (0, 1, or 2)
104
+ // 🎲 Why rem? Modulo keeps result in 0-2 range (tie/p1 wins/p2 wins)
105
+ // ⚡ rem is expensive (~300k gas) - consider alternatives for production
129
106
  euint8 result = FHE.rem(diff, 3);
130
107
 
131
- // 🔍 Check outcomes
108
+ // Compare results to determine outcome
132
109
  ebool isTie = FHE.eq(result, FHE.asEuint8(0));
133
110
  ebool player1Wins = FHE.eq(result, FHE.asEuint8(1));
134
111
 
135
- // 📊 Encode winner as address bits (simplified for demo)
136
- // In production, use public decryption pattern
137
-
138
- // Make result publicly decryptable
112
+ // 🌐 Why makePubliclyDecryptable? Anyone can decrypt result with KMS proof
139
113
  FHE.allowThis(result);
140
114
  FHE.makePubliclyDecryptable(result);
141
115
 
142
- // Store encrypted result for later reveal
143
- // For this demo, we'll use select to pick winner
144
-
145
116
  state = GameState.Revealed;
146
117
 
147
118
  emit GameResult(address(0), gameId); // Placeholder - real winner after decryption
@@ -157,7 +128,10 @@ contract RockPaperScissors is ZamaEthereumConfig {
157
128
  require(state == GameState.Revealed, "Game not ready for reveal");
158
129
 
159
130
  // Build ciphertext list for verification
160
- euint8 diff = FHE.add(FHE.add(_move1, FHE.asEuint8(3)), FHE.neg(_move2));
131
+ euint8 diff = FHE.add(
132
+ FHE.add(_move1, FHE.asEuint8(3)),
133
+ FHE.neg(_move2)
134
+ );
161
135
  euint8 result = FHE.rem(diff, 3);
162
136
 
163
137
  bytes32[] memory cts = new bytes32[](1);
@@ -193,16 +167,17 @@ contract RockPaperScissors is ZamaEthereumConfig {
193
167
  gameId++;
194
168
  }
195
169
 
196
- // ==================== VIEW FUNCTIONS ====================
197
-
198
- /// @notice Get current game state
199
- function getGameState() external view returns (
200
- address p1,
201
- address p2,
202
- GameState currentState,
203
- address currentWinner,
204
- uint256 currentGameId
205
- ) {
170
+ function getGameState()
171
+ external
172
+ view
173
+ returns (
174
+ address p1,
175
+ address p2,
176
+ GameState currentState,
177
+ address currentWinner,
178
+ uint256 currentGameId
179
+ )
180
+ {
206
181
  return (player1, player2, state, winner, gameId);
207
182
  }
208
183
 
@@ -12,19 +12,17 @@ import {
12
12
  } from "@openzeppelin/confidential-contracts/interfaces/IERC7984.sol";
13
13
 
14
14
  /**
15
- * @notice Linear vesting wallet for ERC7984 tokens - amounts stay encrypted!
16
- *
17
- * @dev Timeline: |--START--|---VESTING---|--END--|
18
- * 0% linear 100%
19
- *
20
- * All vesting calculations are performed on encrypted values using FHE operations.
15
+ * @notice Linear vesting wallet for ERC7984 tokens with fully encrypted amounts and schedules.
16
+
17
+ * @dev Timeline: |--START--|---VESTING---|--END--| (0% → linear → 100%)
18
+ * All vesting calculations performed on encrypted values using FHE.
19
+ * ⚡ Gas: FHE.div/mul operations are expensive (~200k gas each)
21
20
  */
22
21
  contract VestingWalletExample is
23
22
  Ownable,
24
23
  ReentrancyGuardTransient,
25
24
  ZamaEthereumConfig
26
25
  {
27
- // 🔐 Track released amounts per token (encrypted)
28
26
  mapping(address token => euint128) private _tokenReleased;
29
27
  uint64 private _start;
30
28
  uint64 private _duration;
@@ -50,8 +48,6 @@ contract VestingWalletExample is
50
48
  _duration = durationSeconds;
51
49
  }
52
50
 
53
- // ==================== VIEW FUNCTIONS ====================
54
-
55
51
  function start() public view virtual returns (uint64) {
56
52
  return _start;
57
53
  }
@@ -77,9 +73,7 @@ contract VestingWalletExample is
77
73
  euint128 vestedAmount_ = vestedAmount(token, uint48(block.timestamp));
78
74
  euint128 releasedAmount = released(token);
79
75
 
80
- // 🔀 FHE.select: encrypted if-else
81
- // If vested >= released: return (vested - released)
82
- // Else: return 0
76
+ // Encrypted comparison: if vested >= released → return difference, else 0
83
77
  ebool canRelease = FHE.ge(vestedAmount_, releasedAmount);
84
78
  return
85
79
  FHE.select(
@@ -89,11 +83,10 @@ contract VestingWalletExample is
89
83
  );
90
84
  }
91
85
 
92
- /// @notice Release vested tokens to beneficiary
93
86
  function release(address token) public virtual nonReentrant {
94
87
  euint64 amount = releasable(token);
95
88
 
96
- // Transfer encrypted amount to owner
89
+ // Transfer encrypted amount using allowTransient (cheaper!)
97
90
  FHE.allowTransient(amount, token);
98
91
  euint64 amountSent = IERC7984(token).confidentialTransfer(
99
92
  owner(),
@@ -122,8 +115,6 @@ contract VestingWalletExample is
122
115
  return _vestingSchedule(totalAllocation, timestamp);
123
116
  }
124
117
 
125
- // ==================== INTERNAL ====================
126
-
127
118
  /// @dev Linear vesting: (total * elapsed) / duration
128
119
  function _vestingSchedule(
129
120
  euint128 totalAllocation,
@@ -136,7 +127,7 @@ contract VestingWalletExample is
136
127
  // After end: 100% vested
137
128
  return totalAllocation;
138
129
  } else {
139
- // During vesting: linear unlock
130
+ // Gas warning: FHE.mul + FHE.div cost ~400k gas combined!
140
131
  return
141
132
  FHE.div(
142
133
  FHE.mul(totalAllocation, (timestamp - start())),
@@ -12,6 +12,18 @@ export declare function cleanupTemplate(outputDir: string): void;
12
12
  * Generates a deploy script for a contract
13
13
  */
14
14
  export declare function generateDeployScript(contractName: string): string;
15
+ /**
16
+ * Extracts FHE function names used in contract
17
+ */
18
+ export declare function extractFHEFunctions(contractContent: string): string[];
19
+ /**
20
+ * Extracts FHE types used in contract (from imports and declarations)
21
+ */
22
+ export declare function extractFHETypes(contractContent: string): string[];
23
+ /**
24
+ * Generates FHE API Reference markdown section (collapsible format)
25
+ */
26
+ export declare function generateFHEApiSection(functions: string[], types: string[]): string;
15
27
  /**
16
28
  * Generates GitBook-compatible markdown documentation
17
29
  */
@@ -1 +1 @@
1
- {"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../../scripts/shared/generators.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAuDvD;AAMD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAkCjE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,MAAM,CA2BR;AAMD;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,EACpB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACvC,IAAI,CAiBN;AAMD;;GAEG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CA+BjB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA2B/C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAchE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA4B1D"}
1
+ {"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../../scripts/shared/generators.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAuDvD;AAMD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAkCjE;AAgFD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,EAAE,CAUrE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,EAAE,CASjE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EAAE,EACnB,KAAK,EAAE,MAAM,EAAE,GACd,MAAM,CAwBR;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,MAAM,CAgCR;AAMD;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,EACpB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACvC,IAAI,CAiBN;AAMD;;GAEG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CAgCjB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA4B/C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAchE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA4B1D"}
@@ -41,6 +41,9 @@ var __importStar = (this && this.__importStar) || (function () {
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.cleanupTemplate = cleanupTemplate;
43
43
  exports.generateDeployScript = generateDeployScript;
44
+ exports.extractFHEFunctions = extractFHEFunctions;
45
+ exports.extractFHETypes = extractFHETypes;
46
+ exports.generateFHEApiSection = generateFHEApiSection;
44
47
  exports.generateGitBookMarkdown = generateGitBookMarkdown;
45
48
  exports.updateProjectPackageJson = updateProjectPackageJson;
46
49
  exports.runCommand = runCommand;
@@ -140,6 +143,121 @@ func.id = "deploy_${contractName.toLowerCase()}";
140
143
  func.tags = ["${contractName}"];
141
144
  `;
142
145
  }
146
+ // =============================================================================
147
+ // FHE API Reference (from @fhevm/solidity)
148
+ // =============================================================================
149
+ /** FHE Library Functions with developer-friendly descriptions */
150
+ const FHE_FUNCTION_DESCRIPTIONS = {
151
+ // Type Conversion & Initialization
152
+ asEbool: "Encrypts a plaintext boolean into ebool",
153
+ asEuint8: "Encrypts a plaintext uint8 value into euint8",
154
+ asEuint16: "Encrypts a plaintext uint16 value into euint16",
155
+ asEuint32: "Encrypts a plaintext uint32 value into euint32",
156
+ asEuint64: "Encrypts a plaintext uint64 value into euint64",
157
+ asEuint128: "Encrypts a plaintext uint128 value into euint128",
158
+ asEuint256: "Encrypts a plaintext uint256 value into euint256",
159
+ asEaddress: "Encrypts a plaintext address into eaddress",
160
+ fromExternal: "Validates and converts external encrypted input using inputProof",
161
+ isInitialized: "Checks if an encrypted value has been set (handle != 0)",
162
+ // Arithmetic Operations
163
+ add: "Homomorphic addition: result = a + b (overflow wraps)",
164
+ sub: "Homomorphic subtraction: result = a - b (underflow wraps)",
165
+ mul: "Homomorphic multiplication: result = a * b",
166
+ div: "Homomorphic division: result = a / b (plaintext divisor only)",
167
+ rem: "Homomorphic remainder: result = a % b (plaintext divisor only)",
168
+ neg: "Homomorphic negation (two's complement)",
169
+ min: "Returns smaller of two encrypted values",
170
+ max: "Returns larger of two encrypted values",
171
+ // Comparison Operations (return ebool)
172
+ eq: "Encrypted equality: returns ebool(a == b)",
173
+ ne: "Encrypted inequality: returns ebool(a != b)",
174
+ gt: "Encrypted greater-than: returns ebool(a > b)",
175
+ lt: "Encrypted less-than: returns ebool(a < b)",
176
+ ge: "Encrypted greater-or-equal: returns ebool(a >= b)",
177
+ le: "Encrypted less-or-equal: returns ebool(a <= b)",
178
+ // Bitwise Operations
179
+ and: "Homomorphic bitwise AND",
180
+ or: "Homomorphic bitwise OR",
181
+ xor: "Homomorphic bitwise XOR",
182
+ not: "Homomorphic bitwise NOT",
183
+ shl: "Homomorphic shift left",
184
+ shr: "Homomorphic shift right",
185
+ rotl: "Homomorphic rotate left",
186
+ rotr: "Homomorphic rotate right",
187
+ // Conditional Logic
188
+ select: "Encrypted if-then-else: select(cond, a, b) → returns a if true, b if false",
189
+ // Random Number Generation
190
+ randEbool: "Generates random encrypted boolean",
191
+ randEuint8: "Generates random encrypted 8-bit integer",
192
+ randEuint16: "Generates random encrypted 16-bit integer",
193
+ randEuint32: "Generates random encrypted 32-bit integer",
194
+ randEuint64: "Generates random encrypted 64-bit integer",
195
+ randEuint128: "Generates random encrypted 128-bit integer",
196
+ randEuint256: "Generates random encrypted 256-bit integer",
197
+ // Access Control
198
+ allow: "Grants PERMANENT permission for address to decrypt/use value",
199
+ allowThis: "Grants contract permission to operate on ciphertext",
200
+ allowTransient: "Grants TEMPORARY permission (expires at tx end)",
201
+ isAllowed: "Checks if address has permission to use ciphertext",
202
+ isSenderAllowed: "Checks if msg.sender has permission",
203
+ // Decryption
204
+ makePubliclyDecryptable: "Marks ciphertext for public decryption via relayer",
205
+ isPubliclyDecryptable: "Checks if ciphertext is publicly decryptable",
206
+ checkSignatures: "Verifies KMS decryption proof (reverts if invalid)",
207
+ toBytes32: "Converts encrypted handle to bytes32 for proof arrays",
208
+ // Utility
209
+ cleanTransientStorage: "Clears transient permissions (for AA bundled UserOps)",
210
+ };
211
+ /**
212
+ * Extracts FHE function names used in contract
213
+ */
214
+ function extractFHEFunctions(contractContent) {
215
+ const pattern = /FHE\.([a-zA-Z0-9]+)\s*[(<]/g;
216
+ const matches = new Set();
217
+ let match;
218
+ while ((match = pattern.exec(contractContent)) !== null) {
219
+ if (FHE_FUNCTION_DESCRIPTIONS[match[1]]) {
220
+ matches.add(match[1]);
221
+ }
222
+ }
223
+ return Array.from(matches).sort();
224
+ }
225
+ /**
226
+ * Extracts FHE types used in contract (from imports and declarations)
227
+ */
228
+ function extractFHETypes(contractContent) {
229
+ const pattern = /\b(ebool|euint(?:8|16|32|64|128|256)|eaddress|externalEbool|externalEuint(?:8|16|32|64|128|256)|externalEaddress)\b/g;
230
+ const matches = new Set();
231
+ let match;
232
+ while ((match = pattern.exec(contractContent)) !== null) {
233
+ matches.add(match[1]);
234
+ }
235
+ return Array.from(matches).sort();
236
+ }
237
+ /**
238
+ * Generates FHE API Reference markdown section (collapsible format)
239
+ */
240
+ function generateFHEApiSection(functions, types) {
241
+ if (functions.length === 0 && types.length === 0)
242
+ return "";
243
+ const totalCount = functions.length + types.length;
244
+ let section = `<details>\n`;
245
+ section += `<summary>🔐 FHE API Reference (${totalCount} items)</summary>\n\n`;
246
+ // Types
247
+ if (types.length > 0) {
248
+ section += `**Types:** ${types.map((t) => `\`${t}\``).join(" · ")}\n\n`;
249
+ }
250
+ // Functions as list
251
+ if (functions.length > 0) {
252
+ section += `**Functions:**\n`;
253
+ for (const f of functions) {
254
+ section += `- \`FHE.${f}()\` - ${FHE_FUNCTION_DESCRIPTIONS[f]}\n`;
255
+ }
256
+ section += `\n`;
257
+ }
258
+ section += `</details>\n\n`;
259
+ return section;
260
+ }
143
261
  /**
144
262
  * Generates GitBook-compatible markdown documentation
145
263
  */
@@ -151,6 +269,10 @@ function generateGitBookMarkdown(description, contractContent, testContent, cont
151
269
  markdown += `- \`.ts\` file → \`<your-project-root-dir>/test/\`\n\n`;
152
270
  markdown += `This ensures Hardhat can compile and test your contracts as expected.\n`;
153
271
  markdown += `{% endhint %}\n\n`;
272
+ // Extract and add FHE API Reference section
273
+ const fheFunctions = extractFHEFunctions(contractContent);
274
+ const fheTypes = extractFHETypes(contractContent);
275
+ markdown += generateFHEApiSection(fheFunctions, fheTypes);
154
276
  markdown += `{% tabs %}\n\n`;
155
277
  markdown += `{% tab title="${contractName}.sol" %}\n\n`;
156
278
  markdown += `\`\`\`solidity\n`;
@@ -194,7 +316,8 @@ function updateProjectPackageJson(outputDir, projectName, description, npmDepend
194
316
  */
195
317
  function runCommand(cmd, args, cwd) {
196
318
  return new Promise((resolve, reject) => {
197
- const child = (0, child_process_1.spawn)(cmd, args, {
319
+ const fullCommand = [cmd, ...args].join(" ");
320
+ const child = (0, child_process_1.spawn)(fullCommand, [], {
198
321
  cwd,
199
322
  shell: true,
200
323
  stdio: "pipe",
@@ -224,7 +347,8 @@ function runCommand(cmd, args, cwd) {
224
347
  function runCommandWithStatus(cmd, args, cwd) {
225
348
  return new Promise((resolve) => {
226
349
  let output = "";
227
- const proc = (0, child_process_1.spawn)(cmd, args, {
350
+ const fullCommand = [cmd, ...args].join(" ");
351
+ const proc = (0, child_process_1.spawn)(fullCommand, [], {
228
352
  cwd,
229
353
  shell: true,
230
354
  stdio: ["ignore", "pipe", "pipe"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fhevm-example",
3
- "version": "1.4.2",
3
+ "version": "1.4.4",
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"