@inco/lightning 0.5.3 → 0.6.0

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 (34) hide show
  1. package/manifest.yaml +14 -0
  2. package/package.json +1 -1
  3. package/src/Lib.alphanet.sol +12 -6
  4. package/src/Lib.demonet.sol +12 -6
  5. package/src/Lib.devnet.sol +12 -6
  6. package/src/Lib.sol +12 -6
  7. package/src/Lib.template.sol +12 -6
  8. package/src/Lib.testnet.sol +12 -6
  9. package/src/Types.sol +2 -1
  10. package/src/libs/incoLightning_alphanet_v0_297966649.sol +12 -6
  11. package/src/libs/incoLightning_demonet_v0_863421733.sol +12 -6
  12. package/src/libs/incoLightning_devnet_v0_340846814.sol +12 -6
  13. package/src/libs/incoLightning_devnet_v1_904635675.sol +12 -6
  14. package/src/libs/incoLightning_testnet_v0_183408998.sol +12 -6
  15. package/src/lightning-parts/AccessControl/BaseAccessControlList.sol +11 -3
  16. package/src/lightning-parts/AccessControl/test/TestAdvancedAccessControl.t.sol +1 -0
  17. package/src/lightning-parts/EncryptedInput.sol +22 -6
  18. package/src/lightning-parts/EncryptedOperations.sol +6 -6
  19. package/src/lightning-parts/Fee.sol +41 -0
  20. package/src/lightning-parts/TEELifecycle.sol +138 -52
  21. package/src/lightning-parts/TEELifecycle.types.sol +9 -12
  22. package/src/lightning-parts/interfaces/IEncryptedInput.sol +3 -3
  23. package/src/lightning-parts/interfaces/IEncryptedOperations.sol +48 -1
  24. package/src/lightning-parts/test/Fee.t.sol +101 -0
  25. package/src/lightning-parts/test/HandleMetadata.t.sol +4 -3
  26. package/src/lightning-parts/test/InputsFee.t.sol +65 -0
  27. package/src/lightning-parts/test/TestDecryptionAttestationInSynchronousFlow.t.sol +1 -0
  28. package/src/test/AddTwo.sol +18 -6
  29. package/src/test/FakeIncoInfra/FakeIncoInfraBase.sol +12 -0
  30. package/src/test/FakeIncoInfra/getOpForSelector.sol +3 -1
  31. package/src/test/TEELifecycle/TEELifecycleMockTest.t.sol +2 -2
  32. package/src/test/TestAddTwo.t.sol +9 -1
  33. package/src/test/TestFakeInfra.t.sol +13 -3
  34. package/src/version/IncoLightningConfig.sol +1 -1
@@ -2,17 +2,17 @@
2
2
  pragma solidity ^0.8;
3
3
 
4
4
  import {BaseAccessControlList} from "./AccessControl/BaseAccessControlList.sol";
5
- import {EventCounter} from "./primitives/EventCounter.sol";
6
5
  import {HandleGeneration} from "./primitives/HandleGeneration.sol";
7
6
  import {euint256, ebool, eaddress, ETypes} from "../Types.sol";
8
7
  import {IEncryptedInput} from "./interfaces/IEncryptedInput.sol";
9
8
  import {HandleAlreadyExists} from "../Errors.sol";
9
+ import {Fee} from "./Fee.sol";
10
10
 
11
11
  abstract contract EncryptedInput is
12
12
  IEncryptedInput,
13
- EventCounter,
14
13
  BaseAccessControlList,
