1
+ /*
2
+ Copyright 2022 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
+ SPDX-License-Identifier: Apache License, Version 2.0
17
+ */
18
+
19
+ pragma solidity 0.6.10 ;
20
+ pragma experimental ABIEncoderV2;
21
+
22
+ import { Address } from "@openzeppelin/contracts/utils/Address.sol " ;
23
+ import { ISetToken } from "@setprotocol/set-protocol-v2/contracts/interfaces/ISetToken.sol " ;
24
+
25
+ import { AddressArrayUtils } from "../lib/AddressArrayUtils.sol " ;
26
+ import { DelegatedManager } from "../manager/DelegatedManager.sol " ;
27
+ import { IDelegatedManager } from "../interfaces/IDelegatedManager.sol " ;
28
+ import { ISetTokenCreator } from "../interfaces/ISetTokenCreator.sol " ;
29
+
30
+ /**
31
+ * @title DelegatedManagerFactory
32
+ * @author Set Protocol
33
+ *
34
+ * Factory smart contract which gives asset managers the ability to:
35
+ * > create a Set Token managed with a DelegatedManager contract
36
+ * > create a DelegatedManager contract for an existing Set Token to migrate to
37
+ * > initialize extensions and modules for SetTokens using the DelegatedManager system
38
+ */
39
+ contract DelegatedManagerFactory {
40
+ using AddressArrayUtils for address [];
41
+ using Address for address ;
42
+
43
+ /* ============ Structs ============ */
44
+
45
+ struct InitializeParams {
46
+ address deployer;
47
+ address owner;
48
+ IDelegatedManager manager;
49
+ bool isPending;
50
+ }
51
+
52
+ /* ============ Events ============ */
53
+
54
+ /**
55
+ * @dev Emitted on DelegatedManager creation
56
+ * @param _setToken Instance of the SetToken being created
57
+ * @param _manager Address of the DelegatedManager
58
+ * @param _deployer Address of the deployer
59
+ */
60
+ event DelegatedManagerCreated (
61
+ ISetToken indexed _setToken ,
62
+ DelegatedManager indexed _manager ,
63
+ address _deployer
64
+ );
65
+
66
+ /**
67
+ * @dev Emitted on DelegatedManager initialization
68
+ * @param _setToken Instance of the SetToken being initialized
69
+ * @param _manager Address of the DelegatedManager owner
70
+ */
71
+ event DelegatedManagerInitialized (
72
+ ISetToken indexed _setToken ,
73
+ IDelegatedManager indexed _manager
74
+ );
75
+
76
+ /* ============ State Variables ============ */
77
+
78
+ // SetTokenFactory address
79
+ ISetTokenCreator public setTokenFactory;
80
+
81
+ // Mapping which stores manager creation metadata between creation and initialization steps
82
+ mapping (ISetToken=> InitializeParams) public initializeState;
83
+
84
+ /* ============ Constructor ============ */
85
+
86
+ /**
87
+ * @dev Sets setTokenFactory address.
88
+ * @param _setTokenFactory Address of SetTokenFactory protocol contract
89
+ */
90
+ constructor (ISetTokenCreator _setTokenFactory ) public {
91
+ setTokenFactory = _setTokenFactory;
92
+ }
93
+
94
+ /* ============ External Functions ============ */
95
+
96
+ /**
97
+ * ANYONE CAN CALL: Deploys a new SetToken and DelegatedManager. Sets some temporary metadata about
98
+ * the deployment which will be read during a subsequent intialization step which wires everything
99
+ * together.
100
+ *
101
+ * @param _components List of addresses of components for initial Positions
102
+ * @param _units List of units. Each unit is the # of components per 10^18 of a SetToken
103
+ * @param _name Name of the SetToken
104
+ * @param _symbol Symbol of the SetToken
105
+ * @param _owner Address to set as the DelegateManager's `owner` role
106
+ * @param _methodologist Address to set as the DelegateManager's methodologist role
107
+ * @param _modules List of modules to enable. All modules must be approved by the Controller
108
+ * @param _operators List of operators authorized for the DelegateManager
109
+ * @param _assets List of assets DelegateManager can trade. When empty, asset allow list is not enforced
110
+ * @param _extensions List of extensions authorized for the DelegateManager
111
+ *
112
+ * @return (ISetToken, address) The created SetToken and DelegatedManager addresses, respectively
113
+ */
114
+ function createSetAndManager (
115
+ address [] memory _components ,
116
+ int256 [] memory _units ,
117
+ string memory _name ,
118
+ string memory _symbol ,
119
+ address _owner ,
120
+ address _methodologist ,
121
+ address [] memory _modules ,
122
+ address [] memory _operators ,
123
+ address [] memory _assets ,
124
+ address [] memory _extensions
125
+ )
126
+ external
127
+ returns (ISetToken, address )
128
+ {
129
+ _validateManagerParameters (_components, _extensions, _assets);
130
+
131
+ ISetToken setToken = _deploySet (
132
+ _components,
133
+ _units,
134
+ _modules,
135
+ _name,
136
+ _symbol
137
+ );
138
+
139
+ DelegatedManager manager = _deployManager (
140
+ setToken,
141
+ _methodologist,
142
+ _extensions,
143
+ _operators,
144
+ _assets
145
+ );
146
+
147
+ _setInitializationState (setToken, address (manager), _owner);
148
+
149
+ return (setToken, address (manager));
150
+ }
151
+
152
+ /**
153
+ * ONLY SETTOKEN MANAGER: Deploys a DelegatedManager and sets some temporary metadata about the
154
+ * deployment which will be read during a subsequent intialization step which wires everything together.
155
+ * This method is used when migrating an existing SetToken to the DelegatedManager system.
156
+ *
157
+ * (Note: This flow should work well for SetTokens managed by an EOA. However, existing
158
+ * contract-managed Sets may need to have their ownership temporarily transferred to an EOA when
159
+ * migrating. We don't anticipate high demand for this migration case though.)
160
+ *
161
+ * @param _setToken Instance of SetToken to migrate to the DelegatedManager system
162
+ * @param _owner Address to set as the DelegateManager's `owner` role
163
+ * @param _methodologist Address to set as the DelegateManager's methodologist role
164
+ * @param _operators List of operators authorized for the DelegateManager
165
+ * @param _assets List of assets DelegateManager can trade. When empty, asset allow list is not enforced
166
+ * @param _extensions List of extensions authorized for the DelegateManager
167
+ *
168
+ * @return (address) Address of the created DelegatedManager
169
+ */
170
+ function createManager (
171
+ ISetToken _setToken ,
172
+ address _owner ,
173
+ address _methodologist ,
174
+ address [] memory _operators ,
175
+ address [] memory _assets ,
176
+ address [] memory _extensions
177
+ )
178
+ external
179
+ returns (address )
180
+ {
181
+ require (msg .sender == _setToken.manager (), "Must be manager " );
182
+
183
+ _validateManagerParameters (_setToken.getComponents (), _extensions, _assets);
184
+
185
+ DelegatedManager manager = _deployManager (
186
+ _setToken,
187
+ _methodologist,
188
+ _extensions,
189
+ _operators,
190
+ _assets
191
+ );
192
+
193
+ _setInitializationState (_setToken, address (manager), _owner);
194
+
195
+ return address (manager);
196
+ }
197
+
198
+ /**
199
+ * ONLY DEPLOYER: Wires SetToken, DelegatedManager, global manager extensions, and modules together
200
+ * into a functioning package.
201
+ *
202
+ * NOTE: When migrating to this manager system from an existing SetToken, the SetToken's current manager address
203
+ * must be reset to point at the newly deployed DelegatedManager contract in a separate, final transaction.
204
+ *
205
+ *
206
+ * @param _setToken Instance of the SetToken
207
+ * @param _ownerFeeSplit Percent of fees in precise units (10^16 = 1%) sent to operator, rest to methodologist
208
+ * @param _ownerFeeRecipient Address which receives owner's share of fees when they're distributed
209
+ * @param _initializeTargets List of addresses of any extensions or modules which need to be initialized
210
+ * @param _initializeBytecode List of bytecode encoded calls to relevant target's initialize function
211
+ */
212
+ function initialize (
213
+ ISetToken _setToken ,
214
+ uint256 _ownerFeeSplit ,
215
+ address _ownerFeeRecipient ,
216
+ address [] memory _initializeTargets ,
217
+ bytes [] memory _initializeBytecode
218
+ )
219
+ external
220
+ {
221
+ require (initializeState[_setToken].isPending, "Manager must be awaiting initialization " );
222
+ require (msg .sender == initializeState[_setToken].deployer, "Only deployer can initialize manager " );
223
+ _initializeTargets.validatePairsWithArray (_initializeBytecode);
224
+
225
+ IDelegatedManager manager = initializeState[_setToken].manager;
226
+ manager.updateOwnerFeeSplit (_ownerFeeSplit);
227
+ manager.updateOwnerFeeRecipient (_ownerFeeRecipient);
228
+
229
+ for (uint256 i = 0 ; i < _initializeTargets.length ; i++ ) {
230
+ // Because we validate uniqueness of _initializeTargets only one transaction can be sent to each module or extension during this
231
+ // transaction. Due to this no modules/extension can be used for any SetToken transactions other than initializing these contracts
232
+ _initializeTargets[i].functionCallWithValue (_initializeBytecode[i], 0 );
233
+ }
234
+
235
+ // If the SetToken was factory-deployed & factory is its current `manager`, transfer
236
+ // managership to the new DelegatedManager
237
+ if (_setToken.manager () == address (this )) {
238
+ _setToken.setManager (address (manager));
239
+ }
240
+
241
+ manager.transferOwnership (initializeState[_setToken].owner);
242
+
243
+ delete initializeState[_setToken];
244
+
245
+ emit DelegatedManagerInitialized (_setToken, manager);
246
+ }
247
+
248
+ /* ============ Internal Functions ============ */
249
+
250
+ /**
251
+ * Deploys a SetToken, setting this factory as its manager temporarily, pending initialization.
252
+ * Managership is transferred to a newly created DelegatedManager during `initialize`
253
+ *
254
+ * @param _components List of addresses of components for initial Positions
255
+ * @param _units List of units. Each unit is the # of components per 10^18 of a SetToken
256
+ * @param _modules List of modules to enable. All modules must be approved by the Controller
257
+ * @param _name Name of the SetToken
258
+ * @param _symbol Symbol of the SetToken
259
+ *
260
+ * @return Address of created SetToken;
261
+ */
262
+ function _deploySet (
263
+ address [] memory _components ,
264
+ int256 [] memory _units ,
265
+ address [] memory _modules ,
266
+ string memory _name ,
267
+ string memory _symbol
268
+ )
269
+ internal
270
+ returns (ISetToken)
271
+ {
272
+ address setToken = setTokenFactory.create (
273
+ _components,
274
+ _units,
275
+ _modules,
276
+ address (this ),
277
+ _name,
278
+ _symbol
279
+ );
280
+
281
+ return ISetToken (setToken);
282
+ }
283
+
284
+ /**
285
+ * Deploys a DelegatedManager
286
+ *
287
+ * @param _setToken Instance of SetToken to migrate to the DelegatedManager system
288
+ * @param _methodologist Address to set as the DelegateManager's methodologist role
289
+ * @param _extensions List of extensions authorized for the DelegateManager
290
+ * @param _operators List of operators authorized for the DelegateManager
291
+ * @param _assets List of assets DelegateManager can trade. When empty, asset allow list is not enforced
292
+ *
293
+ * @return Address of created DelegatedManager
294
+ */
295
+ function _deployManager (
296
+ ISetToken _setToken ,
297
+ address _methodologist ,
298
+ address [] memory _extensions ,
299
+ address [] memory _operators ,
300
+ address [] memory _assets
301
+ )
302
+ internal
303
+ returns (DelegatedManager)
304
+ {
305
+ // If asset array is empty, manager's useAssetAllowList will be set to false
306
+ // and the asset allow list is not enforced
307
+ bool useAssetAllowlist = _assets.length > 0 ;
308
+
309
+ DelegatedManager newManager = new DelegatedManager (
310
+ _setToken,
311
+ address (this ),
312
+ _methodologist,
313
+ _extensions,
314
+ _operators,
315
+ _assets,
316
+ useAssetAllowlist
317
+ );
318
+
319
+ emit DelegatedManagerCreated (
320
+ _setToken,
321
+ newManager,
322
+ msg .sender
323
+ );
324
+
325
+ return newManager;
326
+ }
327
+
328
+ /**
329
+ * Stores temporary creation metadata during the contract creation step. Data is retrieved, read and
330
+ * finally deleted during `initialize`.
331
+ *
332
+ * @param _setToken Instance of SetToken
333
+ * @param _manager Address of DelegatedManager created for SetToken
334
+ * @param _owner Address that will be given the `owner` DelegatedManager's role on initialization
335
+ */
336
+ function _setInitializationState (
337
+ ISetToken _setToken ,
338
+ address _manager ,
339
+ address _owner
340
+ ) internal {
341
+ initializeState[_setToken] = InitializeParams ({
342
+ deployer: msg .sender ,
343
+ owner: _owner,
344
+ manager: IDelegatedManager (_manager),
345
+ isPending: true
346
+ });
347
+ }
348
+
349
+ /**
350
+ * Validates that all components currently held by the Set are on the asset allow list. Validate that the manager is
351
+ * deployed with at least one extension in the PENDING state.
352
+ *
353
+ * @param _components List of addresses of components for initial/current Set positions
354
+ * @param _extensions List of extensions authorized for the DelegateManager
355
+ * @param _assets List of assets DelegateManager can trade. When empty, asset allow list is not enforced
356
+ */
357
+ function _validateManagerParameters (
358
+ address [] memory _components ,
359
+ address [] memory _extensions ,
360
+ address [] memory _assets
361
+ )
362
+ internal
363
+ pure
364
+ {
365
+ require (_extensions.length > 0 , "Must have at least 1 extension " );
366
+
367
+ if (_assets.length != 0 ) {
368
+ _validateComponentsIncludedInAssetsList (_components, _assets);
369
+ }
370
+ }
371
+
372
+ /**
373
+ * Validates that all SetToken components are included in the assets whitelist. This prevents the
374
+ * DelegatedManager from being initialized with some components in an untrade-able state.
375
+ *
376
+ * @param _components List of addresses of components for initial Positions
377
+ * @param _assets List of assets DelegateManager can trade.
378
+ */
379
+ function _validateComponentsIncludedInAssetsList (
380
+ address [] memory _components ,
381
+ address [] memory _assets
382
+ ) internal pure {
383
+ for (uint256 i = 0 ; i < _components.length ; i++ ) {
384
+ require (_assets.contains (_components[i]), "Asset list must include all components " );
385
+ }
386
+ }
387
+ }
0 commit comments