1
+ /*
2
+ Copyright 2021 Set Labs Inc.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ pragma solidity 0.6.10 ;
18
+ pragma experimental ABIEncoderV2;
19
+
20
+ import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol " ;
21
+ import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol " ;
22
+ import { AddressArrayUtils } from "../lib/AddressArrayUtils.sol " ;
23
+
24
+ import { IManagerIssuanceHook } from "../interfaces/IManagerIssuanceHook.sol " ;
25
+ import { ISetToken } from "../interfaces/ISetToken.sol " ;
26
+
27
+
28
+ /**
29
+ * @title SupplyCapAllowedCallerIssuanceHook
30
+ * @author Set Protocol
31
+ *
32
+ * Issuance hook that checks new issuances won't push SetToken totalSupply over supply cap and checks if caller is allowed
33
+ */
34
+ contract SupplyCapAllowedCallerIssuanceHook is Ownable , IManagerIssuanceHook {
35
+ using SafeMath for uint256 ;
36
+ using AddressArrayUtils for address [];
37
+
38
+ /* ============ Events ============ */
39
+
40
+ event SupplyCapUpdated (uint256 _newCap );
41
+ event CallerStatusUpdated (address indexed _caller , bool _status );
42
+ event AnyoneCallableUpdated (bool indexed _status );
43
+
44
+ /* ============ State Variables ============ */
45
+
46
+ // Cap on totalSupply of Sets
47
+ uint256 public supplyCap;
48
+
49
+ // Boolean indicating if anyone can call function
50
+ bool public anyoneCallable;
51
+
52
+ // Mapping of addresses allowed to call function
53
+ mapping (address => bool ) public callAllowList;
54
+
55
+ /* ============ Constructor ============ */
56
+
57
+ /**
58
+ * Constructor, overwrites owner and original supply cap.
59
+ *
60
+ * @param _initialOwner Owner address, overwrites Ownable logic which sets to deployer as default
61
+ * @param _supplyCap Supply cap for Set (in wei of Set)
62
+ */
63
+ constructor (
64
+ address _initialOwner ,
65
+ uint256 _supplyCap
66
+ )
67
+ public
68
+ {
69
+ supplyCap = _supplyCap;
70
+
71
+ // Overwrite _owner param of Ownable contract
72
+ transferOwnership (_initialOwner);
73
+ }
74
+
75
+ /* ============ External Functions ============ */
76
+
77
+ /**
78
+ * Adheres to IManagerIssuanceHook interface, and checks to make sure the current issue call won't push total supply over cap.
79
+ */
80
+ function invokePreIssueHook (
81
+ ISetToken _setToken ,
82
+ uint256 _issueQuantity ,
83
+ address _sender ,
84
+ address /*_to*/
85
+ )
86
+ external
87
+ override
88
+ {
89
+ uint256 totalSupply = _setToken.totalSupply ();
90
+ require (totalSupply.add (_issueQuantity) <= supplyCap, "Supply cap exceeded " );
91
+
92
+ _validateAllowedCaller (_sender);
93
+ }
94
+
95
+ /**
96
+ * Adheres to IManagerIssuanceHook interface
97
+ */
98
+ function invokePreRedeemHook (
99
+ ISetToken /* _setToken */ ,
100
+ uint256 /* _redeemQuantity */ ,
101
+ address _sender ,
102
+ address /* _to */
103
+ )
104
+ external
105
+ override
106
+ {
107
+ _validateAllowedCaller (_sender);
108
+ }
109
+
110
+ /**
111
+ * ONLY OWNER: Updates supply cap
112
+ */
113
+ function updateSupplyCap (uint256 _newCap ) external onlyOwner {
114
+ supplyCap = _newCap;
115
+ SupplyCapUpdated (_newCap);
116
+ }
117
+
118
+ /**
119
+ * ONLY OWNER: Toggle ability for passed addresses to call only allowed caller functions
120
+ *
121
+ * @param _callers Array of caller addresses to toggle status
122
+ * @param _statuses Array of statuses for each caller
123
+ */
124
+ function updateCallerStatus (address [] calldata _callers , bool [] calldata _statuses ) external onlyOwner {
125
+ require (_callers.length == _statuses.length , "Array length mismatch " );
126
+ require (_callers.length > 0 , "Array length must be > 0 " );
127
+ require (! _callers.hasDuplicate (), "Cannot duplicate callers " );
128
+
129
+ for (uint256 i = 0 ; i < _callers.length ; i++ ) {
130
+ address caller = _callers[i];
131
+ bool status = _statuses[i];
132
+ callAllowList[caller] = status;
133
+ emit CallerStatusUpdated (caller, status);
134
+ }
135
+ }
136
+
137
+ /**
138
+ * ONLY OWNER: Toggle whether anyone can call function, bypassing the callAllowlist
139
+ *
140
+ * @param _status Boolean indicating whether to allow anyone call
141
+ */
142
+ function updateAnyoneCallable (bool _status ) external onlyOwner {
143
+ anyoneCallable = _status;
144
+ emit AnyoneCallableUpdated (_status);
145
+ }
146
+
147
+ /* ============ Internal Functions ============ */
148
+
149
+ /**
150
+ * Validate if passed address is allowed to call function. If anyoneCallable set to true anyone can call otherwise needs to be approved or an EOA.
151
+ */
152
+ function _validateAllowedCaller (address _caller ) internal view {
153
+ bool isEOA = msg .sender == tx .origin ;
154
+
155
+ require (anyoneCallable || isEOA || callAllowList[_caller], "Address not permitted to call " );
156
+ }
157
+ }
0 commit comments