-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathERC3643ComplianceModule.sol
More file actions
109 lines (93 loc) · 4.32 KB
/
Copy pathERC3643ComplianceModule.sol
File metadata and controls
109 lines (93 loc) · 4.32 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
//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";
import {ERC3643ComplianceModuleInvariantStorage} from "./library/ERC3643ComplianceModuleInvariantStorage.sol";
abstract contract ERC3643ComplianceModule is
Context,
IERC3643Compliance,
ERC3643ComplianceModuleInvariantStorage
{
/* ==== Type declaration === */
using EnumerableSet for EnumerableSet.AddressSet;
/* ==== State Variables === */
// Token binding tracking
EnumerableSet.AddressSet internal _boundTokens;
/* ==== 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.
* @custom:security-note Operation rules (stateful rules such as `RuleConditionalTransferLight`
* or `RuleMintAllowance`) maintain per-address accounting that is shared across all bound tokens.
* Binding tokens from different issuers to the same engine will silently cross-contaminate
* their accounting. Only bind 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;
}