create-fhevm-example 1.4.3 → 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.
@@ -10,33 +10,19 @@ import {
10
10
  import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
11
11
 
12
12
  /**
13
- * @notice Blind Auction with encrypted bids - only the winning price is revealed
14
- *
15
- * @dev Demonstrates advanced FHE patterns:
16
- * - Encrypted bid storage and comparison
17
- * - FHE.gt() and FHE.select() for finding maximum
18
- * - FHE.makePubliclyDecryptable() for revealing results
19
- * - FHE.checkSignatures() for proof verification
20
- *
21
- * Flow:
22
- * 1. Owner creates auction with end time and minimum bid
23
- * 2. Bidders submit encrypted bids (one per address)
24
- * 3. Owner ends auction → winner computed via FHE.gt/select
25
- * 4. Anyone can reveal winner after decryption proof is ready
26
- *
27
- * ⚠️ IMPORTANT: Losing bids remain encrypted forever!
13
+ * @notice Blind Auction with encrypted bids - only the winning price is revealed after bidding ends
14
+
15
+ * @dev Flow: bid() endAuction() → revealWinner()
16
+ * Uses FHE.gt/select to find winner without revealing losing bids.
17
+ * Losing bids remain encrypted forever!
28
18
  */
29
19
  contract BlindAuction is ZamaEthereumConfig {
30
- // ==================== TYPES ====================
31
-
32
20
  enum AuctionState {
33
21
  Open, // Accepting bids
34
22
  Closed, // Bidding ended, pending reveal
35
23
  Revealed // Winner revealed on-chain
36
24
  }
37
25
 
38
- // ==================== STATE ====================
39
-
40
26
  /// Auction owner (deployer)
41
27
  address public owner;
42
28
 
@@ -70,8 +56,6 @@ contract BlindAuction is ZamaEthereumConfig {
70
56
  /// Revealed winning amount (set after reveal)
71
57
  uint64 public winningAmount;
72
58
 
73
- // ==================== EVENTS ====================
74
-
75
59
  /// @notice Emitted when a new bid is placed
76
60
  /// @param bidder Address of the bidder
77
61
  event BidPlaced(address indexed bidder);
@@ -89,16 +73,12 @@ contract BlindAuction is ZamaEthereumConfig {
89
73
  /// @param amount Winning bid amount
90
74
  event WinnerRevealed(address indexed winner, uint64 amount);
91
75
 
92
- // ==================== MODIFIERS ====================
93
-
94
76
  /// @dev Restricts function to owner only
95
77
  modifier onlyOwner() {
96
78
  require(msg.sender == owner, "Only owner can call");
97
79
  _;
98
80
  }
99
81
 
100
- // ==================== CONSTRUCTOR ====================
101
-
102
82
  /// @notice Creates a new blind auction
103
83
  /// @param _endTime Unix timestamp when bidding ends
104
84
  /// @param _minimumBid Minimum bid amount (plaintext)
@@ -110,11 +90,8 @@ contract BlindAuction is ZamaEthereumConfig {
110
90
  auctionState = AuctionState.Open;
111
91
  }
112
92
 
113
- // ==================== BIDDING ====================
114
-
115
93
  /// @notice Submit an encrypted bid to the auction
116
94
  /// @dev Each address can only bid once
117
- /// @param encryptedBid The encrypted bid amount
118
95
  /// @param inputProof Proof validating the encrypted input
119
96
  function bid(
120
97
  externalEuint64 encryptedBid,
@@ -124,13 +101,11 @@ contract BlindAuction is ZamaEthereumConfig {
124
101
  require(block.timestamp < endTime, "Auction has ended");
125
102
  require(!hasBid[msg.sender], "Already placed a bid");
126
103
 
127
- // 🔐 Convert external encrypted input to internal euint64
104
+ // Convert external encrypted input to internal handle (proof verified)
128
105
  euint64 bidAmount = FHE.fromExternal(encryptedBid, inputProof);
129
-
130
- // ✅ Grant contract permission to operate on this value
131
106
  FHE.allowThis(bidAmount);
132
107
 
133
- // 📋 Store the bid
108
+ // Store bid - amount stays encrypted
134
109
  _bids[msg.sender] = bidAmount;
135
110
  hasBid[msg.sender] = true;
136
111
  bidders.push(msg.sender);
@@ -138,30 +113,24 @@ contract BlindAuction is ZamaEthereumConfig {
138
113
  emit BidPlaced(msg.sender);
139
114
  }
140
115
 
141
- // ==================== END AUCTION ====================
142
-
143
116
  /// @notice End the auction and compute the winner
117
+ /// @dev ⚡ Gas: O(n) loop with FHE.gt/select. ~200k gas per bidder!
144
118
  /// @dev Only owner can call after end time
145
119
  function endAuction() external onlyOwner {
146
120
  require(auctionState == AuctionState.Open, "Auction not open");
147
121
  require(block.timestamp >= endTime, "Auction not yet ended");
148
122
  require(bidders.length > 0, "No bids placed");
149
123
 
150
- // 🏆 Find the winning bid using encrypted comparisons
151
-
152
- // Initialize with first bidder
124
+ // Find winner using encrypted comparisons (no bids revealed!)
153
125
  euint64 currentMax = _bids[bidders[0]];
154
126
  euint64 currentWinnerIdx = FHE.asEuint64(0);
155
127
 
156
- // 🔄 Iterate through remaining bidders
157
128
  for (uint256 i = 1; i < bidders.length; i++) {
158
129
  euint64 candidateBid = _bids[bidders[i]];
159
130
 
160
- // 🔍 Compare: is candidate > currentMax?
161
- // Note: If equal, first bidder wins (no update)
131
+ // 🔀 Why select? if/else would leak which bid is higher!
132
+ // Losing bids remain encrypted forever
162
133
  ebool isGreater = FHE.gt(candidateBid, currentMax);
163
-
164
- // 🔀 Select the higher bid and its index
165
134
  currentMax = FHE.select(isGreater, candidateBid, currentMax);
166
135
  currentWinnerIdx = FHE.select(
167
136
  isGreater,
@@ -170,14 +139,12 @@ contract BlindAuction is ZamaEthereumConfig {
170
139
  );
171
140
  }
172
141
 
173
- // 📊 Check minimum bid threshold
142
+ // Check minimum bid (comparison stays encrypted)
174
143
  ebool meetsMinimum = FHE.ge(currentMax, FHE.asEuint64(minimumBid));
175
-
176
- // If no one meets minimum, winner stays at index 0 but amount becomes 0
177
144
  _winningBid = FHE.select(meetsMinimum, currentMax, FHE.asEuint64(0));
178
145
  _winnerIndex = currentWinnerIdx;
179
146
 
180
- // 🔓 Make results publicly decryptable
147
+ // Mark for public decryption via KMS relayer
181
148
  FHE.allowThis(_winningBid);
182
149
  FHE.allowThis(_winnerIndex);
183
150
  FHE.makePubliclyDecryptable(_winningBid);
@@ -189,36 +156,32 @@ contract BlindAuction is ZamaEthereumConfig {
189
156
  }
190
157
 
191
158
  /// @notice Reveal the winner with KMS decryption proof
192
- /// @dev Anyone can call with valid decryption proof
193
- /// @param abiEncodedResults ABI-encoded (uint64 amount, uint64 index)
194
- /// @param decryptionProof KMS signature proving decryption
159
+ /// @dev Anyone can call once relayer provides proof.
160
+ /// ⚠️ Order matters! cts[] must match abi.decode() order.
195
161
  function revealWinner(
196
162
  bytes memory abiEncodedResults,
197
163
  bytes memory decryptionProof
198
164
  ) external {
199
165
  require(auctionState == AuctionState.Closed, "Auction not closed");
200
166
 
201
- // 🔐 Build ciphertext list for verification
202
- // Order MUST match abiEncodedResults encoding order!
167
+ // Build handle array - order must match abi.decode() below!
203
168
  bytes32[] memory cts = new bytes32[](2);
204
169
  cts[0] = FHE.toBytes32(_winningBid);
205
170
  cts[1] = FHE.toBytes32(_winnerIndex);
206
171
 
207
- // 🔍 Verify the decryption proof (reverts if invalid)
172
+ // Verify KMS signatures (reverts if proof invalid)
208
173
  FHE.checkSignatures(cts, abiEncodedResults, decryptionProof);
209
174
 
210
- // 📤 Decode the verified results
175
+ // Decode verified plaintext results
211
176
  (uint64 revealedAmount, uint64 winnerIdx) = abi.decode(
212
177
  abiEncodedResults,
213
178
  (uint64, uint64)
214
179
  );
215
180
 
216
- // 🏆 Look up winner address
217
181
  if (revealedAmount >= minimumBid && winnerIdx < bidders.length) {
218
182
  winner = bidders[winnerIdx];
219
183
  winningAmount = revealedAmount;
220
184
  } else {
221
- // No valid winner (all bids below minimum)
222
185
  winner = address(0);
223
186
  winningAmount = 0;
224
187
  }
@@ -228,8 +191,6 @@ contract BlindAuction is ZamaEthereumConfig {
228
191
  emit WinnerRevealed(winner, winningAmount);
229
192
  }
230
193
 
231
- // ==================== VIEW FUNCTIONS ====================
232
-
233
194
  /// @notice Get the number of bidders
234
195
  function getBidderCount() external view returns (uint256) {
235
196
  return bidders.length;
@@ -12,24 +12,10 @@ import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
12
12
  /**
13
13
  * @notice Encrypted Escrow service - amounts hidden until release!
14
14
  *
15
- * @dev Demonstrates secure escrow with FHE:
16
- * - Escrow amounts remain encrypted
17
- * - Conditions verified without revealing values
18
- * - Multi-party agreement pattern
19
- * - Dispute resolution with arbiter
20
- *
21
- * Flow:
22
- * 1. Buyer creates escrow with encrypted amount
23
- * 2. Buyer deposits funds
24
- * 3. Seller delivers goods/services
25
- * 4. Buyer releases funds OR disputes
26
- * 5. Arbiter resolves disputes if needed
27
- *
28
- * ⚠️ IMPORTANT: Amount revealed only on release/refund
15
+ * @dev Flow: createEscrow() fundEscrow() → release()/requestRefund()/raiseDispute()
16
+ * Multi-party agreement with arbiter for disputes.
29
17
  */
30
18
  contract EncryptedEscrow is ZamaEthereumConfig {
31
- // ==================== TYPES ====================
32
-
33
19
  enum EscrowState {
34
20
  Created, // Escrow created, awaiting deposit
35
21
  Funded, // Funds deposited
@@ -49,8 +35,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
49
35
  uint256 deadline;
50
36
  }
51
37
 
52
- // ==================== STATE ====================
53
-
54
38
  /// Contract owner
55
39
  address public owner;
56
40
 
@@ -63,8 +47,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
63
47
  /// Arbiter fee percentage (default 1%)
64
48
  uint256 public arbiterFeePercent;
65
49
 
66
- // ==================== EVENTS ====================
67
-
68
50
  /// @notice Emitted when escrow is created
69
51
  /// @param escrowId ID of the escrow
70
52
  /// @param buyer Address of buyer
@@ -100,8 +82,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
100
82
  /// @param winner Address favored in resolution
101
83
  event DisputeResolved(uint256 indexed escrowId, address indexed winner);
102
84
 
103
- // ==================== CONSTRUCTOR ====================
104
-
105
85
  /// @notice Creates the escrow contract
106
86
  /// @param _arbiterFeePercent Fee percentage for arbiter (0-10)
107
87
  constructor(uint256 _arbiterFeePercent) {
@@ -110,8 +90,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
110
90
  arbiterFeePercent = _arbiterFeePercent;
111
91
  }
112
92
 
113
- // ==================== ESCROW CREATION ====================
114
-
115
93
  /// @notice Create a new escrow with encrypted amount
116
94
  /// @param seller Address of the seller
117
95
  /// @param arbiter Address of dispute arbiter
@@ -172,8 +150,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
172
150
  emit EscrowFunded(escrowId, msg.value);
173
151
  }
174
152
 
175
- // ==================== RELEASE / REFUND ====================
176
-
177
153
  /// @notice Release funds to seller
178
154
  /// @dev Only buyer can release after delivery
179
155
  /// @param escrowId ID of escrow to release
@@ -211,8 +187,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
211
187
  emit FundsRefunded(escrowId, escrow.buyer);
212
188
  }
213
189
 
214
- // ==================== DISPUTE RESOLUTION ====================
215
-
216
190
  /// @notice Raise a dispute
217
191
  /// @param escrowId ID of escrow
218
192
  function raiseDispute(uint256 escrowId) external {
@@ -264,8 +238,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
264
238
  emit DisputeResolved(escrowId, winner);
265
239
  }
266
240
 
267
- // ==================== VIEW FUNCTIONS ====================
268
-
269
241
  /// @notice Get escrow details
270
242
  function getEscrow(
271
243
  uint256 escrowId
@@ -5,33 +5,18 @@ import {FHE, euint64, ebool, externalEuint8} from "@fhevm/solidity/lib/FHE.sol";
5
5
  import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
6
6
 
7
7
  /**
8
- * @notice Hidden Voting with encrypted ballots and homomorphic tallying
8
+ * @notice Hidden Voting with encrypted ballots and homomorphic tallying - individual votes stay private forever!
9
9
  *
10
- * @dev Demonstrates FHE voting patterns:
11
- * - Encrypted vote submission (0 = No, 1 = Yes)
12
- * - Homomorphic addition for vote tallying
13
- * - FHE.makePubliclyDecryptable() for revealing final results
14
- * - Privacy: individual votes remain encrypted forever
15
- *
16
- * Flow:
17
- * 1. Owner creates a proposal with voting duration
18
- * 2. Eligible voters submit encrypted votes (0 or 1)
19
- * 3. Votes are homomorphically added to running totals
20
- * 4. After voting ends, owner closes and results become decryptable
21
- * 5. Anyone can reveal final Yes/No counts with valid proof
10
+ * @dev Flow: vote() closeVoting() → revealResults()
11
+ * Gas: Each vote costs ~200k gas (FHE.add + FHE.select operations)
22
12
  */
23
13
  contract HiddenVoting is ZamaEthereumConfig {
24
- // ==================== TYPES ====================
25
-
26
14
  enum VotingState {
27
15
  Active, // Accepting votes
28
16
  Closed, // Voting ended, pending reveal
29
17
  Revealed // Results revealed on-chain
30
18
  }
31
19
 
32
- // ==================== STATE ====================
33
-
34
- /// Voting owner (deployer)
35
20
  address public owner;
36
21
 
37
22
  /// Current voting state
@@ -59,9 +44,7 @@ contract HiddenVoting is ZamaEthereumConfig {
59
44
  uint64 public revealedYesVotes;
60
45
  uint64 public revealedNoVotes;
61
46
 
62
- // ==================== EVENTS ====================
63
-
64
- /// @notice Emitted when a vote is cast
47
+ /// Emitted when a vote is cast
65
48
  /// @param voter Address of the voter
66
49
  event VoteCast(address indexed voter);
67
50
 
@@ -75,19 +58,11 @@ contract HiddenVoting is ZamaEthereumConfig {
75
58
  /// @param noVotes Final No vote count
76
59
  event ResultsRevealed(uint64 yesVotes, uint64 noVotes);
77
60
 
78
- // ==================== MODIFIERS ====================
79
-
80
- /// @dev Restricts function to owner only
81
61
  modifier onlyOwner() {
82
62
  require(msg.sender == owner, "Only owner can call");
83
63
  _;
84
64
  }
85
65
 
86
- // ==================== CONSTRUCTOR ====================
87
-
88
- /// @notice Creates a new voting proposal
89
- /// @param _proposal Description of what is being voted on
90
- /// @param _durationSeconds How long voting is open
91
66
  constructor(string memory _proposal, uint256 _durationSeconds) {
92
67
  require(bytes(_proposal).length > 0, "Empty proposal");
93
68
  require(_durationSeconds > 0, "Duration must be positive");
@@ -97,18 +72,15 @@ contract HiddenVoting is ZamaEthereumConfig {
97
72
  endTime = block.timestamp + _durationSeconds;
98
73
  votingState = VotingState.Active;
99
74
 
100
- // 🔐 Initialize encrypted counters to zero
75
+ // Initialize encrypted counters
101
76
  _yesVotes = FHE.asEuint64(0);
102
77
  _noVotes = FHE.asEuint64(0);
103
78
  FHE.allowThis(_yesVotes);
104
79
  FHE.allowThis(_noVotes);
105
80
  }
106
81
 
107
- // ==================== VOTING ====================
108
-
109
- /// @notice Cast an encrypted vote
110
- /// @dev Vote must be 0 (No) or 1 (Yes). Values > 1 are treated as Yes.
111
- /// @param encryptedVote Encrypted vote (0 or 1)
82
+ /// @notice Cast an encrypted vote (0=No, 1=Yes)
83
+ /// @dev Homomorphic tallying: votes added without decryption!
112
84
  /// @param inputProof Proof validating the encrypted input
113
85
  function vote(
114
86
  externalEuint8 encryptedVote,
@@ -118,14 +90,13 @@ contract HiddenVoting is ZamaEthereumConfig {
118
90
  require(block.timestamp < endTime, "Voting has ended");
119
91
  require(!hasVoted[msg.sender], "Already voted");
120
92
 
121
- // 🔐 Convert external encrypted input
122
- // Note: Using euint8 for vote, but storing as euint64 for addition
93
+ // Convert vote and normalize to 0 or 1
123
94
  euint64 voteValue = FHE.asEuint64(
124
95
  FHE.fromExternal(encryptedVote, inputProof)
125
96
  );
126
97
 
127
- // 📊 Homomorphic vote counting
128
- // We use select to normalize: if vote > 0, count as 1 for Yes
98
+ // 🧮 Why homomorphic? Votes are tallied WITHOUT decrypting individual ballots!
99
+ // Individual votes remain private forever
129
100
  ebool isYes = FHE.gt(voteValue, FHE.asEuint64(0));
130
101
 
131
102
  // ➕ Add to Yes counter if vote is Yes (1)
@@ -136,7 +107,6 @@ contract HiddenVoting is ZamaEthereumConfig {
136
107
  );
137
108
  _yesVotes = FHE.add(_yesVotes, yesIncrement);
138
109
 
139
- // ➕ Add to No counter if vote is No (0)
140
110
  euint64 noIncrement = FHE.select(
141
111
  isYes,
142
112
  FHE.asEuint64(0),
@@ -144,26 +114,21 @@ contract HiddenVoting is ZamaEthereumConfig {
144
114
  );
145
115
  _noVotes = FHE.add(_noVotes, noIncrement);
146
116
 
147
- // ✅ Update permissions for new values
148
- FHE.allowThis(_yesVotes);
149
117
  FHE.allowThis(_noVotes);
150
118
 
151
- // 📋 Record that this address has voted
152
119
  hasVoted[msg.sender] = true;
153
120
  voterCount++;
154
121
 
155
122
  emit VoteCast(msg.sender);
156
123
  }
157
124
 
158
- // ==================== CLOSE VOTING ====================
159
-
160
- /// @notice Close voting and prepare results for decryption
125
+ /// @notice Close voting and mark results for decryption
161
126
  /// @dev Only owner can call after voting period ends
162
127
  function closeVoting() external onlyOwner {
163
128
  require(votingState == VotingState.Active, "Voting not active");
164
129
  require(block.timestamp >= endTime, "Voting not yet ended");
165
130
 
166
- // 🔓 Make results publicly decryptable
131
+ // Mark totals for public decryption via relayer
167
132
  FHE.makePubliclyDecryptable(_yesVotes);
168
133
  FHE.makePubliclyDecryptable(_noVotes);
169
134
 
@@ -182,15 +147,15 @@ contract HiddenVoting is ZamaEthereumConfig {
182
147
  ) external {
183
148
  require(votingState == VotingState.Closed, "Voting not closed");
184
149
 
185
- // 🔐 Build ciphertext list for verification
150
+ // Build handle array for signature verification
186
151
  bytes32[] memory cts = new bytes32[](2);
187
152
  cts[0] = FHE.toBytes32(_yesVotes);
188
153
  cts[1] = FHE.toBytes32(_noVotes);
189
154
 
190
- // 🔍 Verify the decryption proof (reverts if invalid)
155
+ // Verify KMS proof (reverts if invalid)
191
156
  FHE.checkSignatures(cts, abiEncodedResults, decryptionProof);
192
157
 
193
- // 📤 Decode the verified results
158
+ // Decode verified plaintext results
194
159
  (uint64 yesCount, uint64 noCount) = abi.decode(
195
160
  abiEncodedResults,
196
161
  (uint64, uint64)
@@ -203,15 +168,11 @@ contract HiddenVoting is ZamaEthereumConfig {
203
168
  emit ResultsRevealed(yesCount, noCount);
204
169
  }
205
170
 
206
- // ==================== VIEW FUNCTIONS ====================
207
-
208
- /// @notice Get encrypted Yes votes handle (after voting closed)
209
171
  function getEncryptedYesVotes() external view returns (euint64) {
210
172
  require(votingState != VotingState.Active, "Voting still active");
211
173
  return _yesVotes;
212
174
  }
213
175
 
214
- /// @notice Get encrypted No votes handle (after voting closed)
215
176
  function getEncryptedNoVotes() external view returns (euint64) {
216
177
  require(votingState != VotingState.Active, "Voting still active");
217
178
  return _noVotes;
@@ -14,22 +14,11 @@ import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
14
14
  /**
15
15
  * @notice Private KYC - verify identity without revealing personal data!
16
16
  *
17
- * @dev Demonstrates identity verification using FHE predicates:
18
- * - Users submit encrypted KYC attributes (age, country, credit score)
19
- * - Verifiers check conditions without seeing actual values
20
- * - Only boolean results revealed: "Is 18+?", "Is from allowed country?"
21
- * - Personal data never leaves encrypted form
22
- *
23
- * Verification types:
24
- * 1. Age verification: isAbove18(), isAbove21()
25
- * 2. Country check: isFromAllowedCountry()
26
- * 3. Credit score: hasCreditScoreAbove(threshold)
27
- *
28
- * ⚠️ IMPORTANT: This is a demo - production KYC needs trusted attesters!
17
+ * @dev Flow: submitKYC() verifyAge18()/verifyGoodCredit()/etc.
18
+ * Returns encrypted booleans: "Is 18+?", "Good credit?" without revealing actual values.
19
+ * ⚠️ Production KYC needs trusted attesters!
29
20
  */
30
21
  contract PrivateKYC is ZamaEthereumConfig {
31
- // ==================== TYPES ====================
32
-
33
22
  struct Identity {
34
23
  euint8 age; // 0-255 years
35
24
  euint8 countryCode; // ISO 3166-1 numeric (1-255)
@@ -38,8 +27,6 @@ contract PrivateKYC is ZamaEthereumConfig {
38
27
  uint256 verifiedAt; // Timestamp of verification
39
28
  }
40
29
 
41
- // ==================== STATE ====================
42
-
43
30
  /// Contract owner (KYC admin)
44
31
  address public owner;
45
32
 
@@ -56,8 +43,6 @@ contract PrivateKYC is ZamaEthereumConfig {
56
43
  /// Minimum credit score for "good" rating
57
44
  uint16 public constant MIN_CREDIT_GOOD = 700;
58
45
 
59
- // ==================== EVENTS ====================
60
-
61
46
  /// @notice Emitted when user submits KYC
62
47
  /// @param user Address of user
63
48
  event KYCSubmitted(address indexed user);
@@ -76,8 +61,6 @@ contract PrivateKYC is ZamaEthereumConfig {
76
61
  /// @param minAge Minimum age required
77
62
  event AgeVerificationRequested(address indexed user, uint8 minAge);
78
63
 
79
- // ==================== MODIFIERS ====================
80
-
81
64
  modifier onlyOwner() {
82
65
  require(msg.sender == owner, "Only owner");
83
66
  _;
@@ -88,8 +71,6 @@ contract PrivateKYC is ZamaEthereumConfig {
88
71
  _;
89
72
  }
90
73
 
91
- // ==================== CONSTRUCTOR ====================
92
-
93
74
  /// @notice Creates the KYC contract
94
75
  /// @param _allowedCountryCodes Initial list of allowed country codes
95
76
  constructor(uint8[] memory _allowedCountryCodes) {
@@ -101,8 +82,6 @@ contract PrivateKYC is ZamaEthereumConfig {
101
82
  }
102
83
  }
103
84
 
104
- // ==================== KYC SUBMISSION ====================
105
-
106
85
  /// @notice Submit encrypted KYC data
107
86
  /// @param encAge Encrypted age
108
87
  /// @param encCountry Encrypted country code
@@ -147,8 +126,6 @@ contract PrivateKYC is ZamaEthereumConfig {
147
126
  emit KYCRevoked(msg.sender);
148
127
  }
149
128
 
150
- // ==================== VERIFICATION FUNCTIONS ====================
151
-
152
129
  /// @notice Check if user is 18 or older
153
130
  /// @param user Address to verify
154
131
  /// @return result Encrypted boolean result
@@ -232,8 +209,6 @@ contract PrivateKYC is ZamaEthereumConfig {
232
209
  return result;
233
210
  }
234
211
 
235
- // ==================== DECRYPTABLE VERIFICATION ====================
236
-
237
212
  /// @notice Request age verification with public result
238
213
  /// @dev Makes the result publicly decryptable
239
214
  /// @param user Address to verify
@@ -252,8 +227,6 @@ contract PrivateKYC is ZamaEthereumConfig {
252
227
  return result;
253
228
  }
254
229
 
255
- // ==================== ADMIN FUNCTIONS ====================
256
-
257
230
  /// @notice Update country allowlist
258
231
  /// @param countryCode Country code to update
259
232
  /// @param allowed Whether to allow or deny
@@ -278,8 +251,6 @@ contract PrivateKYC is ZamaEthereumConfig {
278
251
  }
279
252
  }
280
253
 
281
- // ==================== VIEW FUNCTIONS ====================
282
-
283
254
  /// @notice Check if user has submitted KYC
284
255
  function hasSubmittedKYC(address user) external view returns (bool) {
285
256
  return _identities[user].isVerified;
@@ -12,24 +12,10 @@ import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
12
12
  /**
13
13
  * @notice Private Payroll system - salaries stay encrypted, only employees see their own!
14
14
  *
15
- * @dev Demonstrates confidential enterprise use case:
16
- * - Employee salaries stored encrypted
17
- * - Bulk payments without revealing individual amounts
18
- * - Each employee can decrypt only their own salary
19
- * - Total payroll visible to employer for budgeting
20
- *
21
- * Flow:
22
- * 1. Employer adds employees with encrypted salaries
23
- * 2. Employer funds the contract
24
- * 3. Employer calls payAll() to process all salaries
25
- * 4. Employees can view (decrypt) their own salary
26
- *
27
- * ⚠️ IMPORTANT: Uses cumulative encrypted sum for total payroll tracking
15
+ * @dev Flow: addEmployee() fund() → processPayment()
16
+ * Each employee can decrypt only their own salary.
28
17
  */
29
18
  contract PrivatePayroll is ZamaEthereumConfig {
30
- // ==================== STATE ====================
31
-
32
- /// Contract owner (employer)
33
19
  address public employer;
34
20
 
35
21
  /// List of employee addresses
@@ -50,9 +36,7 @@ contract PrivatePayroll is ZamaEthereumConfig {
50
36
  /// Payment period in seconds (default: 30 days)
51
37
  uint256 public paymentPeriod;
52
38
 
53
- // ==================== EVENTS ====================
54
-
55
- /// @notice Emitted when a new employee is added
39
+ /// Emitted when a new employee is added
56
40
  /// @param employee Address of the employee
57
41
  event EmployeeAdded(address indexed employee);
58
42
 
@@ -73,8 +57,6 @@ contract PrivatePayroll is ZamaEthereumConfig {
73
57
  /// @param amount Amount funded
74
58
  event ContractFunded(uint256 amount);
75
59
 
76
- // ==================== MODIFIERS ====================
77
-
78
60
  modifier onlyEmployer() {
79
61
  require(msg.sender == employer, "Only employer");
80
62
  _;
@@ -85,10 +67,6 @@ contract PrivatePayroll is ZamaEthereumConfig {
85
67
  _;
86
68
  }
87
69
 
88
- // ==================== CONSTRUCTOR ====================
89
-
90
- /// @notice Creates a new private payroll contract
91
- /// @param _paymentPeriod Time between payments in seconds
92
70
  constructor(uint256 _paymentPeriod) {
93
71
  employer = msg.sender;
94
72
  paymentPeriod = _paymentPeriod > 0 ? _paymentPeriod : 30 days;
@@ -96,8 +74,6 @@ contract PrivatePayroll is ZamaEthereumConfig {
96
74
  FHE.allowThis(_totalSalaries);
97
75
  }
98
76
 
99
- // ==================== EMPLOYEE MANAGEMENT ====================
100
-
101
77
  /// @notice Add a new employee with encrypted salary
102
78
  /// @param employee Address of the employee
103
79
  /// @param encryptedSalary Encrypted salary amount
@@ -190,8 +166,6 @@ contract PrivatePayroll is ZamaEthereumConfig {
190
166
  emit EmployeeRemoved(employee);
191
167
  }
192
168
 
193
- // ==================== PAYMENTS ====================
194
-
195
169
  /// @notice Fund the contract for payroll
196
170
  function fund() external payable onlyEmployer {
197
171
  require(msg.value > 0, "Must send funds");
@@ -231,9 +205,7 @@ contract PrivatePayroll is ZamaEthereumConfig {
231
205
  emit PaymentProcessed(employee, block.timestamp);
232
206
  }
233
207
 
234
- // ==================== VIEW FUNCTIONS ====================
235
-
236
- /// @notice Get encrypted salary handle for an employee
208
+ /// @notice Get encrypted salary handle for employee
237
209
  /// @dev Only callable by the employee themselves
238
210
  function getMySalary() external view onlyEmployee returns (euint64) {
239
211
  return _salaries[msg.sender];
@@ -276,8 +248,6 @@ contract PrivatePayroll is ZamaEthereumConfig {
276
248
  return (employees.length, address(this).balance, paymentPeriod);
277
249
  }
278
250
 
279
- // ==================== RECEIVE ====================
280
-
281
251
  /// @notice Accept ETH deposits
282
252
  receive() external payable {
283
253
  emit ContractFunded(msg.value);