create-fhevm-example 1.3.2 → 1.4.1

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 (125) hide show
  1. package/contracts/advanced/BlindAuction.sol +255 -0
  2. package/contracts/advanced/EncryptedEscrow.sol +315 -0
  3. package/contracts/advanced/HiddenVoting.sol +231 -0
  4. package/contracts/advanced/PrivateKYC.sol +309 -0
  5. package/contracts/advanced/PrivatePayroll.sol +285 -0
  6. package/contracts/basic/decryption/PublicDecryptMultipleValues.sol +160 -0
  7. package/contracts/basic/decryption/PublicDecryptSingleValue.sol +142 -0
  8. package/contracts/basic/decryption/UserDecryptMultipleValues.sol +61 -0
  9. package/contracts/basic/decryption/UserDecryptSingleValue.sol +59 -0
  10. package/contracts/basic/encryption/EncryptMultipleValues.sol +72 -0
  11. package/contracts/basic/encryption/EncryptSingleValue.sol +44 -0
  12. package/contracts/basic/encryption/FHECounter.sol +54 -0
  13. package/contracts/basic/fhe-operations/FHEAdd.sol +51 -0
  14. package/contracts/basic/fhe-operations/FHEArithmetic.sol +99 -0
  15. package/contracts/basic/fhe-operations/FHEComparison.sol +116 -0
  16. package/contracts/basic/fhe-operations/FHEIfThenElse.sol +53 -0
  17. package/contracts/concepts/FHEAccessControl.sol +94 -0
  18. package/contracts/concepts/FHEAntiPatterns.sol +329 -0
  19. package/contracts/concepts/FHEHandles.sol +128 -0
  20. package/contracts/concepts/FHEInputProof.sol +104 -0
  21. package/contracts/gaming/EncryptedLottery.sol +298 -0
  22. package/contracts/gaming/EncryptedPoker.sol +337 -0
  23. package/contracts/gaming/RockPaperScissors.sol +213 -0
  24. package/contracts/openzeppelin/ERC7984.sol +85 -0
  25. package/contracts/openzeppelin/ERC7984ERC20Wrapper.sol +43 -0
  26. package/contracts/openzeppelin/SwapERC7984ToERC20.sol +110 -0
  27. package/contracts/openzeppelin/SwapERC7984ToERC7984.sol +48 -0
  28. package/contracts/openzeppelin/VestingWallet.sol +147 -0
  29. package/contracts/openzeppelin/mocks/ERC20Mock.sol +31 -0
  30. package/dist/scripts/commands/add-mode.d.ts.map +1 -0
  31. package/dist/scripts/{add-mode.js → commands/add-mode.js} +27 -61
  32. package/dist/scripts/commands/doctor.d.ts.map +1 -0
  33. package/dist/scripts/{doctor.js → commands/doctor.js} +2 -2
  34. package/dist/scripts/commands/generate-config.d.ts.map +1 -0
  35. package/dist/scripts/{generate-config.js → commands/generate-config.js} +3 -10
  36. package/dist/scripts/commands/generate-docs.d.ts.map +1 -0
  37. package/dist/scripts/{generate-docs.js → commands/generate-docs.js} +4 -3
  38. package/dist/scripts/commands/maintenance.d.ts.map +1 -0
  39. package/dist/scripts/{maintenance.js → commands/maintenance.js} +11 -10
  40. package/dist/scripts/index.js +14 -33
  41. package/dist/scripts/{builders.d.ts → shared/builders.d.ts} +2 -2
  42. package/dist/scripts/shared/builders.d.ts.map +1 -0
  43. package/dist/scripts/{builders.js → shared/builders.js} +49 -30
  44. package/dist/scripts/{config.d.ts → shared/config.d.ts} +0 -2
  45. package/dist/scripts/shared/config.d.ts.map +1 -0
  46. package/dist/scripts/{config.js → shared/config.js} +48 -59
  47. package/dist/scripts/shared/generators.d.ts +42 -0
  48. package/dist/scripts/shared/generators.d.ts.map +1 -0
  49. package/dist/scripts/{utils.js → shared/generators.js} +34 -271
  50. package/dist/scripts/shared/ui.d.ts.map +1 -0
  51. package/dist/scripts/{ui.js → shared/ui.js} +3 -2
  52. package/dist/scripts/{utils.d.ts → shared/utils.d.ts} +4 -27
  53. package/dist/scripts/shared/utils.d.ts.map +1 -0
  54. package/dist/scripts/shared/utils.js +236 -0
  55. package/fhevm-hardhat-template/.eslintignore +26 -0
  56. package/fhevm-hardhat-template/.eslintrc.yml +21 -0
  57. package/fhevm-hardhat-template/.github/workflows/main.yml +47 -0
  58. package/fhevm-hardhat-template/.github/workflows/manual-windows.yml +28 -0
  59. package/fhevm-hardhat-template/.github/workflows/manual.yml +28 -0
  60. package/fhevm-hardhat-template/.prettierignore +25 -0
  61. package/fhevm-hardhat-template/.prettierrc.yml +15 -0
  62. package/fhevm-hardhat-template/.solcover.js +4 -0
  63. package/fhevm-hardhat-template/.solhint.json +12 -0
  64. package/fhevm-hardhat-template/.solhintignore +3 -0
  65. package/fhevm-hardhat-template/.vscode/extensions.json +3 -0
  66. package/fhevm-hardhat-template/.vscode/settings.json +9 -0
  67. package/fhevm-hardhat-template/LICENSE +33 -0
  68. package/fhevm-hardhat-template/README.md +110 -0
  69. package/fhevm-hardhat-template/contracts/FHECounter.sol +46 -0
  70. package/fhevm-hardhat-template/deploy/deploy.ts +17 -0
  71. package/fhevm-hardhat-template/hardhat.config.ts +90 -0
  72. package/fhevm-hardhat-template/package-lock.json +10405 -0
  73. package/fhevm-hardhat-template/package.json +104 -0
  74. package/fhevm-hardhat-template/tasks/FHECounter.ts +184 -0
  75. package/fhevm-hardhat-template/tasks/accounts.ts +9 -0
  76. package/fhevm-hardhat-template/test/FHECounter.ts +104 -0
  77. package/fhevm-hardhat-template/test/FHECounterSepolia.ts +104 -0
  78. package/fhevm-hardhat-template/tsconfig.json +23 -0
  79. package/package.json +11 -8
  80. package/test/advanced/BlindAuction.ts +246 -0
  81. package/test/advanced/EncryptedEscrow.ts +295 -0
  82. package/test/advanced/HiddenVoting.ts +268 -0
  83. package/test/advanced/PrivateKYC.ts +382 -0
  84. package/test/advanced/PrivatePayroll.ts +253 -0
  85. package/test/basic/decryption/PublicDecryptMultipleValues.ts +254 -0
  86. package/test/basic/decryption/PublicDecryptSingleValue.ts +264 -0
  87. package/test/basic/decryption/UserDecryptMultipleValues.ts +107 -0
  88. package/test/basic/decryption/UserDecryptSingleValue.ts +97 -0
  89. package/test/basic/encryption/EncryptMultipleValues.ts +110 -0
  90. package/test/basic/encryption/EncryptSingleValue.ts +124 -0
  91. package/test/basic/encryption/FHECounter.ts +112 -0
  92. package/test/basic/fhe-operations/FHEAdd.ts +97 -0
  93. package/test/basic/fhe-operations/FHEArithmetic.ts +161 -0
  94. package/test/basic/fhe-operations/FHEComparison.ts +167 -0
  95. package/test/basic/fhe-operations/FHEIfThenElse.ts +97 -0
  96. package/test/concepts/FHEAccessControl.ts +154 -0
  97. package/test/concepts/FHEAntiPatterns.ts +111 -0
  98. package/test/concepts/FHEHandles.ts +156 -0
  99. package/test/concepts/FHEInputProof.ts +151 -0
  100. package/test/gaming/EncryptedLottery.ts +214 -0
  101. package/test/gaming/EncryptedPoker.ts +349 -0
  102. package/test/gaming/RockPaperScissors.ts +205 -0
  103. package/test/openzeppelin/ERC7984.ts +142 -0
  104. package/test/openzeppelin/ERC7984ERC20Wrapper.ts +71 -0
  105. package/test/openzeppelin/SwapERC7984ToERC20.ts +76 -0
  106. package/test/openzeppelin/SwapERC7984ToERC7984.ts +113 -0
  107. package/test/openzeppelin/VestingWallet.ts +89 -0
  108. package/dist/scripts/add-mode.d.ts.map +0 -1
  109. package/dist/scripts/builders.d.ts.map +0 -1
  110. package/dist/scripts/config.d.ts.map +0 -1
  111. package/dist/scripts/doctor.d.ts.map +0 -1
  112. package/dist/scripts/generate-config.d.ts.map +0 -1
  113. package/dist/scripts/generate-docs.d.ts.map +0 -1
  114. package/dist/scripts/help.d.ts +0 -9
  115. package/dist/scripts/help.d.ts.map +0 -1
  116. package/dist/scripts/help.js +0 -73
  117. package/dist/scripts/maintenance.d.ts.map +0 -1
  118. package/dist/scripts/ui.d.ts.map +0 -1
  119. package/dist/scripts/utils.d.ts.map +0 -1
  120. /package/dist/scripts/{add-mode.d.ts → commands/add-mode.d.ts} +0 -0
  121. /package/dist/scripts/{doctor.d.ts → commands/doctor.d.ts} +0 -0
  122. /package/dist/scripts/{generate-config.d.ts → commands/generate-config.d.ts} +0 -0
  123. /package/dist/scripts/{generate-docs.d.ts → commands/generate-docs.d.ts} +0 -0
  124. /package/dist/scripts/{maintenance.d.ts → commands/maintenance.d.ts} +0 -0
  125. /package/dist/scripts/{ui.d.ts → shared/ui.d.ts} +0 -0