15
- HandleGeneration
14
+ HandleGeneration,
15
+ Fee
16
16
  {
17
17
  event NewInput(
18
18
  bytes32 indexed result,
@@ -26,21 +26,21 @@ abstract contract EncryptedInput is
26
26
  function newEuint256(
27
27
  bytes memory ciphertext,
28
28
  address user
29
- ) external returns (euint256 newValue) {
29
+ ) external payable returns (euint256 newValue) {
30
30
  return euint256.wrap(newInput(ciphertext, user, ETypes.Uint256));
31
31
  }
32
32
 
33
33
  function newEbool(
34
34
  bytes memory ciphertext,
35
35
  address user
36
- ) external returns (ebool newValue) {
36
+ ) external payable returns (ebool newValue) {
37
37
  return ebool.wrap(newInput(ciphertext, user, ETypes.Bool));
38
38
  }
39
39
 
40
40
  function newEaddress(
41
41
  bytes memory ciphertext,
42
42
  address user
43
- ) external returns (eaddress newValue) {
43
+ ) external payable returns (eaddress newValue) {
44
44
  return
45
45
  eaddress.wrap(
46
46
  newInput(ciphertext, user, ETypes.AddressOrUint160OrBytes20)
@@ -51,7 +51,23 @@ abstract contract EncryptedInput is
51
51
  bytes memory ciphertext,
52
52
  address user,
53
53
  ETypes inputType
54
+ ) internal paying returns (bytes32 newHandle) {
55
+ newHandle = _newInput(ciphertext, user, inputType);
56
+ }
57
+
58
+ function newInputNotPaying(
59
+ bytes memory ciphertext,
60
+ address user,
61
+ ETypes inputType
54
62
  ) internal returns (bytes32 newHandle) {
63
+ newHandle = _newInput(ciphertext, user, inputType);
64
+ }
65
+
66
+ function _newInput(
67
+ bytes memory ciphertext,
68
+ address user,
69
+ ETypes inputType
70
+ ) private returns (bytes32 newHandle) {
55
71
  newHandle = getInputHandle(ciphertext, user, msg.sender, inputType);
56
72
  // We assume that providing the same handle (which via HADU implies same plaintext, same context, and same
57
73
  // instance of encryption)
@@ -3,15 +3,15 @@ pragma solidity ^0.8;
3
3
 
4
4
  import {euint256, ebool, EOps, SenderNotAllowedForHandle, ETypes, isTypeSupported, typeToBitMask} from "../Types.sol";
5
5
  import {BaseAccessControlList} from "./AccessControl/BaseAccessControlList.sol";
6
- import {EventCounter} from "./primitives/EventCounter.sol";
7
6
  import {HandleGeneration} from "./primitives/HandleGeneration.sol";
8
7
  import {IEncryptedOperations} from "./interfaces/IEncryptedOperations.sol";
8
+ import {Fee} from "./Fee.sol";
9
9
 
10
10
  abstract contract EncryptedOperations is
11
11
  IEncryptedOperations,
12
- EventCounter,
13
12
  BaseAccessControlList,
14
- HandleGeneration
13
+ HandleGeneration,
14
+ Fee
15
15
  {
16
16
  error UnexpectedType(ETypes actual, bytes32 expectedTypes);
17
17
  error UnsupportedType(ETypes actual);
@@ -600,12 +600,12 @@ abstract contract EncryptedOperations is
600
600
 
601
601
  function eRand(
602
602
  ETypes randType
603
- ) external returns (bytes32 result) {
603
+ ) external paying payable returns (bytes32 result) {
604
604
  require(isTypeSupported(randType), UnsupportedType(randType));
605
605
 
606
606
  result = createResultHandle(
607
607
  EOps.Rand,
608
- randType,
608
+ randType,
609
609
  bytes32(randCounter++),
610
610
  bytes32(uint256(randType))
611
611
  );
@@ -620,7 +620,7 @@ abstract contract EncryptedOperations is
620
620
  function eRandBounded(
621
621
  bytes32 upperBound,
622
622
  ETypes randType
623
- ) external returns (bytes32 result) {
623
+ ) external paying payable returns (bytes32 result) {
624
624
  require(isTypeSupported(randType), UnsupportedType(randType));
625
625
  checkInput(upperBound, typeToBitMask(ETypes.Uint256));
626
626
 
@@ -0,0 +1,41 @@
1
+ // SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8;
3
+
4
+ // the fee should be modified through upgrades to limit gas cost
5
+ uint256 constant FEE = 0.0001 ether;
6
+
7
+ /// @notice Fee utils for lightning functions that require a fee
8
+ /// @dev the fee may be changed through upgrades, develop your apps accordingly!
9
+ abstract contract Fee {
10
+ error FeeNotPaid();
11
+
12
+ /// @notice the fee to pay through msg.value for inputs and randomness IT MAY CHANGE
13
+ function getFee() public pure returns (uint256) {
14
+ return FEE;
15
+ }
16
+
17
+ modifier paying() {
18
+ require(msg.value == FEE, FeeNotPaid());
19
+ _;
20
+ }
21
+
22
+ modifier payingMultiple(uint256 nbOfFees) {
23
+ require(msg.value == FEE * nbOfFees, FeeNotPaid());
24
+ _;
25
+ }
26
+
27
+ // Refund the difference between msg.value and what was actually spent
28
+ // assumes that all outflows and inflows to the contract are due to the user
29
+ // though the refund is capped at msg.value
30
+ modifier refundUnspent() {
31
+ uint256 balanceBefore = address(this).balance;
32
+ _;
33
+ uint256 balanceAfter = address(this).balance;
34
+ uint256 spent = balanceBefore > balanceAfter ? balanceBefore - balanceAfter : 0;
35
+ uint256 refund = msg.value > spent ? msg.value - spent : 0;
36
+ if (refund > 0) {
37
+ (bool success, ) = msg.sender.call{value: refund}("");
38
+ require(success, "Refund failed");
39
+ }
40
+ }
41
+ }
@@ -2,8 +2,7 @@ pragma solidity ^0.8.19;
2
2
 
3
3
  import {
4
4
  BootstrapResult,
5
- TEEVersion,
6
- TEEVersionStatus
5
+ UpgradeResult
7
6
  } from "./TEELifecycle.types.sol";
8
7
  import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
9
8
  import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
@@ -28,37 +27,53 @@ abstract contract TEELifecycle is
28
27
  OwnableUpgradeable,
29
28
  EIP712Upgradeable
30
29
  {
30
+ // Errors
31
31
  error InvalidQuoteVerifierVersion(uint16 actual, uint16 expected);
32
32
  error EmptyTcbInfo();
33
33
  error EmptyIdentity();
34
34
  error BootstrapNotComplete();
35
35
  error BootstrapAlreadyCompleted();
36
- /// @notice TEEVersionHistory must have exactly one version, please call approveNewTEEVersion first
37
- error TEEVersionHistoryInconsistent();
38
- error TEEVersionHistoryStatusIsNotPending();
36
+ /// @notice The TEE version was not found in the TEEVersionHistory
37
+ error TEEVersionNotFound();
39
38
  error InvalidReportMrAggregated();
40
- error InvalidBootstrapDataSignature();
41
- error EOASignerAlreadyInitialized();
42
39
  error InvalidReportDataSigner();
40
+ /// @notice The EIP712 signature recovered an incorrect address
41
+ error InvalidEIP712Signature();
42
+ error EOASignerAlreadyInitialized();
43
+ // @notice The EOA signer in the quote is not an existing EOA signer
44
+ error EOASignerNotFound();
45
+ // @notice The network pubkey signed by the TDX EOA is not the same as the one in the bootstrap result
46
+ error InvalidNetworkPubkey();
43
47
 
44
- event QuoteVerifierUpdated(uint16 indexed version);
45
- event TEEVersionUpdated(TEEVersion teeVersion);
48
+ // Events
49
+ // @notice A new MR_AGGREGATED has been approved
50
+ event NewTEEVersionApproved(uint256 indexed version, bytes32 indexed mrAggregated);
46
51
  event NewCovalidatorAdded(address covalidatorAddress, bytes quote);
47
52
  event BootstrapStageComplete(
48
53
  address indexed newEOASigner,
49
54
  BootstrapResult bootstrapResult
50
55
  );
56
+ // @notice Emitted to prove that an EOA has upgraded their TDX to a new
57
+ // MR_AGGREGATED. This is done by checking remote attestation of the quote
58
+ // and verifying the EIP712 signature of the bootstrap/upgrade result by
59
+ // the TDX EOA.
60
+ event EOAHasUpdatedTDX(address indexed eoaSigner, bytes32 indexed mrAggregated);
51
61
 
62
+ // Constants
52
63
  bytes32 public constant BootstrapResultStructHash =
53
64
  keccak256(bytes("BootstrapResult(bytes ecies_pubkey)"));
65
+ bytes32 public constant UpgradeResultStructHash =
66
+ keccak256(bytes("UpgradeResult(bytes network_pubkey)"));
54
67
 
55
68
  uint16 public constant QUOTE_VERIFIER_VERSION = 4;
56
69
 
57
70
  IQuoteVerifier public quoteVerifier;
58
- BootstrapResult public VerifiedBootstrapResult;
59
- bool public BootstrapComplete;
60
71
 
61
- TEEVersion[] public TEEVersionHistory;
72
+ // @notice The list of approved TEE versions, each item is the MR_AGGREGATED 32 bytes
73
+ // @dev The index of the TEE version is the version number
74
+ bytes32[] public ApprovedTEEVersions;
75
+ // @notice The Network key
76
+ // @todo rename to NetworkPubkey https://github.com/Inco-fhevm/inco-monorepo/issues/983
62
77
  bytes public ECIESPubkey;
63
78
  mapping(address => bool) public EOASigners;
64
79
 
@@ -106,10 +121,10 @@ abstract contract TEELifecycle is
106
121
  }
107
122
 
108
123
  /**
109
- * @notice Verifies the bootstrap data against the provided quote and signature
124
+ * @notice Wrapper around activateNewTEEVersion which verifies the bootstrap result and marks the new TEE version as active
110
125
  * @param bootstrapResult - The bootstrap data to verify
111
126
  * @param quote - The quote to verify against
112
- * @param signature - The signature to verify against
127
+ * @param signature - The EIP712 signature of the bootstrap result by the TDX EOA
113
128
  */
114
129
  function verifyBootstrapResult(
115
130
  BootstrapResult calldata bootstrapResult,
@@ -119,54 +134,114 @@ abstract contract TEELifecycle is
119
134
  // Make sure the bootstrap is not already complete, and that the contract owner
120
135
  // has already submitted the pending TEE MR_AGGREGATED.
121
136
  require(!isBootstrapComplete(), BootstrapAlreadyCompleted());
122
- require(TEEVersionHistory.length == 1, TEEVersionHistoryInconsistent());
123
- require(
124
- TEEVersionHistory[0].status == TEEVersionStatus.PENDING,
125
- TEEVersionHistoryStatusIsNotPending()
137
+ require(ApprovedTEEVersions.length == 1, TEEVersionNotFound());
138
+
139
+ bytes32 digest = bootstrapResultDigest(bootstrapResult);
140
+ address reportDataSigner = _verifyResultForEOA(
141
+ ApprovedTEEVersions[0],
142
+ digest,
143
+ quote,
144
+ signature
145
+ );
146
+
147
+ // For bootstrap phase, we only have one EOA signer
148
+ // So if we arrive here in code, it means that the EOA has signed the bootstrap result
149
+
150
+ // Update contract publicly viewable state
151
+ ECIESPubkey = bootstrapResult.ecies_pubkey;
152
+ EOASigners[reportDataSigner] = true;
153
+
154
+ emit BootstrapStageComplete(reportDataSigner, bootstrapResult);
155
+ }
156
+
157
+ /**
158
+ * @notice Verifies the upgrade result for a single EOA. This function does not modify any contract state.
159
+ * It simply serves as an on-chain proof that each TDX has been updated to the newest MR_AGGREGATED.
160
+ * @param upgradeResult - The upgrade data to verify
161
+ * @param quote - The quote to verify against (contains the TDX EOA)
162
+ * @param signature - The EIP712 signature of the upgrade result by the TDX EOA
163
+ */
164
+ function verifyUpgradeResult(
165
+ bytes32 newMrAggregated,
166
+ UpgradeResult calldata upgradeResult,
167
+ bytes calldata quote,
168
+ bytes calldata signature
169
+ ) public {
170
+ require(isBootstrapComplete(), BootstrapNotComplete());
171
+ // Make sure the quote's network pubkey is the same as the one in the bootstrap result
172
+ require(keccak256(ECIESPubkey) == keccak256(upgradeResult.network_pubkey), InvalidNetworkPubkey());
173
+ // Make sure the new MR_AGGREGATED has been pre-approved.
174
+ bool isApproved = _isApprovedTEEVersion(newMrAggregated);
175
+ require(isApproved, TEEVersionNotFound());
176
+
177
+ bytes32 digest = upgradeResultDigest(upgradeResult);
178
+ address reportDataSigner = _verifyResultForEOA(
179
+ newMrAggregated,
180
+ digest,
181
+ quote,
182
+ signature
126
183
  );
184
+ // Make sure the new EOA signer is an existing EOA signer
185
+ require(EOASigners[reportDataSigner], EOASignerNotFound());
186
+ }
187
+
188
+ /**
189
+ * @notice Approves a new TEE version as PENDING and updates the TEEVersionHistory.
190
+ * The new TEE version can be activated by calling verifyBootstrapResult or activateNewTEEVersion.
191
+ * @param newMrAggregated - The MR_AGGREGATED bytes of the new TEE version
192
+ * @dev This function increments the version number automatically based on the current history
193
+ */
194
+ function approveNewTEEVersion(bytes32 newMrAggregated) public onlyOwner {
195
+ ApprovedTEEVersions.push(newMrAggregated);
196
+ emit NewTEEVersionApproved(ApprovedTEEVersions.length - 1, newMrAggregated);
197
+ }
198
+
199
+ function _isApprovedTEEVersion(bytes32 newMrAggregated) internal view returns (bool) {
200
+ for (uint256 i = 0; i < ApprovedTEEVersions.length; i++) {
201
+ if (ApprovedTEEVersions[i] == newMrAggregated) {
202
+ return true;
203
+ }
204
+ }
205
+ return false;
206
+ }
127
207
 
128
- bytes32 _bootstrapResultDigest = bootstrapResultDigest(bootstrapResult);
208
+ /**
209
+ * @notice Verifies quote and signature from TDX for a single EOA. This is a shared function for bootstrap and upgrade.
210
+ * @param newMrAggregated - The MR_AGGREGATED bytes of the new TEE version
211
+ * @param resultEip712Digest - The EIP712 digest of the result to verify
212
+ * @param quote - The quote to verify against (contains the TDX EOA)
213
+ * @param signature - The EIP712 signature of the digest by the TDX EOA
214
+ * @return reportDataSigner - The address of the report data signer (i.e. the TDX EOA)
215
+ */
216
+ function _verifyResultForEOA(
217
+ bytes32 newMrAggregated,
218
+ bytes32 resultEip712Digest,
219
+ bytes calldata quote,
220
+ bytes calldata signature
221
+ ) internal onlyOwner returns (address) {
129
222
  (bool success, bytes memory output) = _verifyAndAttestOnChain(quote);
130
223
  require(success, string(output));
131
224
 
132
- bytes32 v0MrAggregated = TEEVersionHistory[0].mrAggregated;
133
-
134
225
  TD10ReportBody memory tdReport = parseTD10ReportBody(quote);
135
226
  (address reportDataSigner, bytes32 reportMrAggregated) = parseReport(
136
227
  tdReport
137
228
  );
138
229
  require(
139
- reportMrAggregated == v0MrAggregated,
230
+ reportMrAggregated == newMrAggregated,
140
231
  InvalidReportMrAggregated()
141
232
  );
142
233
  address recoveredAddress = ECDSA.recover(
143
- _bootstrapResultDigest,
234
+ resultEip712Digest,
144
235
  signature
145
236
  );
146
237
  require(
147
238
  recoveredAddress == reportDataSigner,
148
- InvalidBootstrapDataSignature()
239
+ InvalidEIP712Signature()
149
240
  );
150
241
 
151
- VerifiedBootstrapResult = bootstrapResult;
152
- TEEVersionHistory[0].status = TEEVersionStatus.ACTIVE;
153
- emit BootstrapStageComplete(reportDataSigner, bootstrapResult);
154
- ECIESPubkey = bootstrapResult.ecies_pubkey;
155
- EOASigners[reportDataSigner] = true;
156
- //TODO: update ECIES public key to ?? contract state and EOA addresses signers to the Signers contract state
157
- }
158
-
159
- /**
160
- * @notice Approves a new TEE version and updates the TEEVersionHistory
161
- * @param newMrAggregated - The MR_AGGREGATED bytes of the new TEE version
162
- * @dev This function increments the version number automatically based on the current history
163
- */
164
- function approveNewTEEVersion(bytes32 newMrAggregated) public onlyOwner {
165
- TEEVersionHistory.push(
166
- TEEVersion({mrAggregated: newMrAggregated, status: TEEVersionStatus.PENDING})
167
- );
242
+ emit EOAHasUpdatedTDX(reportDataSigner, newMrAggregated);
168
243
 
169
- emit TEEVersionUpdated(TEEVersionHistory[TEEVersionHistory.length - 1]);
244
+ return reportDataSigner;
170
245
  }
171
246
 
172
247
  /**
@@ -184,25 +259,22 @@ abstract contract TEELifecycle is
184
259
  );
185
260
  require(!EOASigners[reportDataSigner], EOASignerAlreadyInitialized());
186
261
 
187
- require(
188
- reportMrAggregated ==
189
- TEEVersionHistory[TEEVersionHistory.length - 1].mrAggregated,
190
- InvalidReportMrAggregated()
191
- );
262
+ bool isApproved = _isApprovedTEEVersion(reportMrAggregated);
263
+ require(isApproved, TEEVersionNotFound());
264
+
192
265
  require(reportDataSigner != address(0), InvalidReportDataSigner());
193
266
  emit NewCovalidatorAdded(reportDataSigner, quote);
194
267
  EOASigners[reportDataSigner] = true;
195
- //TODO: Add the new covalidator signers to the Signers contract state
196
268
  }
197
269
 
198
270
  /**
199
- * @notice Checks if the bootstrap is complete, meaning that there is an active TEE version.
271
+ * @notice Checks if the bootstrap is complete.
200
272
  * @return true if the bootstrap is complete, false otherwise
201
273
  */
202
274
  function isBootstrapComplete() public view returns (bool) {
203
- return
204
- TEEVersionHistory.length >= 1 &&
205
- TEEVersionHistory[0].status == TEEVersionStatus.ACTIVE;
275
+ // The network pubkey is set once and once only, during the bootstrap process
276
+ // So we can use the length of the network pubkey to check if the bootstrap is complete
277
+ return ECIESPubkey.length > 0;
206
278
  }
207
279
 
208
280
  /**
@@ -361,4 +433,18 @@ abstract contract TEELifecycle is
361
433
  )
362
434
  );
363
435
  }
436
+
437
+ function upgradeResultDigest(
438
+ UpgradeResult memory upgradeResult
439
+ ) public view returns (bytes32) {
440
+ return
441
+ _hashTypedDataV4(
442
+ keccak256(
443
+ abi.encode(
444
+ UpgradeResultStructHash,
445
+ keccak256(upgradeResult.network_pubkey)
446
+ )
447
+ )
448
+ );
449
+ }
364
450
  }
@@ -1,21 +1,18 @@
1
1
  // SPDX-License-Identifier: No License
2
2
  pragma solidity ^0.8.19;
3
3
 
4
+ /**
5
+ * @notice A struct representing what the TDX EOA signs during the bootstrap process.
6
+ */
4
7
  struct BootstrapResult {
8
+ // TODO: rename to network_pubkey
9
+ // https://github.com/Inco-fhevm/inco-monorepo/issues/983
5
10
  bytes ecies_pubkey;
6
11
  }
7
12
 
8
- enum TEEVersionStatus {
9
- PENDING,
10
- ACTIVE
11
- }
12
-
13
13
  /**
14
- * @notice A struct representing a TEE version. The actual version number is the index in the TEEVersionHistory array.
15
- * @param mrAggregated - The MR_AGGREGATED of the TEE version
16
- * @param status - The status of the TEE version
14
+ * @notice A struct representing what the TDX EOA signs during the upgrade process.
17
15
  */
18
- struct TEEVersion {
19
- bytes32 mrAggregated;
20
- TEEVersionStatus status;
21
- }
16
+ struct UpgradeResult {
17
+ bytes network_pubkey;
18
+ }
@@ -7,13 +7,13 @@ interface IEncryptedInput {
7
7
  function newEuint256(
8
8
  bytes memory ciphertext,
9
9
  address user
10
- ) external returns (euint256 newValue);
10
+ ) external payable returns (euint256 newValue);
11
11
  function newEbool(
12
12
  bytes memory ciphertext,
13
13
  address user
14
- ) external returns (ebool newValue);
14
+ ) external payable returns (ebool newValue);
15
15
  function newEaddress(
16
16
  bytes memory ciphertext,
17
17
  address user
18
- ) external returns (eaddress newValue);
18
+ ) external payable returns (eaddress newValue);
19
19
  }
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: No License
2
2
  pragma solidity ^0.8;
3
3
 
4
- import {euint256} from "../../Types.sol";
4
+ import {euint256, ebool, ETypes} from "../../Types.sol";
5
5
 
6
6
  interface IEncryptedOperations {
7
7
  function eAdd(
@@ -28,4 +28,51 @@ interface IEncryptedOperations {
28
28
  bytes32 lhs,
29
29
  bytes32 rhs
30
30
  ) external returns (bytes32 result);
31
+ function eBitOr(bytes32 lhs, bytes32 rhs) external returns (bytes32 result);
32
+ function eBitXor(
33
+ bytes32 lhs,
34
+ bytes32 rhs
35
+ ) external returns (bytes32 result);
36
+ function eShl(
37
+ euint256 lhs,
38
+ euint256 rhs
39
+ ) external returns (euint256 result);
40
+ function eShr(
41
+ euint256 lhs,
42
+ euint256 rhs
43
+ ) external returns (euint256 result);
44
+ function eRotl(
45
+ euint256 lhs,
46
+ euint256 rhs
47
+ ) external returns (euint256 result);
48
+ function eRotr(
49
+ euint256 lhs,
50
+ euint256 rhs
51
+ ) external returns (euint256 result);
52
+ function eEq(bytes32 lhs, bytes32 rhs) external returns (ebool result);
53
+ function eNe(bytes32 lhs, bytes32 rhs) external returns (ebool result);
54
+ function eGe(euint256 lhs, euint256 rhs) external returns (ebool result);
55
+ function eGt(euint256 lhs, euint256 rhs) external returns (ebool result);
56
+ function eLe(euint256 lhs, euint256 rhs) external returns (ebool result);
57
+ function eLt(euint256 lhs, euint256 rhs) external returns (ebool result);
58
+ function eMin(
59
+ euint256 lhs,
60
+ euint256 rhs
61
+ ) external returns (euint256 result);
62
+ function eMax(
63
+ euint256 lhs,
64
+ euint256 rhs
65
+ ) external returns (euint256 result);
66
+ function eNot(ebool operand) external returns (ebool result);
67
+ function eCast(bytes32 ct, ETypes toType) external returns (bytes32 result);
68
+ function eRand(ETypes randType) external payable returns (bytes32 result);
69
+ function eRandBounded(
70
+ bytes32 upperBound,
71
+ ETypes randType
72
+ ) external payable returns (bytes32 result);
73
+ function eIfThenElse(
74
+ ebool condition,
75
+ bytes32 ifTrue,
76
+ bytes32 ifFalse
77
+ ) external returns (bytes32 result);
31
78
  }
@@ -0,0 +1,101 @@
1
+ // SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8;
3
+
4
+ import {Test} from "forge-std/Test.sol";
5
+ import {Fee, FEE} from "../Fee.sol";
6
+
7
+ contract FeeTester is Fee {
8
+ function costOneFee() public payable paying {
9
+ // do nothing
10
+ }
11
+
12
+ function costMultipleVariableFees(
13
+ uint256 nbOfFees
14
+ ) public payable payingMultiple(nbOfFees) {
15
+ // do nothing
16
+ }
17
+
18
+ function costMultipleFixedFees() public payable payingMultiple(3) {
19
+ // do nothing
20
+ }
21
+ }
22
+
23
+ contract TestFee is Test {
24
+ FeeTester feeTester;
25
+
26
+ function setUp() public {
27
+ feeTester = new FeeTester();
28
+ }
29
+
30
+ function testGetFee() public view {
31
+ uint256 fee = feeTester.getFee();
32
+ assertEq(fee, FEE);
33
+ }
34
+
35
+ function testPaying() public {
36
+ // should fail if no fee
37
+ vm.expectRevert(Fee.FeeNotPaid.selector);
38
+ feeTester.costOneFee{value: 0}();
39
+
40
+ // should fail if not enough fee
41
+ vm.expectRevert(Fee.FeeNotPaid.selector);
42
+ feeTester.costOneFee{value: FEE - 1}();
43
+
44
+ // should fail if too much fee
45
+ vm.expectRevert(Fee.FeeNotPaid.selector);
46
+ feeTester.costOneFee{value: FEE + 1}();
47
+
48
+ // should work with exact fee
49
+ feeTester.costOneFee{value: FEE}();
50
+ }
51
+
52
+ function testPayingMultiple() public {
53
+ // should fail if no fee
54
+ vm.expectRevert(Fee.FeeNotPaid.selector);
55
+ feeTester.costMultipleVariableFees{value: 0}(3);
56
+
57
+ // should fail if not enough fee
58
+ vm.expectRevert(Fee.FeeNotPaid.selector);
59
+ feeTester.costMultipleVariableFees{value: FEE * 3 - 1}(3);
60
+
61
+ // should fail if too much fee
62
+ vm.expectRevert(Fee.FeeNotPaid.selector);
63
+ feeTester.costMultipleVariableFees{value: FEE * 3 + 1}(3);
64
+
65
+ // should work with exact fee
66
+ feeTester.costMultipleVariableFees{value: FEE * 3}(3);
67
+
68
+ // should work with exact fee for fixed number of fees
69
+ feeTester.costMultipleFixedFees{value: FEE * 3}();
70
+ }
71
+
72
+ function testPayingMultipleZero() public {
73
+ feeTester.costMultipleVariableFees{value: 0}(0);
74
+
75
+ // should fail if too much fee
76
+ vm.expectRevert(Fee.FeeNotPaid.selector);
77
+ feeTester.costMultipleVariableFees{value: FEE + 1}(0);
78
+
79
+ // should work with exact fee
80
+ feeTester.costMultipleVariableFees{value: 0}(0);
81
+ }
82
+
83
+ function testFuzzPayingMultipleVariableFees(uint8 nbOfFees) public {
84
+ uint256 expectedValue = FEE * nbOfFees;
85
+
86
+ // should work with exact fee
87
+ feeTester.costMultipleVariableFees{value: expectedValue}(nbOfFees);
88
+
89
+ // should fail if not enough fee (unless expectedValue is 0)
90
+ if (expectedValue > 0) {
91
+ vm.expectRevert(Fee.FeeNotPaid.selector);
92
+ feeTester.costMultipleVariableFees{value: expectedValue - 1}(
93
+ nbOfFees
94
+ );
95
+ }
96
+
97
+ // should fail if too much fee
98
+ vm.expectRevert(Fee.FeeNotPaid.selector);
99
+ feeTester.costMultipleVariableFees{value: expectedValue + 1}(nbOfFees);
100
+ }
101
+ }
@@ -15,6 +15,7 @@ import {
15
15
  typeToBitMask
16
16
  } from "../../Types.sol";
17
17
  import {VerifierAddressGetter} from "../primitives/VerifierAddressGetter.sol";
18
+ import {FEE} from "../Fee.sol";
18
19
 
19
20
  contract TestHandleMetadata is
20
21
  EIP712,
@@ -107,11 +108,11 @@ contract TestHandleMetadata is
107
108
  }
108
109
 
109
110
  function testEncryptedInputHandleType() public {
110
- euint256 a = this.newEuint256("ciphertext", address(this));
111
+ euint256 a = this.newEuint256{value: FEE}("ciphertext", address(this));
111
112
  assert(typeOf(euint256.unwrap(a)) == ETypes.Uint256);
112
- ebool b = this.newEbool("ciphertext", address(this));
113
+ ebool b = this.newEbool{value: FEE}("ciphertext", address(this));
113
114
  assert(typeOf(ebool.unwrap(b)) == ETypes.Bool);
114
- eaddress c = this.newEaddress("ciphertext", address(this));
115
+ eaddress c = this.newEaddress{value: FEE}("ciphertext", address(this));
115
116
  assert(typeOf(eaddress.unwrap(c)) == ETypes.AddressOrUint160OrBytes20);
116
117
  }
117
118
  }