@openzeppelin/confidential-contracts 0.2.0 → 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 (33) hide show
  1. package/build/contracts/Checkpoints.json +2 -2
  2. package/build/contracts/CheckpointsConfidential.json +2 -2
  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} +76 -81
  12. package/build/contracts/FHESafeMath.json +2 -2
  13. package/build/contracts/{IConfidentialFungibleToken.json → IERC7984.json} +15 -15
  14. package/build/contracts/{IConfidentialFungibleTokenReceiver.json → IERC7984Receiver.json} +2 -2
  15. package/build/contracts/IERC7984Rwa.json +797 -0
  16. package/build/contracts/VestingWalletConfidentialFactory.json +2 -2
  17. package/finance/VestingWalletConfidential.sol +6 -9
  18. package/finance/VestingWalletConfidentialFactory.sol +7 -12
  19. package/interfaces/{IConfidentialFungibleToken.sol → IERC7984.sol} +5 -5
  20. package/interfaces/{IConfidentialFungibleTokenReceiver.sol → IERC7984Receiver.sol} +3 -3
  21. package/interfaces/IERC7984Rwa.sol +64 -0
  22. package/package.json +4 -4
  23. package/token/{ConfidentialFungibleToken.sol → ERC7984/ERC7984.sol} +68 -76
  24. package/token/{extensions/ConfidentialFungibleTokenERC20Wrapper.sol → ERC7984/extensions/ERC7984ERC20Wrapper.sol} +18 -20
  25. package/token/ERC7984/extensions/ERC7984Freezable.sol +66 -0
  26. package/token/ERC7984/extensions/ERC7984ObserverAccess.sol +63 -0
  27. package/token/ERC7984/extensions/ERC7984Omnibus.sol +209 -0
  28. package/token/ERC7984/extensions/ERC7984Restricted.sol +118 -0
  29. package/token/ERC7984/extensions/ERC7984Rwa.sol +236 -0
  30. package/token/{extensions/ConfidentialFungibleTokenVotes.sol → ERC7984/extensions/ERC7984Votes.sol} +8 -14
  31. package/token/{utils/ConfidentialFungibleTokenUtils.sol → ERC7984/utils/ERC7984Utils.sol} +12 -12
  32. package/utils/FHESafeMath.sol +42 -7
  33. package/utils/structs/temporary-Checkpoints.sol +2 -2
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- // OpenZeppelin Confidential Contracts (last updated v0.2.0) (token/extensions/ConfidentialFungibleTokenERC20Wrapper.sol)
2
+ // OpenZeppelin Confidential Contracts (last updated v0.3.0-rc.0) (token/ERC7984/extensions/ERC7984ERC20Wrapper.sol)
3
3
 
4
4
  pragma solidity ^0.8.27;
5
5
 
@@ -9,17 +9,17 @@ import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
9
9
  import {IERC20Metadata} from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";
10
10
  import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
11
11
  import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
12
- import {ConfidentialFungibleToken} from "./../ConfidentialFungibleToken.sol";
12
+ import {ERC7984} from "./../ERC7984.sol";
13
13
 
14
14
  /**
15
- * @dev A wrapper contract built on top of {ConfidentialFungibleToken} that allows wrapping an `ERC20` token
16
- * into a confidential fungible token. The wrapper contract implements the `IERC1363Receiver` interface
15
+ * @dev A wrapper contract built on top of {ERC7984} that allows wrapping an `ERC20` token
16
+ * into an `ERC7984` token. The wrapper contract implements the `IERC1363Receiver` interface
17
17
  * which allows users to transfer `ERC1363` tokens directly to the wrapper with a callback to wrap the tokens.
18
18
  *
19
19
  * WARNING: Minting assumes the full amount of the underlying token transfer has been received, hence some non-standard
20
20
  * tokens such as fee-on-transfer or other deflationary-type tokens are not supported by this wrapper.
21
21
  */
22
- abstract contract ConfidentialFungibleTokenERC20Wrapper is ConfidentialFungibleToken, IERC1363Receiver {
22
+ abstract contract ERC7984ERC20Wrapper is ERC7984, IERC1363Receiver {
23
23
  IERC20 private immutable _underlying;
24
24
  uint8 private immutable _decimals;
25
25
  uint256 private immutable _rate;
@@ -41,7 +41,7 @@ abstract contract ConfidentialFungibleTokenERC20Wrapper is ConfidentialFungibleT
41
41
  }
42
42
  }
