-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathERC3643ComplianceModule.sol
More file actions
110 lines (93 loc) · 4.27 KB
/
ERC3643ComplianceModule.sol
File metadata and controls
110 lines (93 loc) · 4.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//SPDX-License-Identifier: MPL-2.0
pragma solidity ^0.8.20;
/* ==== OpenZeppelin === */
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
/* ==== Interface and other library === */
import {IERC3643Compliance} from "../interfaces/IERC3643Compliance.sol";
abstract contract ERC3643ComplianceModule is Context, IERC3643Compliance {
/* ==== Type declaration === */
using EnumerableSet for EnumerableSet.AddressSet;
/* ==== State Variables === */
// Token binding tracking
EnumerableSet.AddressSet internal _boundTokens;
// Access Control
// Will not be present in the final bytecode if not used
bytes32 public constant COMPLIANCE_MANAGER_ROLE = keccak256("COMPLIANCE_MANAGER_ROLE");
/* ==== Errors === */
error RuleEngine_ERC3643Compliance_InvalidTokenAddress();
error RuleEngine_ERC3643Compliance_TokenAlreadyBound();
error RuleEngine_ERC3643Compliance_TokenNotBound();
error RuleEngine_ERC3643Compliance_UnauthorizedCaller();
error RuleEngine_ERC3643Compliance_OperationNotSuccessful();
/* ==== Modifier === */
modifier onlyBoundToken() {
_checkBoundToken();
_;
}
modifier onlyComplianceManager() {
_onlyComplianceManager();
_;
}
/*//////////////////////////////////////////////////////////////
PUBLIC/public FUNCTIONS
//////////////////////////////////////////////////////////////*/
/* ============ State functions ============ */
/**
* @inheritdoc IERC3643Compliance
* @dev Operator warning: "multi-tenant" means one RuleEngine is shared by
* multiple token contracts. In that setup, bind only tokens that are equally
* trusted and governed together.
*/
function bindToken(address token) public virtual override {
_authorizeComplianceBindingChange(token);
_bindToken(token);
}
/**
* @inheritdoc IERC3643Compliance
* @dev Operator warning: unbinding is an administrative operation and does not
* erase any state already stored by external rule contracts in a previously
* shared ("multi-tenant") setup.
*/
function unbindToken(address token) public virtual override {
_authorizeComplianceBindingChange(token);
_unbindToken(token);
}
/// @inheritdoc IERC3643Compliance
function isTokenBound(address token) public view virtual override returns (bool) {
return _boundTokens.contains(token);
}
/// @inheritdoc IERC3643Compliance
function getTokenBound() public view virtual override returns (address) {
if (_boundTokens.length() > 0) {
// Note that there are no guarantees on the ordering of values inside the array,
// and it may change when more values are added or removed.
return _boundTokens.at(0);
} else {
return address(0);
}
}
/*//////////////////////////////////////////////////////////////
INTERNAL/PRIVATE FUNCTIONS
//////////////////////////////////////////////////////////////*/
function _unbindToken(address token) internal {
require(_boundTokens.contains(token), RuleEngine_ERC3643Compliance_TokenNotBound());
// Should never revert because we check if the token address is already set before
require(_boundTokens.remove(token), RuleEngine_ERC3643Compliance_OperationNotSuccessful());
emit TokenUnbound(token);
}
function _bindToken(address token) internal {
require(token != address(0), RuleEngine_ERC3643Compliance_InvalidTokenAddress());
require(!_boundTokens.contains(token), RuleEngine_ERC3643Compliance_TokenAlreadyBound());
// Should never revert because we check if the token address is already set before
require(_boundTokens.add(token), RuleEngine_ERC3643Compliance_OperationNotSuccessful());
emit TokenBound(token);
}
function _checkBoundToken() internal view virtual {
if (!_boundTokens.contains(_msgSender())) {
revert RuleEngine_ERC3643Compliance_UnauthorizedCaller();
}
}
function _authorizeComplianceBindingChange(address token) internal virtual;
function _onlyComplianceManager() internal virtual;
}