@openzeppelin/confidential-contracts 0.2.0 → 0.3.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.
- package/build/contracts/Checkpoints.json +2 -2
- package/build/contracts/CheckpointsConfidential.json +2 -2
- package/build/contracts/{ConfidentialFungibleToken.json → ERC7984.json} +87 -58
- package/build/contracts/{ConfidentialFungibleTokenERC20Wrapper.json → ERC7984ERC20Wrapper.json} +143 -59
- package/build/contracts/ERC7984Freezable.json +700 -0
- package/build/contracts/ERC7984ObserverAccess.json +710 -0
- package/build/contracts/ERC7984Omnibus.json +1028 -0
- package/build/contracts/ERC7984Restricted.json +711 -0
- package/build/contracts/ERC7984Rwa.json +1385 -0
- package/build/contracts/{ConfidentialFungibleTokenUtils.json → ERC7984Utils.json} +4 -4
- package/build/contracts/{ConfidentialFungibleTokenVotes.json → ERC7984Votes.json} +142 -113
- package/build/contracts/FHESafeMath.json +2 -2
- package/build/contracts/{IConfidentialFungibleToken.json → IERC7984.json} +26 -7
- package/build/contracts/{IConfidentialFungibleTokenReceiver.json → IERC7984Receiver.json} +2 -2
- package/build/contracts/IERC7984Rwa.json +797 -0
- package/build/contracts/VestingWalletConfidentialFactory.json +2 -2
- package/finance/ERC7821WithExecutor.sol +3 -4
- package/finance/VestingWalletCliffConfidential.sol +3 -4
- package/finance/VestingWalletConfidential.sol +8 -12
- package/finance/VestingWalletConfidentialFactory.sol +7 -12
- package/interfaces/{IConfidentialFungibleToken.sol → IERC7984.sol} +6 -5
- package/interfaces/{IConfidentialFungibleTokenReceiver.sol → IERC7984Receiver.sol} +3 -3
- package/interfaces/IERC7984Rwa.sol +63 -0
- package/package.json +4 -4
- package/token/{ConfidentialFungibleToken.sol → ERC7984/ERC7984.sol} +81 -82
- package/token/{extensions/ConfidentialFungibleTokenERC20Wrapper.sol → ERC7984/extensions/ERC7984ERC20Wrapper.sol} +40 -35
- package/token/ERC7984/extensions/ERC7984Freezable.sol +75 -0
- package/token/ERC7984/extensions/ERC7984ObserverAccess.sol +63 -0
- package/token/ERC7984/extensions/ERC7984Omnibus.sol +209 -0
- package/token/ERC7984/extensions/ERC7984Restricted.sol +110 -0
- package/token/ERC7984/extensions/ERC7984Rwa.sol +248 -0
- package/token/{extensions/ConfidentialFungibleTokenVotes.sol → ERC7984/extensions/ERC7984Votes.sol} +8 -14
- package/token/{utils/ConfidentialFungibleTokenUtils.sol → ERC7984/utils/ERC7984Utils.sol} +14 -13
- package/utils/FHESafeMath.sol +45 -7
- package/utils/structs/temporary-Checkpoints.sol +2 -2
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// OpenZeppelin Confidential Contracts (last updated v0.3.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
|
+
FHE.allowThis(sender);
|
|
193
|
+
FHE.allow(sender, omnibusFrom);
|
|
194
|
+
FHE.allow(sender, omnibusTo);
|
|
195
|
+
|
|
196
|
+
FHE.allowThis(recipient);
|
|
197
|
+
FHE.allow(recipient, omnibusFrom);
|
|
198
|
+
FHE.allow(recipient, omnibusTo);
|
|
199
|
+
|
|
200
|
+
euint64 transferred = confidentialTransferFromAndCall(omnibusFrom, omnibusTo, amount, data);
|
|
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,110 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// OpenZeppelin Confidential Contracts (last updated v0.3.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
|
+
function isUserAllowed(address account) public view virtual returns (bool) {
|
|
43
|
+
return getRestriction(account) != Restriction.BLOCKED; // i.e. DEFAULT && ALLOWED
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @dev See {ERC7984-_update}. Enforces transfer restrictions (excluding minting and burning).
|
|
48
|
+
*
|
|
49
|
+
* Requirements:
|
|
50
|
+
*
|
|
51
|
+
* * `from` must be allowed to transfer tokens (see {isUserAllowed}).
|
|
52
|
+
* * `to` must be allowed to receive tokens (see {isUserAllowed}).
|
|
53
|
+
*
|
|
54
|
+
* The default restriction behavior can be changed (for a pass-through for instance) by overriding
|
|
55
|
+
* {_checkSenderRestriction} and/or {_checkRecipientRestriction}.
|
|
56
|
+
*/
|
|
57
|
+
function _update(address from, address to, euint64 value) internal virtual override returns (euint64) {
|
|
58
|
+
_checkSenderRestriction(from);
|
|
59
|
+
_checkRecipientRestriction(to);
|
|
60
|
+
return super._update(from, to, value);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// @dev Updates the restriction of a user account.
|
|
64
|
+
function _setRestriction(address account, Restriction restriction) internal virtual {
|
|
65
|
+
if (getRestriction(account) != restriction) {
|
|
66
|
+
_restrictions[account] = restriction;
|
|
67
|
+
emit UserRestrictionUpdated(account, restriction);
|
|
68
|
+
} // no-op if restriction is unchanged
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/// @dev Convenience function to block a user account (set to BLOCKED).
|
|
72
|
+
function _blockUser(address account) internal virtual {
|
|
73
|
+
_setRestriction(account, Restriction.BLOCKED);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/// @dev Convenience function to allow a user account (set to ALLOWED).
|
|
77
|
+
function _allowUser(address account) internal virtual {
|
|
78
|
+
_setRestriction(account, Restriction.ALLOWED);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// @dev Convenience function to reset a user account to default restriction.
|
|
82
|
+
function _resetUser(address account) internal virtual {
|
|
83
|
+
_setRestriction(account, Restriction.DEFAULT);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/// @dev Checks if a user account is restricted. Reverts with {UserRestricted} if so.
|
|
87
|
+
function _checkRestriction(address account) internal view virtual {
|
|
88
|
+
require(isUserAllowed(account), UserRestricted(account));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @dev Internal function which checks restriction of the `from` account before a transfer.
|
|
93
|
+
* Working with {_update} function.
|
|
94
|
+
*/
|
|
95
|
+
function _checkSenderRestriction(address account) internal view virtual {
|
|
96
|
+
if (account != address(0)) {
|
|
97
|
+
_checkRestriction(account); // Not minting
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @dev Internal function which checks restriction of the `to` account before a transfer.
|
|
103
|
+
* Working with {_update} function.
|
|
104
|
+
*/
|
|
105
|
+
function _checkRecipientRestriction(address account) internal view virtual {
|
|
106
|
+
if (account != address(0)) {
|
|
107
|
+
_checkRestriction(account); // Not burning
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// OpenZeppelin Confidential Contracts (last updated v0.3.0) (token/ERC7984/extensions/ERC7984Rwa.sol)
|
|
3
|
+
|
|
4
|
+
pragma solidity ^0.8.27;
|
|
5
|
+
|
|
6
|
+
import {FHE, externalEuint64, euint64} from "@fhevm/solidity/lib/FHE.sol";
|
|
7
|
+
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
|
|
8
|
+
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
|
|
9
|
+
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
10
|
+
import {Multicall} from "@openzeppelin/contracts/utils/Multicall.sol";
|
|
11
|
+
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
|
|
12
|
+
import {IERC7984} from "./../../../interfaces/IERC7984.sol";
|
|
13
|
+
import {IERC7984Rwa} from "./../../../interfaces/IERC7984Rwa.sol";
|
|
14
|
+
import {ERC7984} from "./../ERC7984.sol";
|
|
15
|
+
import {ERC7984Freezable} from "./ERC7984Freezable.sol";
|
|
16
|
+
import {ERC7984Restricted} from "./ERC7984Restricted.sol";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @dev Extension of {ERC7984} that supports confidential Real World Assets (RWAs).
|
|
20
|
+
* This interface provides compliance checks, transfer controls and enforcement actions.
|
|
21
|
+
*/
|
|
22
|
+
abstract contract ERC7984Rwa is IERC7984Rwa, ERC7984Freezable, ERC7984Restricted, Pausable, Multicall, AccessControl {
|
|
23
|
+
/**
|
|
24
|
+
* @dev Accounts granted the agent role have the following permissioned abilities:
|
|
25
|
+
*
|
|
26
|
+
* - Mint/Burn to/from a given address (does not require permission)
|
|
27
|
+
* - Force transfer from a given address (does not require permission)
|
|
28
|
+
* - Bypasses pause and restriction checks (not frozen)
|
|
29
|
+
* - Pause/Unpause the contract
|
|
30
|
+
* - Block/Unblock a given account
|
|
31
|
+
* - Set frozen amount of tokens for a given account.
|
|
32
|
+
*/
|
|
33
|
+
bytes32 public constant AGENT_ROLE = keccak256("AGENT_ROLE");
|
|
34
|
+
|
|
35
|
+
/// @dev Checks if the sender is an admin.
|
|
36
|
+
modifier onlyAdmin() {
|
|
37
|
+
_checkRole(DEFAULT_ADMIN_ROLE);
|
|
38
|
+
_;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// @dev Checks if the sender is an agent.
|
|
42
|
+
modifier onlyAgent() {
|
|
43
|
+
_checkRole(AGENT_ROLE);
|
|
44
|
+
_;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
constructor(address admin) {
|
|
48
|
+
_grantRole(DEFAULT_ADMIN_ROLE, admin);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// @inheritdoc ERC165
|
|
52
|
+
function supportsInterface(
|
|
53
|
+
bytes4 interfaceId
|
|
54
|
+
) public view virtual override(IERC165, ERC7984, AccessControl) returns (bool) {
|
|
55
|
+
return interfaceId == type(IERC7984Rwa).interfaceId || super.supportsInterface(interfaceId);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// @dev Returns true if has admin role, false otherwise.
|
|
59
|
+
function isAdmin(address account) public view virtual returns (bool) {
|
|
60
|
+
return hasRole(DEFAULT_ADMIN_ROLE, account);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// @dev Returns true if agent, false otherwise.
|
|
64
|
+
function isAgent(address account) public view virtual returns (bool) {
|
|
65
|
+
return hasRole(AGENT_ROLE, account);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/// @dev Adds agent.
|
|
69
|
+
function addAgent(address account) public virtual onlyAdmin {
|
|
70
|
+
_grantRole(AGENT_ROLE, account);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/// @dev Removes agent.
|
|
74
|
+
function removeAgent(address account) public virtual onlyAdmin {
|
|
75
|
+
_revokeRole(AGENT_ROLE, account);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// @dev Pauses contract.
|
|
79
|
+
function pause() public virtual onlyAgent {
|
|
80
|
+
_pause();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/// @dev Unpauses contract.
|
|
84
|
+
function unpause() public virtual onlyAgent {
|
|
85
|
+
_unpause();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// @dev Blocks a user account.
|
|
89
|
+
function blockUser(address account) public virtual onlyAgent {
|
|
90
|
+
_blockUser(account);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// @dev Unblocks a user account.
|
|
94
|
+
function unblockUser(address account) public virtual onlyAgent {
|
|
95
|
+
_resetUser(account);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/// @dev Sets confidential frozen for an account with proof.
|
|
99
|
+
function setConfidentialFrozen(
|
|
100
|
+
address account,
|
|
101
|
+
externalEuint64 encryptedAmount,
|
|
102
|
+
bytes calldata inputProof
|
|
103
|
+
) public virtual onlyAgent {
|
|
104
|
+
_setConfidentialFrozen(account, FHE.fromExternal(encryptedAmount, inputProof));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/// @dev Sets confidential frozen for an account.
|
|
108
|
+
function setConfidentialFrozen(address account, euint64 encryptedAmount) public virtual onlyAgent {
|
|
109
|
+
require(
|
|
110
|
+
FHE.isAllowed(encryptedAmount, msg.sender),
|
|
111
|
+
ERC7984UnauthorizedUseOfEncryptedAmount(encryptedAmount, msg.sender)
|
|
112
|
+
);
|
|
113
|
+
_setConfidentialFrozen(account, encryptedAmount);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/// @dev Mints confidential amount of tokens to account with proof.
|
|
117
|
+
function confidentialMint(
|
|
118
|
+
address to,
|
|
119
|
+
externalEuint64 encryptedAmount,
|
|
120
|
+
bytes calldata inputProof
|
|
121
|
+
) public virtual onlyAgent returns (euint64) {
|
|
122
|
+
euint64 mintedAmount = _mint(to, FHE.fromExternal(encryptedAmount, inputProof));
|
|
123
|
+
FHE.allow(mintedAmount, msg.sender);
|
|
124
|
+
return mintedAmount;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/// @dev Mints confidential amount of tokens to account.
|
|
128
|
+
function confidentialMint(address to, euint64 encryptedAmount) public virtual onlyAgent returns (euint64) {
|
|
129
|
+
require(
|
|
130
|
+
FHE.isAllowed(encryptedAmount, msg.sender),
|
|
131
|
+
ERC7984UnauthorizedUseOfEncryptedAmount(encryptedAmount, msg.sender)
|
|
132
|
+
);
|
|
133
|
+
euint64 mintedAmount = _mint(to, encryptedAmount);
|
|
134
|
+
FHE.allow(mintedAmount, msg.sender);
|
|
135
|
+
return mintedAmount;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/// @dev Burns confidential amount of tokens from account with proof.
|
|
139
|
+
function confidentialBurn(
|
|
140
|
+
address account,
|
|
141
|
+
externalEuint64 encryptedAmount,
|
|
142
|
+
bytes calldata inputProof
|
|
143
|
+
) public virtual onlyAgent returns (euint64) {
|
|
144
|
+
euint64 burntAmount = _burn(account, FHE.fromExternal(encryptedAmount, inputProof));
|
|
145
|
+
FHE.allow(burntAmount, msg.sender);
|
|
146
|
+
return burntAmount;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/// @dev Burns confidential amount of tokens from account.
|
|
150
|
+
function confidentialBurn(address account, euint64 encryptedAmount) public virtual onlyAgent returns (euint64) {
|
|
151
|
+
require(
|
|
152
|
+
FHE.isAllowed(encryptedAmount, msg.sender),
|
|
153
|
+
ERC7984UnauthorizedUseOfEncryptedAmount(encryptedAmount, msg.sender)
|
|
154
|
+
);
|
|
155
|
+
euint64 burntAmount = _burn(account, encryptedAmount);
|
|
156
|
+
FHE.allow(burntAmount, msg.sender);
|
|
157
|
+
return burntAmount;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/// @dev Variant of {forceConfidentialTransferFrom-address-address-euint64} with an input proof.
|
|
161
|
+
function forceConfidentialTransferFrom(
|
|
162
|
+
address from,
|
|
163
|
+
address to,
|
|
164
|
+
externalEuint64 encryptedAmount,
|
|
165
|
+
bytes calldata inputProof
|
|
166
|
+
) public virtual onlyAgent returns (euint64) {
|
|
167
|
+
return _forceUpdate(from, to, FHE.fromExternal(encryptedAmount, inputProof));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @dev Force transfer callable by the role {AGENT_ROLE} which transfers tokens from `from` to `to` and
|
|
172
|
+
* bypasses the {ERC7984Restricted} (only on from) and https://docs.openzeppelin.com/contracts/api/utils#pausable[`++Pausable++`]
|
|
173
|
+
* checks. Frozen tokens are not transferred and must be unfrozen first.
|
|
174
|
+
*/
|
|
175
|
+
function forceConfidentialTransferFrom(
|
|
176
|
+
address from,
|
|
177
|
+
address to,
|
|
178
|
+
euint64 encryptedAmount
|
|
179
|
+
) public virtual onlyAgent returns (euint64 transferred) {
|
|
180
|
+
require(
|
|
181
|
+
FHE.isAllowed(encryptedAmount, msg.sender),
|
|
182
|
+
ERC7984UnauthorizedUseOfEncryptedAmount(encryptedAmount, msg.sender)
|
|
183
|
+
);
|
|
184
|
+
return _forceUpdate(from, to, encryptedAmount);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/// @inheritdoc ERC7984Freezable
|
|
188
|
+
function confidentialAvailable(
|
|
189
|
+
address account
|
|
190
|
+
) public virtual override(IERC7984Rwa, ERC7984Freezable) returns (euint64) {
|
|
191
|
+
return super.confidentialAvailable(account);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/// @inheritdoc ERC7984Freezable
|
|
195
|
+
function confidentialFrozen(
|
|
196
|
+
address account
|
|
197
|
+
) public view virtual override(IERC7984Rwa, ERC7984Freezable) returns (euint64) {
|
|
198
|
+
return super.confidentialFrozen(account);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/// @inheritdoc Pausable
|
|
202
|
+
function paused() public view virtual override(IERC7984Rwa, Pausable) returns (bool) {
|
|
203
|
+
return super.paused();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/// @inheritdoc ERC7984Restricted
|
|
207
|
+
function isUserAllowed(
|
|
208
|
+
address account
|
|
209
|
+
) public view virtual override(IERC7984Rwa, ERC7984Restricted) returns (bool) {
|
|
210
|
+
return super.isUserAllowed(account);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/// @dev Internal function which updates confidential balances while performing frozen and restriction compliance checks.
|
|
214
|
+
function _update(
|
|
215
|
+
address from,
|
|
216
|
+
address to,
|
|
217
|
+
euint64 encryptedAmount
|
|
218
|
+
) internal virtual override(ERC7984Freezable, ERC7984Restricted) whenNotPaused returns (euint64) {
|
|
219
|
+
// frozen and restriction checks performed through inheritance
|
|
220
|
+
return super._update(from, to, encryptedAmount);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/// @dev Internal function which forces transfer of confidential amount of tokens from account to account by skipping compliance checks.
|
|
224
|
+
function _forceUpdate(address from, address to, euint64 encryptedAmount) internal virtual returns (euint64) {
|
|
225
|
+
// bypassing `from` restriction check with {_checkSenderRestriction}. Still performing `to` restriction check.
|
|
226
|
+
// bypassing paused state by directly calling `super._update`
|
|
227
|
+
euint64 transferred = super._update(from, to, encryptedAmount);
|
|
228
|
+
FHE.allow(transferred, msg.sender);
|
|
229
|
+
return transferred;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @dev Bypasses the `from` restriction check when performing a {forceConfidentialTransferFrom}.
|
|
234
|
+
*/
|
|
235
|
+
function _checkSenderRestriction(address account) internal view override {
|
|
236
|
+
if (_isForceTransfer()) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
super._checkSenderRestriction(account);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/// @dev Private function which checks if the called function is a {forceConfidentialTransferFrom}.
|
|
243
|
+
function _isForceTransfer() private pure returns (bool) {
|
|
244
|
+
return
|
|
245
|
+
msg.sig == 0x6c9c3c85 || // bytes4(keccak256("forceConfidentialTransferFrom(address,address,bytes32)"))
|
|
246
|
+
msg.sig == 0x44fd6e40; // bytes4(keccak256("forceConfidentialTransferFrom(address,address,bytes32,bytes)"))
|
|
247
|
+
}
|
|
248
|
+
}
|
package/token/{extensions/ConfidentialFungibleTokenVotes.sol → ERC7984/extensions/ERC7984Votes.sol}
RENAMED
|
@@ -1,27 +1,21 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Confidential Contracts (last updated v0.
|
|
2
|
+
// OpenZeppelin Confidential Contracts (last updated v0.3.0) (token/ERC7984/extensions/ERC7984Votes.sol)
|
|
3
3
|
pragma solidity ^0.8.27;
|
|
4
4
|
|
|
5
5
|
import {euint64} from "@fhevm/solidity/lib/FHE.sol";
|
|
6
|
-
import {VotesConfidential} from "
|
|
7
|
-
import {
|
|
6
|
+
import {VotesConfidential} from "../../../governance/utils/VotesConfidential.sol";
|
|
7
|
+
import {ERC7984} from "./../ERC7984.sol";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* @dev Extension of {
|
|
10
|
+
* @dev Extension of {ERC7984} supporting confidential votes tracking and delegation.
|
|
11
11
|
*
|
|
12
|
-
* The amount of confidential voting units an account has is equal to the
|
|
12
|
+
* The amount of confidential voting units an account has is equal to the balance of
|
|
13
13
|
* that account. Voing power is taken into account when an account delegates votes to itself or to another
|
|
14
14
|
* account.
|
|
15
15
|
*/
|
|
16
|
-
abstract contract
|
|
17
|
-
/// @inheritdoc
|
|
18
|
-
function confidentialTotalSupply()
|
|
19
|
-
public
|
|
20
|
-
view
|
|
21
|
-
virtual
|
|
22
|
-
override(VotesConfidential, ConfidentialFungibleToken)
|
|
23
|
-
returns (euint64)
|
|
24
|
-
{
|
|
16
|
+
abstract contract ERC7984Votes is ERC7984, VotesConfidential {
|
|
17
|
+
/// @inheritdoc ERC7984
|
|
18
|
+
function confidentialTotalSupply() public view virtual override(VotesConfidential, ERC7984) returns (euint64) {
|
|
25
19
|
return super.confidentialTotalSupply();
|
|
26
20
|
}
|
|
27
21
|
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Confidential Contracts (last updated v0.
|
|
3
|
-
pragma solidity ^0.8.
|
|
2
|
+
// OpenZeppelin Confidential Contracts (last updated v0.3.0) (token/ERC7984/utils/ERC7984Utils.sol)
|
|
3
|
+
pragma solidity ^0.8.27;
|
|
4
4
|
|
|
5
5
|
import {FHE, ebool, euint64} from "@fhevm/solidity/lib/FHE.sol";
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import {IERC7984Receiver} from "../../../interfaces/IERC7984Receiver.sol";
|
|
8
|
+
import {ERC7984} from "../ERC7984.sol";
|
|
9
9
|
|
|
10
|
-
/// @dev Library that provides common {
|
|
11
|
-
library
|
|
10
|
+
/// @dev Library that provides common {ERC7984} utility functions.
|
|
11
|
+
library ERC7984Utils {
|
|
12
12
|
/**
|
|
13
13
|
* @dev Performs a transfer callback to the recipient of the transfer `to`. Should be invoked
|
|
14
|
-
* after all transfers "withCallback" on a {
|
|
14
|
+
* after all transfers "withCallback" on a {ERC7984}.
|
|
15
15
|
*
|
|
16
16
|
* The transfer callback is not invoked on the recipient if the recipient has no code (i.e. is an EOA). If the
|
|
17
17
|
* recipient has non-zero code, it must implement
|
|
18
|
-
* {
|
|
19
|
-
* whether the transfer was accepted or not. If the `ebool` is `false`, the transfer
|
|
18
|
+
* {IERC7984Receiver-onConfidentialTransferReceived} and return an `ebool` indicating
|
|
19
|
+
* whether the transfer was accepted or not. If the `ebool` is `false`, the transfer function
|
|
20
|
+
* should try to refund the `from` address.
|
|
20
21
|
*/
|
|
21
22
|
function checkOnTransferReceived(
|
|
22
23
|
address operator,
|
|
@@ -26,13 +27,13 @@ library ConfidentialFungibleTokenUtils {
|
|
|
26
27
|
bytes calldata data
|
|
27
28
|
) internal returns (ebool) {
|
|
28
29
|
if (to.code.length > 0) {
|
|
29
|
-
try
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
try IERC7984Receiver(to).onConfidentialTransferReceived(operator, from, amount, data) returns (
|
|
31
|
+
ebool retval
|
|
32
|
+
) {
|
|
32
33
|
return retval;
|
|
33
34
|
} catch (bytes memory reason) {
|
|
34
35
|
if (reason.length == 0) {
|
|
35
|
-
revert
|
|
36
|
+
revert ERC7984.ERC7984InvalidReceiver(to);
|
|
36
37
|
} else {
|
|
37
38
|
assembly ("memory-safe") {
|
|
38
39
|
revert(add(32, reason), mload(reason))
|