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