@openzeppelin/confidential-contracts 0.2.0-rc.2 → 0.3.0-rc.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 (44) hide show
  1. package/build/contracts/Checkpoints.json +2 -2
  2. package/build/contracts/CheckpointsConfidential.json +3 -9
  3. package/build/contracts/{ConfidentialFungibleToken.json → ERC7984.json} +28 -33
  4. package/build/contracts/{ConfidentialFungibleTokenERC20Wrapper.json → ERC7984ERC20Wrapper.json} +34 -39
  5. package/build/contracts/ERC7984Freezable.json +666 -0
  6. package/build/contracts/ERC7984ObserverAccess.json +676 -0
  7. package/build/contracts/ERC7984Omnibus.json +994 -0
  8. package/build/contracts/ERC7984Restricted.json +677 -0
  9. package/build/contracts/ERC7984Rwa.json +1370 -0
  10. package/build/contracts/{ConfidentialFungibleTokenUtils.json → ERC7984Utils.json} +4 -4
  11. package/build/contracts/{ConfidentialFungibleTokenVotes.json → ERC7984Votes.json} +99 -81
  12. package/build/contracts/{TFHESafeMath.json → FHESafeMath.json} +4 -4
  13. package/build/contracts/HandleAccessManager.json +34 -0
  14. package/build/contracts/{IConfidentialFungibleToken.json → IERC7984.json} +15 -15
  15. package/build/contracts/{IConfidentialFungibleTokenReceiver.json → IERC7984Receiver.json} +2 -2
  16. package/build/contracts/IERC7984Rwa.json +797 -0
  17. package/build/contracts/VestingWalletCliffConfidential.json +3 -3
  18. package/build/contracts/VestingWalletConfidential.json +3 -3
  19. package/build/contracts/VestingWalletConfidentialFactory.json +18 -153
  20. package/build/contracts/VotesConfidential.json +23 -0
  21. package/finance/ERC7821WithExecutor.sol +2 -2
  22. package/finance/VestingWalletCliffConfidential.sol +15 -4
  23. package/finance/VestingWalletConfidential.sol +32 -20
  24. package/finance/VestingWalletConfidentialFactory.sol +34 -123
  25. package/governance/utils/VotesConfidential.sol +18 -4
  26. package/interfaces/{IConfidentialFungibleToken.sol → IERC7984.sol} +6 -6
  27. package/interfaces/{IConfidentialFungibleTokenReceiver.sol → IERC7984Receiver.sol} +3 -3
  28. package/interfaces/IERC7984Rwa.sol +64 -0
  29. package/package.json +4 -4
  30. package/token/{ConfidentialFungibleToken.sol → ERC7984/ERC7984.sol} +73 -84
  31. package/token/{extensions/ConfidentialFungibleTokenERC20Wrapper.sol → ERC7984/extensions/ERC7984ERC20Wrapper.sol} +36 -27
  32. package/token/ERC7984/extensions/ERC7984Freezable.sol +66 -0
  33. package/token/ERC7984/extensions/ERC7984ObserverAccess.sol +63 -0
  34. package/token/ERC7984/extensions/ERC7984Omnibus.sol +209 -0
  35. package/token/ERC7984/extensions/ERC7984Restricted.sol +118 -0
  36. package/token/ERC7984/extensions/ERC7984Rwa.sol +236 -0
  37. package/token/ERC7984/extensions/ERC7984Votes.sol +31 -0
  38. package/token/{utils/ConfidentialFungibleTokenUtils.sol → ERC7984/utils/ERC7984Utils.sol} +12 -12
  39. package/utils/FHESafeMath.sol +72 -0
  40. package/utils/HandleAccessManager.sol +29 -0
  41. package/utils/structs/CheckpointsConfidential.sol +1 -6
  42. package/utils/structs/temporary-Checkpoints.sol +2 -2
  43. package/token/extensions/ConfidentialFungibleTokenVotes.sol +0 -29
  44. package/utils/TFHESafeMath.sol +0 -37
@@ -1,48 +1,34 @@
1
1
  // SPDX-License-Identifier: MIT
