@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.
- package/build/contracts/Checkpoints.json +2 -2
- package/build/contracts/CheckpointsConfidential.json +2 -2
- package/build/contracts/{ConfidentialFungibleToken.json → ERC7984.json} +28 -33
- package/build/contracts/{ConfidentialFungibleTokenERC20Wrapper.json → ERC7984ERC20Wrapper.json} +34 -39
- package/build/contracts/ERC7984Freezable.json +666 -0
- package/build/contracts/ERC7984ObserverAccess.json +676 -0
- package/build/contracts/ERC7984Omnibus.json +994 -0
- package/build/contracts/ERC7984Restricted.json +677 -0
- package/build/contracts/ERC7984Rwa.json +1370 -0
- package/build/contracts/{ConfidentialFungibleTokenUtils.json → ERC7984Utils.json} +4 -4
- package/build/contracts/{ConfidentialFungibleTokenVotes.json → ERC7984Votes.json} +76 -81
- package/build/contracts/FHESafeMath.json +2 -2
- package/build/contracts/{IConfidentialFungibleToken.json → IERC7984.json} +15 -15
- 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/VestingWalletConfidential.sol +6 -9
- package/finance/VestingWalletConfidentialFactory.sol +7 -12
- package/interfaces/{IConfidentialFungibleToken.sol → IERC7984.sol} +5 -5
- package/interfaces/{IConfidentialFungibleTokenReceiver.sol → IERC7984Receiver.sol} +3 -3
- package/interfaces/IERC7984Rwa.sol +64 -0
- package/package.json +4 -4
- package/token/{ConfidentialFungibleToken.sol → ERC7984/ERC7984.sol} +68 -76
- package/token/{extensions/ConfidentialFungibleTokenERC20Wrapper.sol → ERC7984/extensions/ERC7984ERC20Wrapper.sol} +18 -20
- package/token/ERC7984/extensions/ERC7984Freezable.sol +66 -0
- package/token/ERC7984/extensions/ERC7984ObserverAccess.sol +63 -0
- package/token/ERC7984/extensions/ERC7984Omnibus.sol +209 -0
- package/token/ERC7984/extensions/ERC7984Restricted.sol +118 -0
- package/token/ERC7984/extensions/ERC7984Rwa.sol +236 -0
- package/token/{extensions/ConfidentialFungibleTokenVotes.sol → ERC7984/extensions/ERC7984Votes.sol} +8 -14
- package/token/{utils/ConfidentialFungibleTokenUtils.sol → ERC7984/utils/ERC7984Utils.sol} +12 -12
- package/utils/FHESafeMath.sol +42 -7
- 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
|
+
// 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 {
|
|
12
|
+
import {ERC7984} from "./../ERC7984.sol";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @dev A wrapper contract built on top of {
|
|
16
|
-
* into
|
|
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
|
|
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
|
|
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,
|
|
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(
|
|
134
|
-
|
|
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),
|
|
137
|
+
require(to != address(0), ERC7984InvalidGatewayRequest(requestID));
|
|
137
138
|
delete _receivers[requestID];
|
|
138
139
|
|
|
139
|
-
SafeERC20.safeTransfer(underlying(), to,
|
|
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),
|
|
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
|
+
}
|