Skip to content

Commit 6b30dae

Browse files
authored
DelegatedManagerFactory tests & contract updates (#15)
1 parent bfe86c2 commit 6b30dae

File tree

7 files changed

+839
-37
lines changed

7 files changed

+839
-37
lines changed

contracts/factories/DelegatedManagerFactory.sol

Lines changed: 174 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2021 Set Labs Inc.
2+
Copyright 2022 Set Labs Inc.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -27,30 +27,96 @@ import { DelegatedManager } from "../manager/DelegatedManager.sol";
2727
import { IDelegatedManager } from "../interfaces/IDelegatedManager.sol";
2828
import { ISetTokenCreator } from "../interfaces/ISetTokenCreator.sol";
2929

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+
*/
3039
contract DelegatedManagerFactory {
3140
using AddressArrayUtils for address[];
3241
using Address for address;
3342

43+
/* ============ Structs ============ */
44+
3445
struct InitializeParams{
3546
address deployer;
3647
address owner;
3748
IDelegatedManager manager;
3849
bool isPending;
3950
}
40-
51+
52+
/* ============ Events ============ */
53+
54+
/**
55+
* @dev Emitted on DelegatedManager creation
56+
* @param _setToken Instance of the SetToken being levered
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 levered
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
4179
ISetTokenCreator public setTokenFactory;
80+
81+
// Mapping which stores manager creation metadata between creation and initialization steps
4282
mapping(ISetToken=>InitializeParams) public initializeState;
83+
84+
// Mapping of all sets that have succesfully initialized
4385
mapping(ISetToken=>bool) public isValidSet;
44-
address[] internal validSets;
4586

46-
constructor(
47-
ISetTokenCreator _setTokenFactory
48-
) public {
87+
// Address array of all sets that have succesfully initialized
88+
address[] internal validSets;
89+
90+
/* ============ Constructor ============ */
91+
92+
/**
93+
* @dev Sets setTokenFactory address.
94+
* @param _setTokenFactory Address of SetTokenFactory protocol contract
95+
*/
96+
constructor(ISetTokenCreator _setTokenFactory) public {
4997
setTokenFactory = _setTokenFactory;
5098
}
5199

52100
/* ============ External Functions ============ */
53101

102+
/**
103+
* ANYONE CAN CALL: Deploys a new SetToken and DelegatedManager. Sets some temporary metadata about
104+
* the deployment which will be read during a subsequent intialization step which wires everything
105+
* together.
106+
*
107+
* @param _components List of addresses of components for initial Positions
108+
* @param _units List of units. Each unit is the # of components per 10^18 of a SetToken
109+
* @param _name Name of the SetToken
110+
* @param _symbol Symbol of the SetToken
111+
* @param _owner Address to set as the DelegateManager's `owner` role
112+
* @param _methodologist Address to set as the DelegateManager's methodologist role
113+
* @param _modules List of modules to enable. All modules must be approved by the Controller
114+
* @param _operators List of operators authorized for the DelegateManager
115+
* @param _assets List of assets DelegateManager can trade. When empty, manager can trade any asset
116+
* @param _extensions List of extensions authorized for the DelegateManager
117+
*
118+
* @return (ISetToken, address) The created SetToken and DelegatedManager addresses, respectively
119+
*/
54120
function createSetAndManager(
55121
address[] memory _components,
56122
int256[] memory _units,
@@ -66,9 +132,9 @@ contract DelegatedManagerFactory {
66132
external
67133
returns (ISetToken, address)
68134
{
69-
require(_extensions.length > 0, "Must have at least 1 extension");
70-
// Require that components of Set are contained in the _assets array
71-
// Require there be at least one operator?
135+
if (_assets.length != 0) {
136+
_validateComponentsIncludedInAssetsList(_components, _assets);
137+
}
72138

73139
ISetToken setToken = _deploySet(
74140
_components,
@@ -91,6 +157,24 @@ contract DelegatedManagerFactory {
91157
return (setToken, address(manager));
92158
}
93159

160+
/**
161+
* ONLY SETTOKEN MANAGER: Deploys a DelegatedManager and sets some temporary metadata about the
162+
* deployment which will be read during a subsequent intialization step which wires everything together.
163+
* This method is used when migrating an existing SetToken to the DelegatedManager system.
164+
*
165+
* (Note: This flow should work well for SetTokens managed by an EOA. However, existing
166+
* contract-managed Sets may need to have their ownership temporarily transferred to an EOA when
167+
* migrating. We don't anticipate high demand for this migration case though.)
168+
*
169+
* @param _setToken Instance of SetToken to migrate to the DelegatedManager system
170+
* @param _owner Address to set as the DelegateManager's `owner` role
171+
* @param _methodologist Address to set as the DelegateManager's methodologist role
172+
* @param _operators List of operators authorized for the DelegateManager
173+
* @param _assets List of assets DelegateManager can trade. When empty, manager can trade any asset
174+
* @param _extensions List of extensions authorized for the DelegateManager
175+
*
176+
* @return (address) Address of the created DelegatedManager
177+
*/
94178
function createManager(
95179
ISetToken _setToken,
96180
address _owner,
@@ -102,6 +186,10 @@ contract DelegatedManagerFactory {
102186
external
103187
returns (address)
104188
{
189+
if (_assets.length != 0) {
190+
_validateComponentsIncludedInAssetsList(_setToken.getComponents(), _assets);
191+
}
192+
105193
require(msg.sender == _setToken.manager(), "Must be manager");
106194

107195
DelegatedManager manager = _deployManager(
@@ -117,6 +205,16 @@ contract DelegatedManagerFactory {
117205
return address(manager);
118206
}
119207

208+
/**
209+
* ONLY DEPLOYER: Wires SetToken, DelegatedManager, global manager extensions, and modules together
210+
* into a functioning package.
211+
*
212+
* @param _setToken Instance of the SetToken
213+
* @param _ownerFeeSplit Percent of fees in precise units (10^16 = 1%) sent to operator, rest to methodologist
214+
* @param _ownerFeeRecipient Address which receives operator's share of fees when they're distributed
215+
* @param _initializeTargets List of addresses of any extensions or modules which need to be initialized
216+
* @param _initializeBytecode List of bytecode encoded calls to relevant target's initialize function
217+
*/
120218
function initialize(
121219
ISetToken _setToken,
122220
uint256 _ownerFeeSplit,
@@ -138,20 +236,41 @@ contract DelegatedManagerFactory {
138236
_initializeTargets[i].functionCallWithValue(_initializeBytecode[i], 0);
139237
}
140238

141-
_setToken.setManager(address(manager));
239+
if (_setToken.manager() == address(this)) {
240+
_setToken.setManager(address(manager));
241+
}
242+
142243
initializeState[_setToken].manager.transferOwnership(initializeState[_setToken].owner);
143244

144245
delete initializeState[_setToken];
246+
emit DelegatedManagerInitialized(_setToken, manager);
145247
}
146248

147249
/* ============ External View Functions ============ */
148250

251+
/**
252+
* Returns list of sets that have been successfully initialized by this factory
253+
*
254+
* @return address[] List of valid sets
255+
*/
149256
function getValidSets() external view returns (address[] memory) {
150257
return validSets;
151258
}
152259

153260
/* ============ Internal Functions ============ */
154261

262+
/**
263+
* Deploys a SetToken, setting this factory as its manager temporarily, pending initialization.
264+
* Managership is transferred to a newly created DelegatedManager during `initialize`
265+
*
266+
* @param _components List of addresses of components for initial Positions
267+
* @param _units List of units. Each unit is the # of components per 10^18 of a SetToken
268+
* @param _modules List of modules to enable. All modules must be approved by the Controller
269+
* @param _name Name of the SetToken
270+
* @param _symbol Symbol of the SetToken
271+
*
272+
* @return Address of created SetToken;
273+
*/
155274
function _deploySet(
156275
address[] memory _components,
157276
int256[] memory _units,
@@ -166,14 +285,26 @@ contract DelegatedManagerFactory {
166285
_components,
167286
_units,
168287
_modules,
169-
address(this), // Set Manager to this address so can xfer to manager deployed in next step
288+
address(this),
170289
_name,
171290
_symbol
172291
);
173292

174293
return ISetToken(setToken);
175294
}
176295

296+
297+
/**
298+
* Deploys a DelegatedManager
299+
*
300+
* @param _setToken Instance of SetToken to migrate to the DelegatedManager system
301+
* @param _methodologist Address to set as the DelegateManager's methodologist role
302+
* @param _extensions List of extensions authorized for the DelegateManager
303+
* @param _operators List of operators authorized for the DelegateManager
304+
* @param _assets List of assets DelegateManager can trade. When empty, manager can trade any asset
305+
*
306+
* @return Address of created DelegatedManager
307+
*/
177308
function _deployManager(
178309
ISetToken _setToken,
179310
address _methodologist,
@@ -194,10 +325,24 @@ contract DelegatedManagerFactory {
194325
_assets,
195326
useAssetAllowlist
196327
);
197-
// emit ManagerCreated(address(setToken), _manager, _name, _symbol);
328+
329+
emit DelegatedManagerCreated(
330+
_setToken,
331+
newManager,
332+
msg.sender
333+
);
334+
198335
return newManager;
199336
}
200337

338+
/**
339+
* Stores temporary creation metadata during the contract creation step. Data is retrieved, read and
340+
* finally deleted during `initialize`.
341+
*
342+
* @param _setToken Instance of SetToken
343+
* @param _manager Address of DelegatedManager created for SetToken
344+
* @param _owner Address that will be given the `owner` DelegatedManager's role on initialization
345+
*/
201346
function _setInitializationState(
202347
ISetToken _setToken,
203348
address _manager,
@@ -213,4 +358,21 @@ contract DelegatedManagerFactory {
213358
isValidSet[_setToken] = true;
214359
validSets.push(address(_setToken));
215360
}
361+
362+
363+
/**
364+
* Validates that all SetToken components are included in the assets whitelist. This prevents the
365+
* DelegatedManager from being initialized with some components in an untrade-able state.
366+
*
367+
* @param _components List of addresses of components for initial Positions
368+
* @param _assets List of assets DelegateManager can trade.
369+
*/
370+
function _validateComponentsIncludedInAssetsList(
371+
address[] memory _components,
372+
address[] memory _assets
373+
) internal pure {
374+
for (uint256 i = 0; i < _components.length; i++) {
375+
require(_assets.contains(_components[i]), "Asset list must include all components");
376+
}
377+
}
216378
}

0 commit comments

Comments
 (0)