-
Notifications
You must be signed in to change notification settings - Fork 104
/
MISOTokenFactory.sol
346 lines (305 loc) · 12.6 KB
/
MISOTokenFactory.sol
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
pragma solidity 0.6.12;
//----------------------------------------------------------------------------------
// I n s t a n t
//
// .:mmm. .:mmm:. .ii. .:SSSSSSSSSSSSS. .oOOOOOOOOOOOo.
// .mMM'':Mm. .:MM'':Mm:. .II: :SSs.......... .oOO'''''''''''OOo.
// .:Mm' ':Mm. .:Mm' 'MM:. .II: 'sSSSSSSSSSSSSS:. :OO. .OO:
// .'mMm' ':MM:.:MMm' ':MM:. .II: .:...........:SS. 'OOo:.........:oOO'
// 'mMm' ':MMmm' 'mMm: II: 'sSSSSSSSSSSSSS' 'oOOOOOOOOOOOO'
//
//----------------------------------------------------------------------------------
//
// Chef Gonpachi's MISO Token Factory
//
// A factory to conveniently deploy your own source code verified token contracts
//
// Inspired by Bokky's EtherVendingMachince.io
// https://github.com/bokkypoobah/FixedSupplyTokenFactory
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// Made for Sushi.com
//
// Enjoy. (c) Chef Gonpachi 2021
// <https://github.com/chefgonpachi/MISO/>
//
// ---------------------------------------------------------------------
// SPDX-License-Identifier: GPL-3.0
// ---------------------------------------------------------------------
import "./Utils/CloneFactory.sol";
import "./interfaces/IMisoToken.sol";
import "./Access/MISOAccessControls.sol";
import "./Utils/SafeTransfer.sol";
import "./interfaces/IERC20.sol";
contract MISOTokenFactory is CloneFactory, SafeTransfer{
/// @notice Responsible for access rights to the contract
MISOAccessControls public accessControls;
bytes32 public constant TOKEN_MINTER_ROLE = keccak256("TOKEN_MINTER_ROLE");
/// @notice Whether token factory has been initialized or not.
bool private initialised;
/// @notice Struct to track Token template.
struct Token {
bool exists;
uint256 templateId;
uint256 index;
}
/// @notice Mapping from auction address created through this contract to Auction struct.
mapping(address => Token) public tokenInfo;
/// @notice Array of tokens created using the factory.
address[] public tokens;
/// @notice Template id to track respective token template.
uint256 public tokenTemplateId;
/// @notice Mapping from token template id to token template address.
mapping(uint256 => address) private tokenTemplates;
/// @notice mapping from token template address to token template id
mapping(address => uint256) private tokenTemplateToId;
/// @notice mapping from template type to template id
mapping(uint256 => uint256) public currentTemplateId;
/// @notice Minimum fee to create a token through the factory.
uint256 public minimumFee;
uint256 public integratorFeePct;
/// @notice Contract locked status. If locked, only minters can deploy
bool public locked;
/// @notice Any MISO dividends collected are sent here.
address payable public misoDiv;
/// @notice Event emitted when first initializing Miso Token Factory.
event MisoInitTokenFactory(address sender);
/// @notice Event emitted when a token is created using template id.
event TokenCreated(address indexed owner, address indexed addr, address tokenTemplate);
/// @notice event emitted when a token is initialized using template id
event TokenInitialized(address indexed addr, uint256 templateId, bytes data);
/// @notice Event emitted when a token template is added.
event TokenTemplateAdded(address newToken, uint256 templateId);
/// @notice Event emitted when a token template is removed.
event TokenTemplateRemoved(address token, uint256 templateId);
constructor() public {
}
/**
* @notice Single gateway to initialize the MISO Token Factory with proper address.
* @dev Can only be initialized once.
* @param _accessControls Sets address to get the access controls from.
*/
/// @dev GP: Migrate to the BentoBox.
function initMISOTokenFactory(address _accessControls) external {
require(!initialised);
initialised = true;
locked = true;
accessControls = MISOAccessControls(_accessControls);
emit MisoInitTokenFactory(msg.sender);
}
/**
* @notice Sets the minimum fee.
* @param _amount Fee amount.
*/
function setMinimumFee(uint256 _amount) external {
require(
accessControls.hasAdminRole(msg.sender),
"MISOTokenFactory: Sender must be operator"
);
minimumFee = _amount;
}
/**
* @notice Sets integrator fee percentage.
* @param _amount Percentage amount.
*/
function setIntegratorFeePct(uint256 _amount) external {
require(
accessControls.hasAdminRole(msg.sender),
"MISOTokenFactory: Sender must be operator"
);
/// @dev this is out of 1000, ie 25% = 250
require(
_amount <= 1000,
"MISOTokenFactory: Range is from 0 to 1000"
);
integratorFeePct = _amount;
}
/**
* @notice Sets dividend address.
* @param _divaddr Dividend address.
*/
function setDividends(address payable _divaddr) external {
require(
accessControls.hasAdminRole(msg.sender),
"MISOTokenFactory: Sender must be operator"
);
require(_divaddr != address(0));
misoDiv = _divaddr;
}
/**
* @notice Sets the factory to be locked or unlocked.
* @param _locked bool.
*/
function setLocked(bool _locked) external {
require(
accessControls.hasAdminRole(msg.sender),
"MISOTokenFactory: Sender must be admin"
);
locked = _locked;
}
/**
* @notice Sets the current template ID for any type.
* @param _templateType Type of template.
* @param _templateId The ID of the current template for that type
*/
function setCurrentTemplateId(uint256 _templateType, uint256 _templateId) external {
require(
accessControls.hasAdminRole(msg.sender) ||
accessControls.hasOperatorRole(msg.sender),
"MISOTokenFactory: Sender must be admin"
);
require(tokenTemplates[_templateId] != address(0), "MISOMarket: incorrect _templateId");
require(IMisoToken(tokenTemplates[_templateId]).tokenTemplate() == _templateType, "MISOMarket: incorrect _templateType");
currentTemplateId[_templateType] = _templateId;
}
/**
* @notice Used to check whether an address has the minter role
* @param _address EOA or contract being checked
* @return bool True if the account has the role or false if it does not
*/
function hasTokenMinterRole(address _address) public view returns (bool) {
return accessControls.hasRole(TOKEN_MINTER_ROLE, _address);
}
/**
* @notice Creates a token corresponding to template id and transfers fees.
* @dev Initializes token with parameters passed
* @param _templateId Template id of token to create.
* @param _integratorFeeAccount Address to pay the fee to.
* @return token Token address.
*/
function deployToken(
uint256 _templateId,
address payable _integratorFeeAccount
)
public payable returns (address token)
{
/// @dev If the contract is locked, only admin and minters can deploy.
if (locked) {
require(accessControls.hasAdminRole(msg.sender)
|| accessControls.hasMinterRole(msg.sender)
|| hasTokenMinterRole(msg.sender),
"MISOTokenFactory: Sender must be minter if locked"
);
}
require(msg.value >= minimumFee, "MISOTokenFactory: Failed to transfer minimumFee");
require(tokenTemplates[_templateId] != address(0));
uint256 integratorFee = 0;
uint256 misoFee = msg.value;
if (_integratorFeeAccount != address(0) && _integratorFeeAccount != misoDiv) {
integratorFee = misoFee * integratorFeePct / 1000;
misoFee = misoFee - integratorFee;
}
token = createClone(tokenTemplates[_templateId]);
/// @dev GP: Triple check the token index is correct.
tokenInfo[token] = Token(true, _templateId, tokens.length);
tokens.push(token);
emit TokenCreated(msg.sender, token, tokenTemplates[_templateId]);
if (misoFee > 0) {
misoDiv.transfer(misoFee);
}
if (integratorFee > 0) {
_integratorFeeAccount.transfer(integratorFee);
}
}
/**
* @notice Creates a token corresponding to template id.
* @dev Initializes token with parameters passed.
* @param _templateId Template id of token to create.
* @param _integratorFeeAccount Address to pay the fee to.
* @param _data Data to be passed to the token contract for init.
* @return token Token address.
*/
function createToken(
uint256 _templateId,
address payable _integratorFeeAccount,
bytes calldata _data
)
external payable returns (address token)
{
emit TokenInitialized(address(token), _templateId, _data);
token = deployToken(_templateId, _integratorFeeAccount);
IMisoToken(token).initToken(_data);
uint256 initialTokens = IERC20(token).balanceOf(address(this));
if (initialTokens > 0 ) {
_safeTransfer(token, msg.sender, initialTokens);
}
}
/**
* @notice Function to add a token template to create through factory.
* @dev Should have operator access.
* @param _template Token template to create a token.
*/
function addTokenTemplate(address _template) external {
require(
accessControls.hasAdminRole(msg.sender) ||
accessControls.hasOperatorRole(msg.sender),
"MISOTokenFactory: Sender must be operator"
);
uint256 templateType = IMisoToken(_template).tokenTemplate();
require(templateType > 0, "MISOLauncher: Incorrect template code ");
require(tokenTemplateToId[_template] == 0, "MISOTokenFactory: Template exists");
tokenTemplateId++;
tokenTemplates[tokenTemplateId] = _template;
tokenTemplateToId[_template] = tokenTemplateId;
currentTemplateId[templateType] = tokenTemplateId;
emit TokenTemplateAdded(_template, tokenTemplateId);
}
/**
* @notice Function to remove a token template.
* @dev Should have operator access.
* @param _templateId Refers to template that is to be deleted.
*/
function removeTokenTemplate(uint256 _templateId) external {
require(
accessControls.hasAdminRole(msg.sender) ||
accessControls.hasOperatorRole(msg.sender),
"MISOTokenFactory: Sender must be operator"
);
require(tokenTemplates[_templateId] != address(0));
address template = tokenTemplates[_templateId];
uint256 templateType = IMisoToken(tokenTemplates[_templateId]).tokenTemplate();
if (currentTemplateId[templateType] == _templateId) {
delete currentTemplateId[templateType];
}
tokenTemplates[_templateId] = address(0);
delete tokenTemplateToId[template];
emit TokenTemplateRemoved(template, _templateId);
}
/**
* @notice Get the total number of tokens in the factory.
* @return Token count.
*/
function numberOfTokens() external view returns (uint256) {
return tokens.length;
}
function getTokens() external view returns (address[] memory) {
return tokens;
}
/**
* @notice Get the address based on template ID.
* @param _templateId Token template ID.
* @return Address of the required template ID.
*/
function getTokenTemplate(uint256 _templateId) external view returns (address ) {
return tokenTemplates[_templateId];
}
/**
* @notice Get the ID based on template address.
* @param _tokenTemplate Token template address.
* @return ID of the required template address.
*/
function getTemplateId(address _tokenTemplate) external view returns (uint256) {
return tokenTemplateToId[_tokenTemplate];
}
}