@@ -0,0 +1,112 @@
1
+ import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
2
+ import { ethers, fhevm } from "hardhat";
3
+ import { FHECounter, FHECounter__factory } from "../types";
4
+ import { expect } from "chai";
5
+ import { FhevmType } from "@fhevm/hardhat-plugin";
6
+
7
+ type Signers = {
8
+ deployer: HardhatEthersSigner;
9
+ alice: HardhatEthersSigner;
10
+ bob: HardhatEthersSigner;
11
+ };
12
+
13
+ async function deployFixture() {
14
+ const factory = (await ethers.getContractFactory(
15
+ "FHECounter"
16
+ )) as FHECounter__factory;
17
+ const fheCounterContract = (await factory.deploy()) as FHECounter;
18
+ const fheCounterContractAddress = await fheCounterContract.getAddress();
19
+
20
+ return { fheCounterContract, fheCounterContractAddress };
21
+ }
22
+
23
+ describe("FHECounter", function () {
24
+ let signers: Signers;
25
+ let fheCounterContract: FHECounter;
26
+ let fheCounterContractAddress: string;
27
+
28
+ before(async function () {
29
+ const ethSigners: HardhatEthersSigner[] = await ethers.getSigners();
30
+ signers = {
31
+ deployer: ethSigners[0],
32
+ alice: ethSigners[1],
33
+ bob: ethSigners[2],
34
+ };
35
+ });
36
+
37
+ beforeEach(async function () {
38
+ // Check whether the tests are running against an FHEVM mock environment
39
+ if (!fhevm.isMock) {
40
+ console.warn(`This hardhat test suite cannot run on Sepolia Testnet`);
41
+ this.skip();
42
+ }
43
+
44
+ ({ fheCounterContract, fheCounterContractAddress } = await deployFixture());
45
+ });
46
+
47
+ it("encrypted count should be uninitialized after deployment", async function () {
48
+ const encryptedCount = await fheCounterContract.getCount();
49
+ // Expect initial count to be bytes32(0) after deployment,
50
+ // (meaning the encrypted count value is uninitialized)
51
+ expect(encryptedCount).to.eq(ethers.ZeroHash);
52
+ });
53
+
54
+ it("increment the counter by 1", async function () {
55
+ const encryptedCountBeforeInc = await fheCounterContract.getCount();
56
+ expect(encryptedCountBeforeInc).to.eq(ethers.ZeroHash);
57
+ const clearCountBeforeInc = 0;
58
+
59
+ // Encrypt constant 1 as a euint32
60
+ const clearOne = 1;
61
+ const encryptedOne = await fhevm
62
+ .createEncryptedInput(fheCounterContractAddress, signers.alice.address)
63
+ .add32(clearOne)
64
+ .encrypt();
65
+
66
+ const tx = await fheCounterContract
67
+ .connect(signers.alice)
68
+ .increment(encryptedOne.handles[0], encryptedOne.inputProof);
69
+ await tx.wait();
70
+
71
+ const encryptedCountAfterInc = await fheCounterContract.getCount();
72
+ const clearCountAfterInc = await fhevm.userDecryptEuint(
73
+ FhevmType.euint32,
74
+ encryptedCountAfterInc,
75
+ fheCounterContractAddress,
76
+ signers.alice
77
+ );
78
+
79
+ expect(clearCountAfterInc).to.eq(clearCountBeforeInc + clearOne);
80
+ });
81
+
82
+ it("decrement the counter by 1", async function () {
83
+ // Encrypt constant 1 as a euint32
84
+ const clearOne = 1;
85
+ const encryptedOne = await fhevm
86
+ .createEncryptedInput(fheCounterContractAddress, signers.alice.address)
87
+ .add32(clearOne)
88
+ .encrypt();
89
+
90
+ // First increment by 1, count becomes 1
91
+ let tx = await fheCounterContract
92
+ .connect(signers.alice)
93
+ .increment(encryptedOne.handles[0], encryptedOne.inputProof);
94
+ await tx.wait();
95
+
96
+ // Then decrement by 1, count goes back to 0
97
+ tx = await fheCounterContract
98
+ .connect(signers.alice)
99
+ .decrement(encryptedOne.handles[0], encryptedOne.inputProof);
100
+ await tx.wait();
101
+
102
+ const encryptedCountAfterDec = await fheCounterContract.getCount();
103
+ const clearCountAfterInc = await fhevm.userDecryptEuint(
104
+ FhevmType.euint32,
105
+ encryptedCountAfterDec,
106
+ fheCounterContractAddress,
107
+ signers.alice
108
+ );
109
+
110
+ expect(clearCountAfterInc).to.eq(0);
111
+ });
112
+ });
@@ -0,0 +1,97 @@
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 { FHEAdd, FHEAdd__factory } from "../types";
11
+ import type { Signers } from "./types";
12
+
13
+ async function deployFixture() {
14
+ // Contracts are deployed using the first signer/account by default
15
+ const factory = (await ethers.getContractFactory(
16
+ "FHEAdd"
17
+ )) as FHEAdd__factory;
18
+ const fheAdd = (await factory.deploy()) as FHEAdd;
19
+ const fheAdd_address = await fheAdd.getAddress();
20
+
21
+ return { fheAdd, fheAdd_address };
22
+ }
23
+
24
+ /**
25
+ * This trivial example demonstrates the FHE encryption mechanism
26
+ * and highlights a common pitfall developers may encounter.
27
+ */
28
+ describe("FHEAdd", function () {
29
+ let contract: FHEAdd;
30
+ let contractAddress: string;
31
+ let signers: Signers;
32
+ let bob: HardhatEthersSigner;
33
+
34
+ before(async function () {
35
+ // Check whether the tests are running against an FHEVM mock environment
36
+ if (!hre.fhevm.isMock) {
37
+ throw new Error(`This hardhat test suite cannot run on Sepolia Testnet`);
38
+ }
39
+
40
+ const ethSigners: HardhatEthersSigner[] = await ethers.getSigners();
41
+ signers = { owner: ethSigners[0], alice: ethSigners[1] };
42
+ bob = ethSigners[2];
43
+ });
44
+
45
+ beforeEach(async function () {
46
+ // Deploy a new contract each time we run a new test
47
+ const deployment = await deployFixture();
48
+ contractAddress = deployment.fheAdd_address;
49
+ contract = deployment.fheAdd;
50
+ });
51
+
52
+ it("a + b should succeed", async function () {
53
+ const fhevm: HardhatFhevmRuntimeEnvironment = hre.fhevm;
54
+
55
+ let tx;
56
+
57
+ // Let's compute 80 + 123 = 203
58
+ const a = 80;
59
+ const b = 123;
60
+
61
+ // Alice encrypts and sets `a` as 80
62
+ const inputA = await fhevm
63
+ .createEncryptedInput(contractAddress, signers.alice.address)
64
+ .add8(a)
65
+ .encrypt();
66
+ tx = await contract
67
+ .connect(signers.alice)
68
+ .setA(inputA.handles[0], inputA.inputProof);
69
+ await tx.wait();
70
+
71
+ // Alice encrypts and sets `b` as 203
72
+ const inputB = await fhevm
73
+ .createEncryptedInput(contractAddress, signers.alice.address)
74
+ .add8(b)
75
+ .encrypt();
76
+ tx = await contract
77
+ .connect(signers.alice)
78
+ .setB(inputB.handles[0], inputB.inputProof);
79
+ await tx.wait();
80
+
81
+ // Why Bob has FHE permissions to execute the operation in this case ?
82
+ // See `computeAPlusB()` in `FHEAdd.sol` for a detailed answer
83
+ tx = await contract.connect(bob).computeAPlusB();
84
+ await tx.wait();
85
+
86
+ const encryptedAplusB = await contract.result();
87
+
88
+ const clearAplusB = await fhevm.userDecryptEuint(
89
+ FhevmType.euint8, // Specify the encrypted type
90
+ encryptedAplusB,
91
+ contractAddress, // The contract address
92
+ bob // The user wallet
93
+ );
94
+
95
+ expect(clearAplusB).to.equal(a + b);
96
+ });
97
+ });
@@ -0,0 +1,161 @@
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 { FHEArithmetic, FHEArithmetic__factory } from "../types";
11
+ import type { Signers } from "./types";
12
+
13
+ async function deployFixture() {
14
+ const factory = (await ethers.getContractFactory(
15
+ "FHEArithmetic"
16
+ )) as FHEArithmetic__factory;
17
+ const contract = (await factory.deploy()) as FHEArithmetic;
18
+ const contractAddress = await contract.getAddress();
19
+ return { contract, contractAddress };
20
+ }
21
+
22
+ /**
23
+ * @notice Demonstrates all FHE arithmetic operations on encrypted integers.
24
+ * Tests: add, sub, mul, div, rem, min, max
25
+ */
26
+ describe("FHEArithmetic", function () {
27
+ let contract: FHEArithmetic;
28
+ let contractAddress: string;
29
+ let signers: Signers;
30
+
31
+ before(async function () {
32
+ if (!hre.fhevm.isMock) {
33
+ throw new Error(`This hardhat test suite cannot run on Sepolia Testnet`);
34
+ }
35
+ const ethSigners: HardhatEthersSigner[] = await ethers.getSigners();
36
+ signers = { owner: ethSigners[0], alice: ethSigners[1] };
37
+ });
38
+
39
+ beforeEach(async function () {
40
+ const deployment = await deployFixture();
41
+ contractAddress = deployment.contractAddress;
42
+ contract = deployment.contract;
43
+ });
44
+
45
+ describe("Arithmetic Operations", function () {
46
+ const valueA = 100;
47
+ const valueB = 25;
48
+
49
+ beforeEach(async function () {
50
+ const fhevm: HardhatFhevmRuntimeEnvironment = hre.fhevm;
51
+
52
+ // Set encrypted values A and B
53
+ const inputA = await fhevm
54
+ .createEncryptedInput(contractAddress, signers.alice.address)
55
+ .add32(valueA)
56
+ .encrypt();
57
+ await contract
58
+ .connect(signers.alice)
59
+ .setA(inputA.handles[0], inputA.inputProof);
60
+
61
+ const inputB = await fhevm
62
+ .createEncryptedInput(contractAddress, signers.alice.address)
63
+ .add32(valueB)
64
+ .encrypt();
65
+ await contract
66
+ .connect(signers.alice)
67
+ .setB(inputB.handles[0], inputB.inputProof);
68
+ });
69
+
70
+ it("should compute addition correctly (100 + 25 = 125)", async function () {
71
+ await contract.connect(signers.alice).computeAdd();
72
+ const encrypted = await contract.getResult();
73
+
74
+ const decrypted = await hre.fhevm.userDecryptEuint(
75
+ FhevmType.euint32,
76
+ encrypted,
77
+ contractAddress,
78
+ signers.alice
79
+ );
80
+ expect(decrypted).to.equal(valueA + valueB);
81
+ });
82
+
83
+ it("should compute subtraction correctly (100 - 25 = 75)", async function () {
84
+ await contract.connect(signers.alice).computeSub();
85
+ const encrypted = await contract.getResult();
86
+
87
+ const decrypted = await hre.fhevm.userDecryptEuint(
88
+ FhevmType.euint32,
89
+ encrypted,
90
+ contractAddress,
91
+ signers.alice
92
+ );
93
+ expect(decrypted).to.equal(valueA - valueB);
94
+ });
95
+
96
+ it("should compute multiplication correctly (100 * 25 = 2500)", async function () {
97
+ await contract.connect(signers.alice).computeMul();
98
+ const encrypted = await contract.getResult();
99
+
100
+ const decrypted = await hre.fhevm.userDecryptEuint(
101
+ FhevmType.euint32,
102
+ encrypted,
103
+ contractAddress,
104
+ signers.alice
105
+ );
106
+ expect(decrypted).to.equal(valueA * valueB);
107
+ });
108
+
109
+ it("should compute division correctly (100 / 25 = 4)", async function () {
110
+ await contract.connect(signers.alice).computeDiv(valueB);
111
+ const encrypted = await contract.getResult();
112
+
113
+ const decrypted = await hre.fhevm.userDecryptEuint(
114
+ FhevmType.euint32,
115
+ encrypted,
116
+ contractAddress,
117
+ signers.alice
118
+ );
119
+ expect(decrypted).to.equal(Math.floor(valueA / valueB));
120
+ });
121
+
122
+ it("should compute remainder correctly (100 % 25 = 0)", async function () {
123
+ await contract.connect(signers.alice).computeRem(valueB);
124
+ const encrypted = await contract.getResult();
125
+
126
+ const decrypted = await hre.fhevm.userDecryptEuint(
127
+ FhevmType.euint32,
128
+ encrypted,
129
+ contractAddress,
130
+ signers.alice
131
+ );
132
+ expect(decrypted).to.equal(valueA % valueB);
133
+ });
134
+
135
+ it("should compute minimum correctly (min(100, 25) = 25)", async function () {
136
+ await contract.connect(signers.alice).computeMin();
137
+ const encrypted = await contract.getResult();
138
+
139
+ const decrypted = await hre.fhevm.userDecryptEuint(
140
+ FhevmType.euint32,
141
+ encrypted,
142
+ contractAddress,
143
+ signers.alice
144
+ );
145
+ expect(decrypted).to.equal(Math.min(valueA, valueB));
146
+ });
147
+
148
+ it("should compute maximum correctly (max(100, 25) = 100)", async function () {
149
+ await contract.connect(signers.alice).computeMax();
150
+ const encrypted = await contract.getResult();
151
+
152
+ const decrypted = await hre.fhevm.userDecryptEuint(
153
+ FhevmType.euint32,
154
+ encrypted,
155
+ contractAddress,
156
+ signers.alice
157
+ );
158
+ expect(decrypted).to.equal(Math.max(valueA, valueB));
159
+ });
160
+ });
161
+ });
@@ -0,0 +1,167 @@
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 { FHEComparison, FHEComparison__factory } from "../types";
11
+ import type { Signers } from "./types";
12
+
13
+ async function deployFixture() {
14
+ const factory = (await ethers.getContractFactory(
15
+ "FHEComparison"
16
+ )) as FHEComparison__factory;
17
+ const contract = (await factory.deploy()) as FHEComparison;
18
+ const contractAddress = await contract.getAddress();
19
+ return { contract, contractAddress };
20
+ }
21
+
22
+ /**
23
+ * @notice Demonstrates all FHE comparison operations on encrypted integers.
24
+ * Tests: eq, ne, gt, lt, ge, le, select
25
+ */
26
+ describe("FHEComparison", function () {
27
+ let contract: FHEComparison;
28
+ let contractAddress: string;
29
+ let signers: Signers;
30
+
31
+ before(async function () {
32
+ if (!hre.fhevm.isMock) {
33
+ throw new Error(`This hardhat test suite cannot run on Sepolia Testnet`);
34
+ }
35
+ const ethSigners: HardhatEthersSigner[] = await ethers.getSigners();
36
+ signers = { owner: ethSigners[0], alice: ethSigners[1] };
37
+ });
38
+
39
+ beforeEach(async function () {
40
+ const deployment = await deployFixture();
41
+ contractAddress = deployment.contractAddress;
42
+ contract = deployment.contract;
43
+ });
44
+
45
+ describe("Comparison Operations with A=100, B=25", function () {
46
+ const valueA = 100;
47
+ const valueB = 25;
48
+
49
+ beforeEach(async function () {
50
+ const fhevm: HardhatFhevmRuntimeEnvironment = hre.fhevm;
51
+
52
+ const inputA = await fhevm
53
+ .createEncryptedInput(contractAddress, signers.alice.address)
54
+ .add32(valueA)
55
+ .encrypt();
56
+ await contract
57
+ .connect(signers.alice)
58
+ .setA(inputA.handles[0], inputA.inputProof);
59
+
60
+ const inputB = await fhevm
61
+ .createEncryptedInput(contractAddress, signers.alice.address)
62
+ .add32(valueB)
63
+ .encrypt();
64
+ await contract
65
+ .connect(signers.alice)
66
+ .setB(inputB.handles[0], inputB.inputProof);
67
+ });
68
+
69
+ it("should compute equality correctly (100 == 25 is false)", async function () {
70
+ await contract.connect(signers.alice).computeEq();
71
+ const encrypted = await contract.getBoolResult();
72
+
73
+ const decrypted = await hre.fhevm.userDecryptEbool(
74
+ encrypted,
75
+ contractAddress,
76
+ signers.alice
77
+ );
78
+ expect(decrypted).to.equal(false);
79
+ });
80
+
81
+ it("should compute inequality correctly (100 != 25 is true)", async function () {
82
+ await contract.connect(signers.alice).computeNe();
83
+ const encrypted = await contract.getBoolResult();
84
+
85
+ const decrypted = await hre.fhevm.userDecryptEbool(
86
+ encrypted,
87
+ contractAddress,
88
+ signers.alice
89
+ );
90
+ expect(decrypted).to.equal(true);
91
+ });
92
+
93
+ it("should compute greater than correctly (100 > 25 is true)", async function () {
94
+ await contract.connect(signers.alice).computeGt();
95
+ const encrypted = await contract.getBoolResult();
96
+
97
+ const decrypted = await hre.fhevm.userDecryptEbool(
98
+ encrypted,
99
+ contractAddress,
100
+ signers.alice
101
+ );
102
+ expect(decrypted).to.equal(true);
103
+ });
104
+
105
+ it("should compute less than correctly (100 < 25 is false)", async function () {
106
+ await contract.connect(signers.alice).computeLt();
107
+ const encrypted = await contract.getBoolResult();
108
+
109
+ const decrypted = await hre.fhevm.userDecryptEbool(
110
+ encrypted,
111
+ contractAddress,
112
+ signers.alice
113
+ );
114
+ expect(decrypted).to.equal(false);
115
+ });
116
+
117
+ it("should compute greater or equal correctly (100 >= 25 is true)", async function () {
118
+ await contract.connect(signers.alice).computeGe();
119
+ const encrypted = await contract.getBoolResult();
120
+
121
+ const decrypted = await hre.fhevm.userDecryptEbool(
122
+ encrypted,
123
+ contractAddress,
124
+ signers.alice
125
+ );
126
+ expect(decrypted).to.equal(true);
127
+ });
128
+
129
+ it("should compute less or equal correctly (100 <= 25 is false)", async function () {
130
+ await contract.connect(signers.alice).computeLe();
131
+ const encrypted = await contract.getBoolResult();
132
+
133
+ const decrypted = await hre.fhevm.userDecryptEbool(
134
+ encrypted,
135
+ contractAddress,
136
+ signers.alice
137
+ );
138
+ expect(decrypted).to.equal(false);
139
+ });
140
+
141
+ it("should compute max via select correctly (max(100, 25) = 100)", async function () {
142
+ await contract.connect(signers.alice).computeMaxViaSelect();
143
+ const encrypted = await contract.getSelectedResult();
144
+
145
+ const decrypted = await hre.fhevm.userDecryptEuint(
146
+ FhevmType.euint32,
147
+ encrypted,
148
+ contractAddress,
149
+ signers.alice
150
+ );
151
+ expect(decrypted).to.equal(valueA);
152
+ });
153
+
154
+ it("should compute min via select correctly (min(100, 25) = 25)", async function () {
155
+ await contract.connect(signers.alice).computeMinViaSelect();
156
+ const encrypted = await contract.getSelectedResult();
157
+
158
+ const decrypted = await hre.fhevm.userDecryptEuint(
159
+ FhevmType.euint32,
160
+ encrypted,
161
+ contractAddress,
162
+ signers.alice
163
+ );
164
+ expect(decrypted).to.equal(valueB);
165
+ });
166
+ });
167
+ });
@@ -0,0 +1,97 @@
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 { FHEIfThenElse, FHEIfThenElse__factory } from "../types";
11
+ import type { Signers } from "./types";
12
+
13
+ async function deployFixture() {
14
+ // Contracts are deployed using the first signer/account by default
15
+ const factory = (await ethers.getContractFactory(
16
+ "FHEIfThenElse"
17
+ )) as FHEIfThenElse__factory;
18
+ const fheIfThenElse = (await factory.deploy()) as FHEIfThenElse;
19
+ const fheIfThenElse_address = await fheIfThenElse.getAddress();
20
+
21
+ return { fheIfThenElse, fheIfThenElse_address };
22
+ }
23
+
24
+ /**
25
+ * This trivial example demonstrates the FHE encryption mechanism
26
+ * and highlights a common pitfall developers may encounter.
27
+ */
28
+ describe("FHEIfThenElse", function () {
29
+ let contract: FHEIfThenElse;
30
+ let contractAddress: string;
31
+ let signers: Signers;
32
+ let bob: HardhatEthersSigner;
33
+
34
+ before(async function () {
35
+ // Check whether the tests are running against an FHEVM mock environment
36
+ if (!hre.fhevm.isMock) {
37
+ throw new Error(`This hardhat test suite cannot run on Sepolia Testnet`);
38
+ }
39
+
40
+ const ethSigners: HardhatEthersSigner[] = await ethers.getSigners();
41
+ signers = { owner: ethSigners[0], alice: ethSigners[1] };
42
+ bob = ethSigners[2];
43
+ });
44
+
45
+ beforeEach(async function () {
46
+ // Deploy a new contract each time we run a new test
47
+ const deployment = await deployFixture();
48
+ contractAddress = deployment.fheIfThenElse_address;
49
+ contract = deployment.fheIfThenElse;
50
+ });
51
+
52
+ it("a >= b ? a : b should succeed", async function () {
53
+ const fhevm: HardhatFhevmRuntimeEnvironment = hre.fhevm;
54
+
55
+ let tx;
56
+
57
+ // Let's compute `a >= b ? a : b`
58
+ const a = 80;
59
+ const b = 123;
60
+
61
+ // Alice encrypts and sets `a` as 80
62
+ const inputA = await fhevm
63
+ .createEncryptedInput(contractAddress, signers.alice.address)
64
+ .add8(a)
65
+ .encrypt();
66
+ tx = await contract
67
+ .connect(signers.alice)
68
+ .setA(inputA.handles[0], inputA.inputProof);
69
+ await tx.wait();
70
+
71
+ // Alice encrypts and sets `b` as 203
72
+ const inputB = await fhevm
73
+ .createEncryptedInput(contractAddress, signers.alice.address)
74
+ .add8(b)
75
+ .encrypt();
76
+ tx = await contract
77
+ .connect(signers.alice)
78
+ .setB(inputB.handles[0], inputB.inputProof);
79
+ await tx.wait();
80
+
81
+ // Why Bob has FHE permissions to execute the operation in this case ?
82
+ // See `computeAPlusB()` in `FHEAdd.sol` for a detailed answer
83
+ tx = await contract.connect(bob).computeMax();
84
+ await tx.wait();
85
+
86
+ const encryptedMax = await contract.result();
87
+
88
+ const clearMax = await fhevm.userDecryptEuint(
89
+ FhevmType.euint8, // Specify the encrypted type
90
+ encryptedMax,
91
+ contractAddress, // The contract address
92
+ bob // The user wallet
93
+ );
94
+
95
+ expect(clearMax).to.equal(a >= b ? a : b);
96
+ });
97
+ });