2
- // OpenZeppelin Confidential Contracts (last updated v0.2.0-rc.2) (finance/VestingWalletConfidentialFactory.sol)
2
+ // OpenZeppelin Confidential Contracts (last updated v0.3.0-rc.0) (finance/VestingWalletConfidentialFactory.sol)
3
3
  pragma solidity ^0.8.27;
4
4
 
5
- import {FHE, euint64, externalEuint64, euint128} from "@fhevm/solidity/lib/FHE.sol";
6
- import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
5
+ import {FHE, euint64, externalEuint64} from "@fhevm/solidity/lib/FHE.sol";
7
6
  import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
8
- import {IConfidentialFungibleToken} from "./../interfaces/IConfidentialFungibleToken.sol";
9
- import {VestingWalletCliffConfidential} from "./VestingWalletCliffConfidential.sol";
7
+ import {IERC7984} from "./../interfaces/IERC7984.sol";
10
8
 
11
9
  /**
12
10
  * @dev A factory which enables batch funding of vesting wallets.
13
11
  *
14
- * The {_deployVestingWalletImplementation} and {_initializeVestingWallet} functions remain unimplemented
15
- * to allow for custom implementations of the vesting wallet to be used.
12
+ * The {_deployVestingWalletImplementation}, {_initializeVestingWallet}, and {_validateVestingWalletInitArgs}
13
+ * functions remain unimplemented to allow for custom implementations of the vesting wallet to be used.
16
14
  */