43
43
 
44
- /// @inheritdoc ConfidentialFungibleToken
44
+ /// @inheritdoc ERC7984
45
45
  function decimals() public view virtual override returns (uint8) {
46
46
  return _decimals;
47
47
  }
@@ -71,7 +71,7 @@ abstract contract ConfidentialFungibleTokenERC20Wrapper is ConfidentialFungibleT
71
71
  bytes calldata data
72
72
  ) public virtual returns (bytes4) {
73
73
  // check caller is the token contract
74
- require(address(underlying()) == msg.sender, ConfidentialFungibleTokenUnauthorizedCaller(msg.sender));
74
+ require(address(underlying()) == msg.sender, ERC7984UnauthorizedCaller(msg.sender));
75
75
 
76
76
  // mint confidential token
77
77
  address to = data.length < 20 ? from : address(bytes20(data));
@@ -107,10 +107,7 @@ abstract contract ConfidentialFungibleTokenERC20Wrapper is ConfidentialFungibleT
107
107
  * NOTE: The caller *must* already be approved by ACL for the given `amount`.
108
108
  */
109
109
  function unwrap(address from, address to, euint64 amount) public virtual {
110
- require(
111
- FHE.isAllowed(amount, msg.sender),
112
- ConfidentialFungibleTokenUnauthorizedUseOfEncryptedAmount(amount, msg.sender)
113
- );
110
+ require(FHE.isAllowed(amount, msg.sender), ERC7984UnauthorizedUseOfEncryptedAmount(amount, msg.sender));
114
111
  _unwrap(from, to, amount);
115
112
  }
116
113
 
@@ -130,21 +127,22 @@ abstract contract ConfidentialFungibleTokenERC20Wrapper is ConfidentialFungibleT
130
127
  /**
131
128
  * @dev Fills an unwrap request for a given request id related to a decrypted unwrap amount.
132
129
  */
133
- function finalizeUnwrap(uint256 requestID, uint64 amount, bytes[] memory signatures) public virtual {
134
- FHE.checkSignatures(requestID, signatures);
130
+ function finalizeUnwrap(
131
+ uint256 requestID,
132
+ bytes calldata cleartexts,
133
+ bytes calldata decryptionProof
134
+ ) public virtual {
135
+ FHE.checkSignatures(requestID, cleartexts, decryptionProof);
135
136
  address to = _receivers[requestID];
136
- require(to != address(0), ConfidentialFungibleTokenInvalidGatewayRequest(requestID));
137
+ require(to != address(0), ERC7984InvalidGatewayRequest(requestID));
137
138
  delete _receivers[requestID];
138
139
 
139
- SafeERC20.safeTransfer(underlying(), to, amount * rate());
140
+ SafeERC20.safeTransfer(underlying(), to, abi.decode(cleartexts, (uint64)) * rate());
140
141
  }
141
142
 
142
143
  function _unwrap(address from, address to, euint64 amount) internal virtual {
143
- require(to != address(0), ConfidentialFungibleTokenInvalidReceiver(to));
144
- require(
145
- from == msg.sender || isOperator(from, msg.sender),
146
- ConfidentialFungibleTokenUnauthorizedSpender(from, msg.sender)
147
- );
144
+ require(to != address(0), ERC7984InvalidReceiver(to));
145
+ require(from == msg.sender || isOperator(from, msg.sender), ERC7984UnauthorizedSpender(from, msg.sender));
148
146
 
149
147
  // try to burn, see how much we actually got
150
148
  euint64 burntAmount = _burn(from, amount);
@@ -0,0 +1,66 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // OpenZeppelin Confidential Contracts (last updated v0.3.0-rc.0) (token/ERC7984/extensions/ERC7984Freezable.sol)
3
+
4
+ pragma solidity ^0.8.27;
5
+
6
+ import {FHE, ebool, euint64, externalEuint64} from "@fhevm/solidity/lib/FHE.sol";
7
+ import {FHESafeMath} from "../../../utils/FHESafeMath.sol";
8
+ import {ERC7984} from "../ERC7984.sol";
9
+
10
+ /**
11
+ * @dev Extension of {ERC7984} that implements a confidential
12
+ * freezing mechanism that can be managed by an authorized account with
13
+ * {setConfidentialFrozen} functions.
14
+ *
15
+ * The freezing mechanism provides the guarantee to the contract owner
16
+ * (e.g. a DAO or a well-configured multisig) that a specific confidential
17
+ * amount of tokens held by an account won't be transferable until those
18
+ * tokens are unfrozen.
19
+ *
20
+ * Inspired by https://github.com/OpenZeppelin/openzeppelin-community-contracts/blob/master/contracts/token/ERC20/extensions/ERC20Freezable.sol
21
+ */
22
+ abstract contract ERC7984Freezable is ERC7984 {
23
+ /// @dev Confidential frozen amount of tokens per address.
24
+ mapping(address account => euint64 encryptedAmount) private _frozenBalances;
25
+
26
+ /// @dev Emitted when a confidential amount of token is frozen for an account
27
+ event TokensFrozen(address indexed account, euint64 encryptedAmount);
28
+
29
+ /// @dev Returns the confidential frozen balance of an account.
30
+ function confidentialFrozen(address account) public view virtual returns (euint64) {
31
+ return _frozenBalances[account];
32
+ }
33
+
34
+ /// @dev Returns the confidential available (unfrozen) balance of an account. Up to {confidentialBalanceOf}.
35
+ function confidentialAvailable(address account) public virtual returns (euint64) {
36
+ (ebool success, euint64 unfrozen) = FHESafeMath.tryDecrease(
37
+ confidentialBalanceOf(account),
38
+ confidentialFrozen(account)
39
+ );
40
+ return FHE.select(success, unfrozen, FHE.asEuint64(0));
41
+ }
42
+
43
+ /// @dev Internal function to freeze a confidential amount of tokens for an account.
44
+ function _setConfidentialFrozen(address account, euint64 encryptedAmount) internal virtual {
45
+ FHE.allowThis(encryptedAmount);
46
+ FHE.allow(encryptedAmount, account);
47
+ _frozenBalances[account] = encryptedAmount;
48
+ emit TokensFrozen(account, encryptedAmount);
49
+ }
50
+
51
+ /**
52
+ * @dev See {ERC7984-_update}.
53
+ *
54
+ * The `from` account must have sufficient unfrozen balance,
55
+ * otherwise 0 tokens are transferred.
56
+ * The default freezing behavior can be changed (for a pass-through for instance) by overriding
57
+ * {confidentialAvailable}.
58
+ */
59
+ function _update(address from, address to, euint64 encryptedAmount) internal virtual override returns (euint64) {
60
+ if (from != address(0)) {
61
+ euint64 unfrozen = confidentialAvailable(from);
62
+ encryptedAmount = FHE.select(FHE.le(encryptedAmount, unfrozen), encryptedAmount, FHE.asEuint64(0));
63
+ }
64
+ return super._update(from, to, encryptedAmount);
65
+ }
66
+ }
@@ -0,0 +1,63 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // OpenZeppelin Confidential Contracts (last updated v0.3.0-rc.0) (token/ERC7984/extensions/ERC7984ObserverAccess.sol)
3
+
4
+ pragma solidity ^0.8.27;
5
+
6
+ import {FHE, euint64} from "@fhevm/solidity/lib/FHE.sol";
7
+ import {ERC7984} from "../ERC7984.sol";
8
+
9
+ /**
10
+ * @dev Extension of {ERC7984} that allows each account to add a observer who is given
11
+ * permanent ACL access to its transfer and balance amounts. A observer can be added or removed at any point in time.
12
+ */
13
+ abstract contract ERC7984ObserverAccess is ERC7984 {
14
+ mapping(address => address) private _observers;
15
+
16
+ /// @dev Emitted when the observer is changed for the given account `account`.
17
+ event ERC7984ObserverAccessObserverSet(address account, address oldObserver, address newObserver);
18
+
19
+ /// @dev Thrown when an account tries to set a `newObserver` for a given `account` without proper authority.
20
+ error Unauthorized();
21
+
22
+ /**
23
+ * @dev Sets the observer for the given account `account` to `newObserver`. Can be called by the
24
+ * account or the existing observer to abdicate the observer role (may only set to `address(0)`).
25
+ */
26
+ function setObserver(address account, address newObserver) public virtual {
27
+ address oldObserver = observer(account);
28
+ require(msg.sender == account || (msg.sender == oldObserver && newObserver == address(0)), Unauthorized());
29
+ if (oldObserver != newObserver) {
30
+ if (newObserver != address(0)) {
31
+ euint64 balanceHandle = confidentialBalanceOf(account);
32
+ if (FHE.isInitialized(balanceHandle)) {
33
+ FHE.allow(balanceHandle, newObserver);
34
+ }
35
+ }
36
+
37
+ emit ERC7984ObserverAccessObserverSet(account, oldObserver, _observers[account] = newObserver);
38
+ }
39
+ }
40
+
41
+ /// @dev Returns the observer for the given account `account`.
42
+ function observer(address account) public view virtual returns (address) {
43
+ return _observers[account];
44
+ }
45
+
46
+ function _update(address from, address to, euint64 amount) internal virtual override returns (euint64 transferred) {
47
+ transferred = super._update(from, to, amount);
48
+
49
+ address fromObserver = observer(from);
50
+ address toObserver = observer(to);
51
+
52
+ if (fromObserver != address(0)) {
53
+ FHE.allow(confidentialBalanceOf(from), fromObserver);
54
+ FHE.allow(transferred, fromObserver);
55
+ }
56
+ if (toObserver != address(0)) {
57
+ FHE.allow(confidentialBalanceOf(to), toObserver);
58
+ if (toObserver != fromObserver) {
59
+ FHE.allow(transferred, toObserver);
60
+ }
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,209 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // OpenZeppelin Confidential Contracts (last updated v0.3.0-rc.0) (token/ERC7984/extensions/ERC7984Omnibus.sol)
3
+
4
+ pragma solidity ^0.8.27;
5
+
6
+ import {FHE, euint64, externalEuint64, externalEaddress, eaddress} from "@fhevm/solidity/lib/FHE.sol";
7
+ import {ERC7984} from "../ERC7984.sol";
8
+
9
+ /**
10
+ * @dev Extension of {ERC7984} that emits additional events for omnibus transfers.
11
+ * These events contain encrypted addresses for the sub-account sender and recipient.
12
+ *
13
+ * NOTE: There is no onchain accounting for sub-accounts--integrators must track sub-account
14
+ * balances externally.
15
+ */
16
+ abstract contract ERC7984Omnibus is ERC7984 {
17
+ /**
18
+ * @dev Emitted when a confidential transfer is made representing the onchain settlement of
19
+ * an omnibus transfer from `sender` to `recipient` of amount `amount`. Settlement occurs between
20
+ * `omnibusFrom` and `omnibusTo` and is represented in a matching {IERC7984-ConfidentialTransfer} event.
21
+ *
22
+ * NOTE: `omnibusFrom` and `omnibusTo` get permanent ACL allowances for `sender` and `recipient`.
23
+ */
24
+ event OmnibusConfidentialTransfer(
25
+ address indexed omnibusFrom,
26
+ address indexed omnibusTo,
27
+ eaddress sender,
28
+ eaddress indexed recipient,
29
+ euint64 amount
30
+ );
31
+
32
+ /**
33
+ * @dev The caller `user` does not have access to the encrypted address `addr`.
34
+ *
35
+ * NOTE: Try using the equivalent transfer function with an input proof.
36
+ */
37
+ error ERC7984UnauthorizedUseOfEncryptedAddress(eaddress addr, address user);
38
+
39
+ /// @dev Wraps the {confidentialTransfer-address-externalEuint64-bytes} function and emits the {OmnibusConfidentialTransfer} event.
40
+ function confidentialTransferOmnibus(
41
+ address omnibusTo,
42
+ externalEaddress externalSender,
43
+ externalEaddress externalRecipient,
44
+ externalEuint64 externalAmount,
45
+ bytes calldata inputProof
46
+ ) public virtual returns (euint64) {
47
+ return
48
+ confidentialTransferFromOmnibus(
49
+ msg.sender,
50
+ omnibusTo,
51
+ externalSender,
52
+ externalRecipient,
53
+ externalAmount,
54
+ inputProof
55
+ );
56
+ }
57
+
58
+ /// @dev Wraps the {confidentialTransfer-address-euint64} function and emits the {OmnibusConfidentialTransfer} event.
59
+ function confidentialTransferOmnibus(
60
+ address omnibusTo,
61
+ eaddress sender,
62
+ eaddress recipient,
63
+ euint64 amount
64
+ ) public virtual returns (euint64) {
65
+ return confidentialTransferFromOmnibus(msg.sender, omnibusTo, sender, recipient, amount);
66
+ }
67
+
68
+ /// @dev Wraps the {confidentialTransferFrom-address-address-externalEuint64-bytes} function and emits the {OmnibusConfidentialTransfer} event.
69
+ function confidentialTransferFromOmnibus(
70
+ address omnibusFrom,
71
+ address omnibusTo,
72
+ externalEaddress externalSender,
73
+ externalEaddress externalRecipient,
74
+ externalEuint64 externalAmount,
75
+ bytes calldata inputProof
76
+ ) public virtual returns (euint64) {
77
+ eaddress sender = FHE.fromExternal(externalSender, inputProof);
78
+ eaddress recipient = FHE.fromExternal(externalRecipient, inputProof);
79
+ euint64 amount = FHE.fromExternal(externalAmount, inputProof);
80
+
81
+ return _confidentialTransferFromOmnibus(omnibusFrom, omnibusTo, sender, recipient, amount);
82
+ }
83
+
84
+ /// @dev Wraps the {confidentialTransferFrom-address-address-euint64} function and emits the {OmnibusConfidentialTransfer} event.
85
+ function confidentialTransferFromOmnibus(
86
+ address omnibusFrom,
87
+ address omnibusTo,
88
+ eaddress sender,
89
+ eaddress recipient,
90
+ euint64 amount
91
+ ) public virtual returns (euint64) {
92
+ require(FHE.isAllowed(sender, msg.sender), ERC7984UnauthorizedUseOfEncryptedAddress(sender, msg.sender));
93
+ require(FHE.isAllowed(recipient, msg.sender), ERC7984UnauthorizedUseOfEncryptedAddress(recipient, msg.sender));
94
+
95
+ return _confidentialTransferFromOmnibus(omnibusFrom, omnibusTo, sender, recipient, amount);
96
+ }
97
+
98
+ /// @dev Wraps the {confidentialTransferAndCall-address-externalEuint64-bytes-bytes} function and emits the {OmnibusConfidentialTransfer} event.
99
+ function confidentialTransferAndCallOmnibus(
100
+ address omnibusTo,
101
+ externalEaddress externalSender,
102
+ externalEaddress externalRecipient,
103
+ externalEuint64 externalAmount,
104
+ bytes calldata inputProof,
105
+ bytes calldata data
106
+ ) public virtual returns (euint64) {
107
+ return
108
+ confidentialTransferFromAndCallOmnibus(
109
+ msg.sender,
110
+ omnibusTo,
111
+ externalSender,
112
+ externalRecipient,
113
+ externalAmount,
114
+ inputProof,
115
+ data
116
+ );
117
+ }
118
+
119
+ /// @dev Wraps the {confidentialTransferAndCall-address-euint64-bytes} function and emits the {OmnibusConfidentialTransfer} event.
120
+ function confidentialTransferAndCallOmnibus(
121
+ address omnibusTo,
122
+ eaddress sender,
123
+ eaddress recipient,
124
+ euint64 amount,
125
+ bytes calldata data
126
+ ) public virtual returns (euint64) {
127
+ return confidentialTransferFromAndCallOmnibus(msg.sender, omnibusTo, sender, recipient, amount, data);
128
+ }
129
+
130
+ /// @dev Wraps the {confidentialTransferFromAndCall-address-address-externalEuint64-bytes-bytes} function and emits the {OmnibusConfidentialTransfer} event.
131
+ function confidentialTransferFromAndCallOmnibus(
132
+ address omnibusFrom,
133
+ address omnibusTo,
134
+ externalEaddress externalSender,
135
+ externalEaddress externalRecipient,
136
+ externalEuint64 externalAmount,
137
+ bytes calldata inputProof,
138
+ bytes calldata data
139
+ ) public virtual returns (euint64) {
140
+ eaddress sender = FHE.fromExternal(externalSender, inputProof);
141
+ eaddress recipient = FHE.fromExternal(externalRecipient, inputProof);
142
+ euint64 amount = FHE.fromExternal(externalAmount, inputProof);
143
+
144
+ return _confidentialTransferFromAndCallOmnibus(omnibusFrom, omnibusTo, sender, recipient, amount, data);
145
+ }
146
+
147
+ /// @dev Wraps the {confidentialTransferFromAndCall-address-address-euint64-bytes} function and emits the {OmnibusConfidentialTransfer} event.
148
+ function confidentialTransferFromAndCallOmnibus(
149
+ address omnibusFrom,
150
+ address omnibusTo,
151
+ eaddress sender,
152
+ eaddress recipient,
153
+ euint64 amount,
154
+ bytes calldata data
155
+ ) public virtual returns (euint64) {
156
+ require(FHE.isAllowed(sender, msg.sender), ERC7984UnauthorizedUseOfEncryptedAddress(sender, msg.sender));
157
+ require(FHE.isAllowed(recipient, msg.sender), ERC7984UnauthorizedUseOfEncryptedAddress(recipient, msg.sender));
158
+
159
+ return _confidentialTransferFromAndCallOmnibus(omnibusFrom, omnibusTo, sender, recipient, amount, data);
160
+ }
161
+
162
+ /// @dev Handles the ACL allowances, does the transfer without a callback, and emits {OmnibusConfidentialTransfer}.
163
+ function _confidentialTransferFromOmnibus(
164
+ address omnibusFrom,
165
+ address omnibusTo,
166
+ eaddress sender,
167
+ eaddress recipient,
168
+ euint64 amount
169
+ ) internal virtual returns (euint64) {
170
+ FHE.allowThis(sender);
171
+ FHE.allow(sender, omnibusFrom);
172
+ FHE.allow(sender, omnibusTo);
173
+
174
+ FHE.allowThis(recipient);
175
+ FHE.allow(recipient, omnibusFrom);
176
+ FHE.allow(recipient, omnibusTo);
177
+
178
+ euint64 transferred = confidentialTransferFrom(omnibusFrom, omnibusTo, amount);
179
+ emit OmnibusConfidentialTransfer(omnibusFrom, omnibusTo, sender, recipient, transferred);
180
+ return transferred;
181
+ }
182
+
183
+ /// @dev Handles the ACL allowances, does the transfer with a callback, and emits {OmnibusConfidentialTransfer}.
184
+ function _confidentialTransferFromAndCallOmnibus(
185
+ address omnibusFrom,
186
+ address omnibusTo,
187
+ eaddress sender,
188
+ eaddress recipient,
189
+ euint64 amount,
190
+ bytes calldata data
191
+ ) internal virtual returns (euint64) {
192
+ euint64 transferred = confidentialTransferFromAndCall(omnibusFrom, omnibusTo, amount, data);
193
+
194
+ FHE.allowThis(sender);
195
+ FHE.allow(sender, omnibusFrom);
196
+ FHE.allow(sender, omnibusTo);
197
+
198
+ FHE.allowThis(recipient);
199
+ FHE.allow(recipient, omnibusFrom);
200
+ FHE.allow(recipient, omnibusTo);
201
+
202
+ FHE.allowThis(transferred);
203
+ FHE.allow(transferred, omnibusFrom);
204
+ FHE.allow(transferred, omnibusTo);
205
+
206
+ emit OmnibusConfidentialTransfer(omnibusFrom, omnibusTo, sender, recipient, transferred);
207
+ return transferred;
208
+ }
209
+ }
@@ -0,0 +1,118 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // OpenZeppelin Confidential Contracts (last updated v0.3.0-rc.0) (token/ERC7984/extensions/ERC7984Restricted.sol)
3
+
4
+ pragma solidity ^0.8.27;
5
+
6
+ import {ERC7984, euint64} from "../ERC7984.sol";
7
+
8
+ /**
9
+ * @dev Extension of {ERC7984} that implements user account transfer restrictions through the
10
+ * {isUserAllowed} function. Inspired by
11
+ * https://github.com/OpenZeppelin/openzeppelin-community-contracts/blob/master/contracts/token/ERC20/extensions/ERC20Restricted.sol.
12
+ *
13
+ * By default, each account has no explicit restriction. The {isUserAllowed} function acts as
14
+ * a blocklist. Developers can override {isUserAllowed} to check that `restriction == ALLOWED`
15
+ * to implement an allowlist.
16
+ */
17
+ abstract contract ERC7984Restricted is ERC7984 {
18
+ enum Restriction {
19
+ DEFAULT, // User has no explicit restriction
20
+ BLOCKED, // User is explicitly blocked
21
+ ALLOWED // User is explicitly allowed
22
+ }
23
+
24
+ mapping(address account => Restriction) private _restrictions;
25
+
26
+ /// @dev Emitted when a user account's restriction is updated.
27
+ event UserRestrictionUpdated(address indexed account, Restriction restriction);
28
+
29
+ /// @dev The operation failed because the user account is restricted.
30
+ error UserRestricted(address account);
31
+
32
+ /// @dev Returns the restriction of a user account.
33
+ function getRestriction(address account) public view virtual returns (Restriction) {
34
+ return _restrictions[account];
35
+ }
36
+
37
+ /**
38
+ * @dev Returns whether a user account is allowed to interact with the token.
39
+ *
40
+ * Default implementation only disallows explicitly BLOCKED accounts (i.e. a blocklist).
41
+ *
42
+ * To convert into an allowlist, override as:
43
+ *
44
+ * ```solidity
45
+ * function isUserAllowed(address account) public view virtual override returns (bool) {
46
+ * return getRestriction(account) == Restriction.ALLOWED;
47
+ * }
48
+ * ```
49
+ */
50
+ function isUserAllowed(address account) public view virtual returns (bool) {
51
+ return getRestriction(account) != Restriction.BLOCKED; // i.e. DEFAULT && ALLOWED
52
+ }
53
+
54
+ /**
55
+ * @dev See {ERC7984-_update}. Enforces transfer restrictions (excluding minting and burning).
56
+ *
57
+ * Requirements:
58
+ *
59
+ * * `from` must be allowed to transfer tokens (see {isUserAllowed}).
60
+ * * `to` must be allowed to receive tokens (see {isUserAllowed}).
61
+ *
62
+ * The default restriction behaviour can be changed (for a pass-through for instance) by overriding
63
+ * {_checkSenderRestriction} and/or {_checkRecipientRestriction}.
64
+ */
65
+ function _update(address from, address to, euint64 value) internal virtual override returns (euint64) {
66
+ _checkSenderRestriction(from);
67
+ _checkRecipientRestriction(to);
68
+ return super._update(from, to, value);
69
+ }
70
+
71
+ /// @dev Updates the restriction of a user account.
72
+ function _setRestriction(address account, Restriction restriction) internal virtual {
73
+ if (getRestriction(account) != restriction) {
74
+ _restrictions[account] = restriction;
75
+ emit UserRestrictionUpdated(account, restriction);
76
+ } // no-op if restriction is unchanged
77
+ }
78
+
79
+ /// @dev Convenience function to block a user account (set to BLOCKED).
80
+ function _blockUser(address account) internal virtual {
81
+ _setRestriction(account, Restriction.BLOCKED);
82
+ }
83
+
84
+ /// @dev Convenience function to allow a user account (set to ALLOWED).
85
+ function _allowUser(address account) internal virtual {
86
+ _setRestriction(account, Restriction.ALLOWED);
87
+ }
88
+
89
+ /// @dev Convenience function to reset a user account to default restriction.
90
+ function _resetUser(address account) internal virtual {
91
+ _setRestriction(account, Restriction.DEFAULT);
92
+ }
93
+
94
+ /// @dev Checks if a user account is restricted. Reverts with {ERC20Restricted} if so.
95
+ function _checkRestriction(address account) internal view virtual {
96
+ require(isUserAllowed(account), UserRestricted(account));
97
+ }
98
+
99
+ /**
100
+ * @dev Internal function which checks restriction of the `from` account before a transfer.
101
+ * Working with {_update} function.
102
+ */
103
+ function _checkSenderRestriction(address account) internal view virtual {
104
+ if (account != address(0)) {
105
+ _checkRestriction(account); // Not minting
106
+ }
107
+ }
108
+
109
+ /**
110
+ * @dev Internal function which checks restriction of the `to` account before a transfer.
111
+ * Working with {_update} function.
112
+ */
113
+ function _checkRecipientRestriction(address account) internal view virtual {
114
+ if (account != address(0)) {
115
+ _checkRestriction(account); // Not burning
116
+ }
117
+ }
118
+ }