17
15
  abstract contract VestingWalletConfidentialFactory {
18
16
  struct VestingPlan {
19
- address beneficiary;
20
17
  externalEuint64 encryptedAmount;
21
- uint48 startTimestamp;
22
- uint48 durationSeconds;
23
- uint48 cliffSeconds;
18
+ bytes initArgs;
24
19
  }
25
20
 
26
21
  address private immutable _vestingImplementation;
27
22
 
23
+ /// @dev Emitted for each vesting wallet funded within a batch.
28
24
  event VestingWalletConfidentialFunded(
29
25
  address indexed vestingWalletConfidential,
30
- address indexed beneficiary,
31
- address indexed confidentialFungibleToken,
32
- euint64 encryptedAmount,
33
- uint48 startTimestamp,
34
- uint48 durationSeconds,
35
- uint48 cliffSeconds,
36
- address executor
37
- );
38
- event VestingWalletConfidentialCreated(
39
- address indexed vestingWalletConfidential,
40
- address indexed beneficiary,
41
- uint48 startTimestamp,
42
- uint48 durationSeconds,
43
- uint48 cliffSeconds,
44
- address indexed executor
26
+ address indexed token,
27
+ euint64 transferredAmount,
28
+ bytes initArgs
45
29
  );
30
+ /// @dev Emitted when a vesting wallet is deployed.
31
+ event VestingWalletConfidentialCreated(address indexed vestingWalletConfidential, bytes initArgs);
46
32
 
47
33
  constructor() {
48
34
  _vestingImplementation = _deployVestingWalletImplementation();
@@ -57,53 +43,26 @@ abstract contract VestingWalletConfidentialFactory {
57
43
  * Emits a {VestingWalletConfidentialFunded} event for each funded vesting plan.
58
44
  */
59
45
  function batchFundVestingWalletConfidential(
60
- address confidentialFungibleToken,
46
+ address token,
61
47
  VestingPlan[] calldata vestingPlans,
62
- address executor,
63
48
  bytes calldata inputProof
64
49
  ) public virtual {
65
50
  uint256 vestingPlansLength = vestingPlans.length;
66
51
  for (uint256 i = 0; i < vestingPlansLength; i++) {
67
52
  VestingPlan memory vestingPlan = vestingPlans[i];
68
- require(
69
- vestingPlan.cliffSeconds <= vestingPlan.durationSeconds,
70
- VestingWalletCliffConfidential.VestingWalletCliffConfidentialInvalidCliffDuration(
71
- vestingPlan.cliffSeconds,
72
- vestingPlan.durationSeconds
73
- )
74
- );
75
-
76
- require(vestingPlan.beneficiary != address(0), OwnableUpgradeable.OwnableInvalidOwner(address(0)));
77
- address vestingWalletAddress = predictVestingWalletConfidential(
78
- vestingPlan.beneficiary,
79
- vestingPlan.startTimestamp,
80
- vestingPlan.durationSeconds,
81
- vestingPlan.cliffSeconds,
82
- executor
83
- );
53
+ _validateVestingWalletInitArgs(vestingPlan.initArgs);
84
54
 
85
- euint64 transferredAmount;
86
- {
87
- // avoiding stack too deep with scope
88
- euint64 encryptedAmount = FHE.fromExternal(vestingPlan.encryptedAmount, inputProof);
89
- FHE.allowTransient(encryptedAmount, confidentialFungibleToken);
90
- transferredAmount = IConfidentialFungibleToken(confidentialFungibleToken).confidentialTransferFrom(
91
- msg.sender,
92
- vestingWalletAddress,
93
- encryptedAmount
94
- );
95
- }
55
+ address vestingWalletAddress = predictVestingWalletConfidential(vestingPlan.initArgs);
96
56
 
97
- emit VestingWalletConfidentialFunded(
57
+ euint64 encryptedAmount = FHE.fromExternal(vestingPlan.encryptedAmount, inputProof);
58
+ FHE.allowTransient(encryptedAmount, token);
59
+ euint64 transferredAmount = IERC7984(token).confidentialTransferFrom(
60
+ msg.sender,
98
61
  vestingWalletAddress,
99
- vestingPlan.beneficiary,
100
- confidentialFungibleToken,
101
- transferredAmount,
102
- vestingPlan.startTimestamp,
103
- vestingPlan.durationSeconds,
104
- vestingPlan.cliffSeconds,
105
- executor
62
+ encryptedAmount
106
63
  );
64
+
65
+ emit VestingWalletConfidentialFunded(vestingWalletAddress, token, transferredAmount, vestingPlan.initArgs);
107
66
  }
108
67
  }
109
68
 
@@ -112,75 +71,33 @@ abstract contract VestingWalletConfidentialFactory {
112
71
  *
113
72
  * Emits a {VestingWalletConfidentialCreated}.
114
73
  */
115
- function createVestingWalletConfidential(
116
- address beneficiary,
117
- uint48 startTimestamp,
118
- uint48 durationSeconds,
119
- uint48 cliffSeconds,
120
- address executor
121
- ) public virtual returns (address) {
74
+ function createVestingWalletConfidential(bytes calldata initArgs) public virtual returns (address) {
122
75
  // Will revert if clone already created
123
76
  address vestingWalletConfidentialAddress = Clones.cloneDeterministic(
124
77
  _vestingImplementation,
125
- _getCreate2VestingWalletConfidentialSalt(
126
- beneficiary,
127
- startTimestamp,
128
- durationSeconds,
129
- cliffSeconds,
130
- executor
131
- )
132
- );
133
- _initializeVestingWallet(
134
- vestingWalletConfidentialAddress,
135
- beneficiary,
136
- startTimestamp,
137
- durationSeconds,
138
- cliffSeconds,
139
- executor
140
- );
141
- emit VestingWalletConfidentialCreated(
142
- beneficiary,
143
- vestingWalletConfidentialAddress,
144
- startTimestamp,
145
- durationSeconds,
146
- cliffSeconds,
147
- executor
78
+ _getCreate2VestingWalletConfidentialSalt(initArgs)
148
79
  );
80
+ _initializeVestingWallet(vestingWalletConfidentialAddress, initArgs);
81
+ emit VestingWalletConfidentialCreated(vestingWalletConfidentialAddress, initArgs);
149
82
  return vestingWalletConfidentialAddress;
150
83
  }
151
84
 
152
85
  /**
153
86
  * @dev Predicts the deterministic address for a confidential vesting wallet.
154
87
  */
155
- function predictVestingWalletConfidential(
156
- address beneficiary,
157
- uint48 startTimestamp,
158
- uint48 durationSeconds,
159
- uint48 cliffSeconds,
160
- address executor
161
- ) public view virtual returns (address) {
88
+ function predictVestingWalletConfidential(bytes memory initArgs) public view virtual returns (address) {
162
89
  return
163
90
  Clones.predictDeterministicAddress(
164
91
  _vestingImplementation,
165
- _getCreate2VestingWalletConfidentialSalt(
166
- beneficiary,
167
- startTimestamp,
168
- durationSeconds,
169
- cliffSeconds,
170
- executor
171
- )
92
+ _getCreate2VestingWalletConfidentialSalt(initArgs)
172
93
  );
173
94
  }
174
95
 
96
+ /// @dev Virtual function that must be implemented to validate the initArgs bytes.
97
+ function _validateVestingWalletInitArgs(bytes memory initArgs) internal virtual;
98
+
175
99
  /// @dev Virtual function that must be implemented to initialize the vesting wallet at `vestingWalletAddress`.
176
- function _initializeVestingWallet(
177
- address vestingWalletAddress,
178
- address beneficiary,
179
- uint48 startTimestamp,
180
- uint48 durationSeconds,
181
- uint48 cliffSeconds,
182
- address executor
183
- ) internal virtual;
100
+ function _initializeVestingWallet(address vestingWalletAddress, bytes calldata initArgs) internal virtual;
184
101
 
185
102
  /**
186
103
  * @dev Internal function that is called once to deploy the vesting wallet implementation.
@@ -192,13 +109,7 @@ abstract contract VestingWalletConfidentialFactory {
192
109
  /**
193
110
  * @dev Gets create2 salt for a confidential vesting wallet.
194
111
  */
195
- function _getCreate2VestingWalletConfidentialSalt(
196
- address beneficiary,
197
- uint48 startTimestamp,
198
- uint48 durationSeconds,
199
- uint48 cliffSeconds,
200
- address executor
201
- ) internal pure virtual returns (bytes32) {
202
- return keccak256(abi.encodePacked(beneficiary, startTimestamp, durationSeconds, cliffSeconds, executor));
112
+ function _getCreate2VestingWalletConfidentialSalt(bytes memory initArgs) internal pure virtual returns (bytes32) {
113
+ return keccak256(initArgs);
203
114
  }
204
115
  }
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- // OpenZeppelin Confidential Contracts (last updated v0.2.0-rc.2) (governance/utils/VotesConfidential.sol)
2
+ // OpenZeppelin Confidential Contracts (last updated v0.2.0) (governance/utils/VotesConfidential.sol)
3
3
  pragma solidity ^0.8.24;
4
4
 
5
5
  import {FHE, ebool, euint64} from "@fhevm/solidity/lib/FHE.sol";
@@ -9,9 +9,25 @@ import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
9
9
  import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
10
10
  import {Nonces} from "@openzeppelin/contracts/utils/Nonces.sol";
11
11
  import {Time} from "@openzeppelin/contracts/utils/types/Time.sol";
12
+ import {HandleAccessManager} from "./../../utils/HandleAccessManager.sol";
12
13
  import {CheckpointsConfidential} from "./../../utils/structs/CheckpointsConfidential.sol";
13
14
 
14
- abstract contract VotesConfidential is Nonces, EIP712, IERC6372 {
15
+ /**
16
+ * @dev A confidential votes contract tracking confidential voting power of accounts over time.
17
+ * It features vote delegation to delegators.
18
+
19
+ * This contract keeps a history (checkpoints) of each account's confidential vote power. Confidential
20
+ * voting power can be delegated either by calling the {delegate} function directly, or by providing
21
+ * a signature to be used with {delegateBySig}. Confidential voting power handles can be queried
22
+ * through the public accessors {getVotes} and {getPastVotes} but can only be decrypted by accounts
23
+ * allowed to access them. Ensure that {HandleAccessManager-_validateHandleAllowance} is implemented properly, allowing all
24
+ * necessary addresses to access voting power handles.
25
+ *
26
+ * By default, voting units does not account for voting power. This makes transfers of underlying
27
+ * voting units cheaper. The downside is that it requires users to delegate to themselves in order
28
+ * to activate checkpoints and have their voting power tracked.
29
+ */
30
+ abstract contract VotesConfidential is Nonces, EIP712, IERC6372, HandleAccessManager {
15
31
  using FHE for *;
16
32
  using CheckpointsConfidential for CheckpointsConfidential.TraceEuint64;
17
33
 
@@ -168,7 +184,6 @@ abstract contract VotesConfidential is Nonces, EIP712, IERC6372 {
168
184
  store = _delegateCheckpoints[from];
169
185
  euint64 newValue = store.latest().sub(amount);
170
186
  newValue.allowThis();
171
- newValue.allow(from);
172
187
  euint64 oldValue = _push(store, newValue);
173
188
  emit DelegateVotesChanged(from, oldValue, newValue);
174
189
  }
@@ -176,7 +191,6 @@ abstract contract VotesConfidential is Nonces, EIP712, IERC6372 {
176
191
  store = _delegateCheckpoints[to];
177
192
  euint64 newValue = store.latest().add(amount);
178
193
  newValue.allowThis();
179
- newValue.allow(to);
180
194
  euint64 oldValue = _push(store, newValue);
181
195
  emit DelegateVotesChanged(to, oldValue, newValue);
182
196
  }
@@ -1,11 +1,11 @@
1
1
  // SPDX-License-Identifier: MIT
2
- // OpenZeppelin Confidential Contracts (last updated v0.2.0-rc.2) (interfaces/IConfidentialFungibleToken.sol)
2
+ // OpenZeppelin Confidential Contracts (last updated v0.3.0-rc.0) (interfaces/IERC7984.sol)
3
3
  pragma solidity ^0.8.24;
4
4
 
5
5
  import {euint64, externalEuint64} from "@fhevm/solidity/lib/FHE.sol";
6
6
 
7
- /// @dev Draft interface for a confidential fungible token standard utilizing the Zama TFHE library.
8
- interface IConfidentialFungibleToken {
7
+ /// @dev Draft interface for a confidential fungible token standard utilizing the Zama FHE library.
8
+ interface IERC7984 {
9
9
  /**
10
10
  * @dev Emitted when the expiration timestamp for an operator `operator` is updated for a given `holder`.
11
11
  * The operator may move any amount of tokens on behalf of the holder until the timestamp `until`.
@@ -32,8 +32,8 @@ interface IConfidentialFungibleToken {
32
32
  /// @dev Returns the number of decimals of the token. Recommended to be 6.
33
33
  function decimals() external view returns (uint8);
34
34
 
35
- /// @dev Returns the token URI.
36
- function tokenURI() external view returns (string memory);
35
+ /// @dev Returns the contract URI. See [ERC-7572](https://eips.ethereum.org/EIPS/eip-7572) for details.
36
+ function contractURI() external view returns (string memory);
37
37
 
38
38
  /// @dev Returns the confidential total supply of the token.
39
39
  function confidentialTotalSupply() external view returns (euint64);
@@ -91,7 +91,7 @@ interface IConfidentialFungibleToken {
91
91
  * @dev Similar to {confidentialTransfer-address-externalEuint64-bytes} but with a callback to `to` after
92
92
  * the transfer.
93
93
  *
94
- * The callback is made to the {IConfidentialFungibleTokenReceiver-onConfidentialTransferReceived} function on the
94
+ * The callback is made to the {IERC7984Receiver-onConfidentialTransferReceived} function on the
95
95
  * to address with the actual transferred amount (may differ from the given `encryptedAmount`) and the given
96
96
  * data `data`.
97
97
  */
@@ -1,11 +1,11 @@
1
1
  // SPDX-License-Identifier: MIT
2
- // OpenZeppelin Confidential Contracts (last updated v0.2.0-rc.2) (interfaces/IConfidentialFungibleTokenReceiver.sol)
2
+ // OpenZeppelin Confidential Contracts (last updated v0.3.0-rc.0) (interfaces/IERC7984Receiver.sol)
3
3
  pragma solidity ^0.8.24;
4
4
 
5
5
  import {ebool, euint64} from "@fhevm/solidity/lib/FHE.sol";
6
6
 
7
- /// @dev Interface for contracts that can receive confidential token transfers with a callback.
8
- interface IConfidentialFungibleTokenReceiver {
7
+ /// @dev Interface for contracts that can receive ERC7984 transfers with a callback.
8
+ interface IERC7984Receiver {
9
9
  /**
10
10
  * @dev Called upon receiving a confidential token transfer. Returns an encrypted boolean indicating success
11
11
  * of the callback. If false is returned, the transfer must be reversed.
@@ -0,0 +1,64 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // OpenZeppelin Confidential Contracts (last updated v0.3.0-rc.0) (interfaces/IERC7984Rwa.sol)
3
+ pragma solidity ^0.8.24;
4
+
5
+ import {externalEuint64, euint64} from "@fhevm/solidity/lib/FHE.sol";
6
+ import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
7
+ import {IERC7984} from "./IERC7984.sol";
8
+
9
+ /// @dev Interface for confidential RWA contracts.
10
+ interface IERC7984Rwa is IERC7984, IERC165 {
11
+ /// @dev Returns true if the contract is paused, false otherwise.
12
+ function paused() external view returns (bool);
13
+ /// @dev Returns whether an account is allowed to interact with the token.
14
+ function isUserAllowed(address account) external view returns (bool);
15
+ /// @dev Returns the confidential frozen balance of an account.
16
+ function confidentialFrozen(address account) external view returns (euint64);
17
+ /// @dev Returns the confidential available (unfrozen) balance of an account. Up to {IERC7984-confidentialBalanceOf}.
18
+ function confidentialAvailable(address account) external returns (euint64);
19
+ /// @dev Pauses contract.
20
+ function pause() external;
21
+ /// @dev Unpauses contract.
22
+ function unpause() external;
23
+ /// @dev Blocks a user account.
24
+ function blockUser(address account) external;
25
+ /// @dev Unblocks a user account.
26
+ function unblockUser(address account) external;
27
+ /// @dev Sets confidential amount of token for an account as frozen with proof.
28
+ function setConfidentialFrozen(
29
+ address account,
30
+ externalEuint64 encryptedAmount,
31
+ bytes calldata inputProof
32
+ ) external;
33
+ /// @dev Sets confidential amount of token for an account as frozen.
34
+ function setConfidentialFrozen(address account, euint64 encryptedAmount) external;
35
+ /// @dev Mints confidential amount of tokens to account with proof.
36
+ function confidentialMint(
37
+ address to,
38
+ externalEuint64 encryptedAmount,
39
+ bytes calldata inputProof
40
+ ) external returns (euint64);
41
+ /// @dev Mints confidential amount of tokens to account.
42
+ function confidentialMint(address to, euint64 encryptedAmount) external returns (euint64);
43
+ /// @dev Burns confidential amount of tokens from account with proof.
44
+ function confidentialBurn(
45
+ address account,
46
+ externalEuint64 encryptedAmount,
47
+ bytes calldata inputProof
48
+ ) external returns (euint64);
49
+ /// @dev Burns confidential amount of tokens from account.
50
+ function confidentialBurn(address account, euint64 encryptedAmount) external returns (euint64);
51
+ /// @dev Forces transfer of confidential amount of tokens from account to account with proof by skipping compliance checks.
52
+ function forceConfidentialTransferFrom(
53
+ address from,
54
+ address to,
55
+ externalEuint64 encryptedAmount,
56
+ bytes calldata inputProof
57
+ ) external returns (euint64);
58
+ /// @dev Forces transfer of confidential amount of tokens from account to account by skipping compliance checks.
59
+ function forceConfidentialTransferFrom(
60
+ address from,
61
+ address to,
62
+ euint64 encryptedAmount
63
+ ) external returns (euint64);
64
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openzeppelin/confidential-contracts",
3
3
  "description": "Smart Contract library for use with confidential coprocessors",
4
- "version": "0.2.0-rc.2",
4
+ "version": "0.3.0-rc.0",
5
5
  "files": [
6
6
  "**/*.sol",
7
7
  "/build/contracts/*.json",
@@ -32,8 +32,8 @@
32
32
  },
33
33
  "homepage": "https://openzeppelin.com/contracts/",
34
34
  "peerDependencies": {
35
- "@fhevm/solidity": "0.7.0",
36
- "@openzeppelin/contracts": "^5.3.0",
37
- "@openzeppelin/contracts-upgradeable": "^5.3.0"
35
+ "@fhevm/solidity": "0.8.0",
36
+ "@openzeppelin/contracts": "^5.4.0",
37
+ "@openzeppelin/contracts-upgradeable": "^5.4.0"
38
38
  }
39
39
  }