@daohost/host 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +39 -0
  3. package/out/activity.d.ts +16 -0
  4. package/out/activity.d.ts.map +1 -0
  5. package/out/activity.js +25 -0
  6. package/out/activity.js.map +1 -0
  7. package/out/agents.d.ts +15 -0
  8. package/out/agents.d.ts.map +1 -0
  9. package/out/agents.js +14 -0
  10. package/out/agents.js.map +1 -0
  11. package/out/api.d.ts +115 -0
  12. package/out/api.d.ts.map +1 -0
  13. package/out/api.js +3 -0
  14. package/out/api.js.map +1 -0
  15. package/out/assets.d.ts +46 -0
  16. package/out/assets.d.ts.map +1 -0
  17. package/out/assets.js +1645 -0
  18. package/out/assets.js.map +1 -0
  19. package/out/chains.d.ts +106 -0
  20. package/out/chains.d.ts.map +1 -0
  21. package/out/chains.js +605 -0
  22. package/out/chains.js.map +1 -0
  23. package/out/deployments.d.ts +9 -0
  24. package/out/deployments.d.ts.map +1 -0
  25. package/out/deployments.js +18 -0
  26. package/out/deployments.js.map +1 -0
  27. package/out/host/types.d.ts +59 -0
  28. package/out/host/types.d.ts.map +1 -0
  29. package/out/host/types.js +35 -0
  30. package/out/host/types.js.map +1 -0
  31. package/out/host.d.ts +387 -0
  32. package/out/host.d.ts.map +1 -0
  33. package/out/host.js +948 -0
  34. package/out/host.js.map +1 -0
  35. package/out/index.d.ts +15 -0
  36. package/out/index.d.ts.map +1 -0
  37. package/out/index.js +45 -0
  38. package/out/index.js.map +1 -0
  39. package/out/storage/daos.d.ts +3 -0
  40. package/out/storage/daos.d.ts.map +1 -0
  41. package/out/storage/daos.js +374 -0
  42. package/out/storage/daos.js.map +1 -0
  43. package/out/storage/metaData.d.ts +5 -0
  44. package/out/storage/metaData.d.ts.map +1 -0
  45. package/out/storage/metaData.js +44 -0
  46. package/out/storage/metaData.js.map +1 -0
  47. package/out/tokenlist.json +2098 -0
  48. package/out/unit.d.ts +75 -0
  49. package/out/unit.d.ts.map +1 -0
  50. package/out/unit.js +3 -0
  51. package/out/unit.js.map +1 -0
  52. package/out/validation.d.ts +15 -0
  53. package/out/validation.d.ts.map +1 -0
  54. package/out/validation.js +105 -0
  55. package/out/validation.js.map +1 -0
  56. package/package.json +37 -0
package/out/host.js ADDED
@@ -0,0 +1,948 @@
1
+ "use strict";
2
+ /**
3
+ Host prototype.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DAOAction = exports.Host = exports.daoContractIndices = exports.ContractIndices = exports.FundingType = exports.LifecyclePhase = exports.STATIC_BASE_URL = exports.DAO_FEATURES = exports.HOST_DESCRIPTION = void 0;
7
+ exports.getUnit = getUnit;
8
+ exports.getDAOUnit = getDAOUnit;
9
+ exports.getDAOUnitMetaData = getDAOUnitMetaData;
10
+ exports.getUnitMetaData = getUnitMetaData;
11
+ exports.getBridgeTokens = getBridgeTokens;
12
+ const chains_1 = require("./chains");
13
+ const assets_1 = require("./assets");
14
+ const validation_1 = require("./validation");
15
+ exports.HOST_DESCRIPTION = "Where True DAOs Live & Work";
16
+ exports.DAO_FEATURES = [
17
+ "True DAO: only holders owns, manage and earn whole value",
18
+ "Inter-chain setup with bridging",
19
+ "Decentralized fundraising",
20
+ "Self-developing via Builder activity",
21
+ "Tokenomics constructor",
22
+ "Proper token launch flow to get cg/cmc and wallets listings",
23
+ "Deterministic managed contract addresses",
24
+ ];
25
+ exports.STATIC_BASE_URL = "https://raw.githubusercontent.com/stabilitydao/.github/main";
26
+ /**
27
+ Lifecycle phase represents DAO tokenomics stage.
28
+ */
29
+ var LifecyclePhase;
30
+ (function (LifecyclePhase) {
31
+ /** Created */
32
+ LifecyclePhase["DRAFT"] = "DRAFT";
33
+ /**
34
+ * DAO ready to attract initial community
35
+ */
36
+ LifecyclePhase["INCEPTION"] = "INCEPTION";
37
+ /**
38
+ Initial funding. DAO project passed requirements.
39
+ Since SEED started a DAO become real DAO:
40
+ - noncustodial
41
+ - tokenized share holdings
42
+ - collective management via voting
43
+ */
44
+ LifecyclePhase["SEED"] = "SEED";
45
+ /** Seed was not success. Raised funds sent back to seeders. */
46
+ LifecyclePhase["SEED_FAILED"] = "SEED_FAILED";
47
+ /** Using SEED funds to launch MVP / Unit generating */
48
+ LifecyclePhase["DEVELOPMENT"] = "DEVELOPMENT";
49
+ /** TGE is funding event for token liquidity and DAO developments (optionally) */
50
+ LifecyclePhase["TGE"] = "TGE";
51
+ /** Delay before any vesting allocation started */
52
+ LifecyclePhase["LIVE_CLIFF"] = "LIVE_CLIFF";
53
+ /** Vesting period active */
54
+ LifecyclePhase["LIVE_VESTING"] = "LIVE_VESTING";
55
+ /** Vesting ended - token fully distributed */
56
+ LifecyclePhase["LIVE"] = "LIVE";
57
+ })(LifecyclePhase || (exports.LifecyclePhase = LifecyclePhase = {}));
58
+ var FundingType;
59
+ (function (FundingType) {
60
+ FundingType["SEED"] = "SEED";
61
+ FundingType["TGE"] = "TGE";
62
+ })(FundingType || (exports.FundingType = FundingType = {}));
63
+ /// @notice Indices of all contracts that can be deployed by a DAO. The indices are used to pre-set salts
64
+ var ContractIndices;
65
+ (function (ContractIndices) {
66
+ ContractIndices[ContractIndices["NOT_USED_0"] = 0] = "NOT_USED_0";
67
+ ContractIndices[ContractIndices["SEED_TOKEN_1"] = 1] = "SEED_TOKEN_1";
68
+ ContractIndices[ContractIndices["TGE_TOKEN_2"] = 2] = "TGE_TOKEN_2";
69
+ ContractIndices[ContractIndices["TOKEN_3"] = 3] = "TOKEN_3";
70
+ ContractIndices[ContractIndices["X_TOKEN_4"] = 4] = "X_TOKEN_4";
71
+ ContractIndices[ContractIndices["DAO_TOKEN_5"] = 5] = "DAO_TOKEN_5";
72
+ ContractIndices[ContractIndices["STAKING_6"] = 6] = "STAKING_6";
73
+ ContractIndices[ContractIndices["RECOVERY_7"] = 7] = "RECOVERY_7";
74
+ ContractIndices[ContractIndices["TOKEN_BRIDGE_8"] = 8] = "TOKEN_BRIDGE_8";
75
+ ContractIndices[ContractIndices["X_TOKEN_BRIDGE_9"] = 9] = "X_TOKEN_BRIDGE_9";
76
+ ContractIndices[ContractIndices["DAO_TOKEN_BRIDGE_10"] = 10] = "DAO_TOKEN_BRIDGE_10";
77
+ ContractIndices[ContractIndices["VESTING_1_11"] = 11] = "VESTING_1_11";
78
+ ContractIndices[ContractIndices["VESTING_2_12"] = 12] = "VESTING_2_12";
79
+ ContractIndices[ContractIndices["VESTING_3_13"] = 13] = "VESTING_3_13";
80
+ ContractIndices[ContractIndices["VESTING_4_14"] = 14] = "VESTING_4_14";
81
+ ContractIndices[ContractIndices["VESTING_5_15"] = 15] = "VESTING_5_15";
82
+ ContractIndices[ContractIndices["VESTING_6_16"] = 16] = "VESTING_6_16";
83
+ ContractIndices[ContractIndices["VESTING_7_17"] = 17] = "VESTING_7_17";
84
+ ContractIndices[ContractIndices["VESTING_8_18"] = 18] = "VESTING_8_18";
85
+ ContractIndices[ContractIndices["VESTING_9_19"] = 19] = "VESTING_9_19";
86
+ ContractIndices[ContractIndices["VESTING_10_20"] = 20] = "VESTING_10_20";
87
+ ContractIndices[ContractIndices["REVENUE_ROUTER_21"] = 21] = "REVENUE_ROUTER_21";
88
+ // add new indices here if necessary
89
+ ContractIndices[ContractIndices["COUNT_CONTRACT_INDICES"] = 22] = "COUNT_CONTRACT_INDICES";
90
+ })(ContractIndices || (exports.ContractIndices = ContractIndices = {}));
91
+ exports.daoContractIndices = {
92
+ [ContractIndices.SEED_TOKEN_1]: {
93
+ name: "Seed token",
94
+ description: "Seed round receipt token",
95
+ },
96
+ [ContractIndices.TGE_TOKEN_2]: {
97
+ name: "Presale token",
98
+ description: "TGE pre-sale receipt token",
99
+ },
100
+ [ContractIndices.TOKEN_3]: {
101
+ name: "Token",
102
+ description: "Main tradable DAO token",
103
+ },
104
+ [ContractIndices.X_TOKEN_4]: {
105
+ name: "VE-token",
106
+ description: "VE-tokenomics entry token",
107
+ },
108
+ [ContractIndices.DAO_TOKEN_5]: {
109
+ name: "DAO token",
110
+ description: "Governance token",
111
+ },
112
+ [ContractIndices.STAKING_6]: {
113
+ name: "Staking",
114
+ description: "Staking contract",
115
+ },
116
+ [ContractIndices.RECOVERY_7]: {
117
+ name: "Recovery",
118
+ description: "Accident recovery system contract",
119
+ },
120
+ [ContractIndices.TOKEN_BRIDGE_8]: {
121
+ name: "Token bridge",
122
+ description: "Bridge for main token",
123
+ },
124
+ [ContractIndices.X_TOKEN_BRIDGE_9]: {
125
+ name: "VE-token bridge",
126
+ description: "Bridge for VE-token",
127
+ },
128
+ [ContractIndices.DAO_TOKEN_BRIDGE_10]: {
129
+ name: "DAO token bridge",
130
+ description: "Bridge for Governance token",
131
+ },
132
+ [ContractIndices.VESTING_1_11]: {
133
+ name: "Vesting 1",
134
+ },
135
+ [ContractIndices.VESTING_2_12]: {
136
+ name: "Vesting 2",
137
+ },
138
+ [ContractIndices.VESTING_3_13]: {
139
+ name: "Vesting 3",
140
+ },
141
+ [ContractIndices.VESTING_4_14]: {
142
+ name: "Vesting 4",
143
+ },
144
+ [ContractIndices.VESTING_5_15]: {
145
+ name: "Vesting 5",
146
+ },
147
+ [ContractIndices.VESTING_6_16]: {
148
+ name: "Vesting 6",
149
+ },
150
+ [ContractIndices.VESTING_7_17]: {
151
+ name: "Vesting 7",
152
+ },
153
+ [ContractIndices.VESTING_8_18]: {
154
+ name: "Vesting 8",
155
+ },
156
+ [ContractIndices.VESTING_9_19]: {
157
+ name: "Vesting 9",
158
+ },
159
+ [ContractIndices.VESTING_10_20]: {
160
+ name: "Vesting 10",
161
+ },
162
+ [ContractIndices.REVENUE_ROUTER_21]: {
163
+ name: "Revenue Router",
164
+ description: "Revenue collector and utilizer contract",
165
+ },
166
+ };
167
+ /**
168
+ Typescript implementation of the Host
169
+ Object of this class is Host instance deployed on a single blockchain.
170
+
171
+ @class
172
+ */
173
+ class Host {
174
+ constructor(chainId) {
175
+ /** Chain block timestamp */
176
+ this.blockTimestamp = Math.floor(new Date().getTime() / 1000);
177
+ /** Local DAOs storage (in form of a mapping) */
178
+ this.daos = {};
179
+ /** Actual DAO symbols at all blockchains */
180
+ this.usedSymbols = {};
181
+ /** All emitted events */
182
+ this.events = [];
183
+ /** Governance proposals. Can be created only at initialChain of DAO. */
184
+ this.proposals = {};
185
+ /** Current user address */
186
+ this.from = "0x00";
187
+ this.settings = {
188
+ priceDao: 1000,
189
+ fundingFee: 1000, // 10%
190
+ minNameLength: 1,
191
+ maxNameLength: 20,
192
+ minSymbolLength: 1,
193
+ maxSymbolLength: 7,
194
+ minVePeriod: 14,
195
+ maxVePeriod: 365 * 4,
196
+ minPvPFee: 10,
197
+ maxPvPFee: 100,
198
+ minFundingDuration: 1,
199
+ maxFundingDuration: 180,
200
+ minFundingRaise: 1000,
201
+ maxFundingRaise: 1e12,
202
+ minVestingNameLen: 1,
203
+ maxVestingNameLen: 20,
204
+ minCliff: 15,
205
+ minVestingDuration: 10,
206
+ maxVestingDuration: 365,
207
+ };
208
+ this.chainId = chainId;
209
+ }
210
+ static getTokensNaming(name, symbol) {
211
+ return {
212
+ seedName: `${name} SEED`,
213
+ seedSymbol: `seed${symbol}`,
214
+ tgeName: `${name} PRESALE`,
215
+ tgeSymbol: `sale${symbol}`,
216
+ tokenName: name,
217
+ tokenSymbol: symbol,
218
+ xName: `x${name}`,
219
+ xSymbol: `x${symbol}`,
220
+ daoName: `${name} DAO`,
221
+ daoSymbol: `${symbol}_DAO`,
222
+ };
223
+ }
224
+ static isLiveDAO(phase) {
225
+ return [
226
+ LifecyclePhase.LIVE_CLIFF,
227
+ LifecyclePhase.LIVE_VESTING,
228
+ LifecyclePhase.LIVE,
229
+ ].includes(phase);
230
+ }
231
+ /**
232
+ * Create new DAO
233
+ * @throws Error
234
+ */
235
+ createDAO(name, symbol, activity, params, funding, metaDataLocation) {
236
+ const dao = {
237
+ phase: LifecyclePhase.DRAFT,
238
+ name,
239
+ symbol,
240
+ activity,
241
+ socials: [],
242
+ images: {},
243
+ deployments: {},
244
+ units: [],
245
+ params,
246
+ chainSettings: {
247
+ [this.chainId]: {
248
+ bbRate: 50,
249
+ },
250
+ },
251
+ initialChain: chains_1.chains[this.chainId].name,
252
+ funding,
253
+ vesting: [],
254
+ governanceSettings: {},
255
+ deployer: this.from,
256
+ salts: {},
257
+ metaDataLocation: metaDataLocation,
258
+ unitEmitData: [],
259
+ };
260
+ this.validate(dao);
261
+ this.daos[dao.symbol] = dao;
262
+ this.usedSymbols[dao.symbol] = true;
263
+ this._emit("DAO created");
264
+ this._sendCrossChainMessage(CROSS_CHAIN_MESSAGE.NEW_DAO_SYMBOL, {
265
+ symbol,
266
+ });
267
+ return dao;
268
+ }
269
+ /** Add live compatible DAO */
270
+ addLiveDAO(dao) {
271
+ // todo _onlyVerifier
272
+ this.validate(dao);
273
+ this.daos[dao.symbol] = dao;
274
+ this.usedSymbols[dao.symbol] = true;
275
+ this._emit("DAO created");
276
+ this._sendCrossChainMessage(CROSS_CHAIN_MESSAGE.NEW_DAO_SYMBOL, {
277
+ symbol: dao.symbol,
278
+ });
279
+ }
280
+ getDAOMetaData(daoMetaData, symbol) {
281
+ const dao = this.getDAO(symbol);
282
+ if (dao.metaDataLocation === "local") {
283
+ return daoMetaData[symbol.toLowerCase()];
284
+ }
285
+ return {};
286
+ }
287
+ /** Change lifecycle phase of a DAO */
288
+ changePhase(symbol) {
289
+ // anybody can call this
290
+ const dao = this.getDAO(symbol);
291
+ const currentTasks = this.tasks(symbol);
292
+ if (currentTasks.length > 0) {
293
+ throw new Error("SolveTasksFirst");
294
+ }
295
+ if (dao.phase === LifecyclePhase.DRAFT) {
296
+ const seed = dao.funding[this.getFundingIndex(symbol, FundingType.SEED)];
297
+ // SEED can be started not later than 1 week after must start
298
+ // todo settings.maxSeedStartDelay
299
+ if (seed.start < this.blockTimestamp &&
300
+ this.blockTimestamp - seed.start > 7 * 86400) {
301
+ throw new Error("TooLateSoSetupFundingAgain");
302
+ }
303
+ /*// SEED can be started not later than 1 week before end
304
+ if (seed.end - this.blockTimestamp < 7 * 86400) {
305
+ throw new Error("TooLateSoSetupFundingAgain")
306
+ }*/
307
+ this.daos[symbol].phase = LifecyclePhase.INCEPTION;
308
+ }
309
+ else if (dao.phase === LifecyclePhase.INCEPTION) {
310
+ const seed = dao.funding[this.getFundingIndex(symbol, FundingType.SEED)];
311
+ if (seed.start > this.blockTimestamp) {
312
+ throw new Error("WaitFundingStart");
313
+ }
314
+ // deploy seedToken
315
+ this.daos[symbol].deployments[this.chainId] = {
316
+ [ContractIndices.SEED_TOKEN_1]: "0xProxyDeployed",
317
+ };
318
+ this.daos[symbol].phase = LifecyclePhase.SEED;
319
+ }
320
+ else if (dao.phase === LifecyclePhase.SEED) {
321
+ const seed = dao.funding[this.getFundingIndex(symbol, FundingType.SEED)];
322
+ if (seed.end > this.blockTimestamp) {
323
+ throw new Error("WaitFundingEnd");
324
+ }
325
+ const success = seed.raised >= seed.minRaise;
326
+ if (success) {
327
+ this.daos[symbol].phase = LifecyclePhase.DEVELOPMENT;
328
+ }
329
+ else {
330
+ // send all raised back to seeders
331
+ this.daos[symbol].phase = LifecyclePhase.SEED_FAILED;
332
+ }
333
+ }
334
+ else if (dao.phase === LifecyclePhase.DEVELOPMENT) {
335
+ const tge = dao.funding[this.getFundingIndex(symbol, FundingType.TGE)];
336
+ if (tge.start > this.blockTimestamp) {
337
+ throw new Error("WaitFundingStart");
338
+ }
339
+ // deploy tgeToken
340
+ this.daos[symbol].deployments[this.chainId][ContractIndices.TGE_TOKEN_2] =
341
+ "0xProxyDeployedTge";
342
+ this.daos[symbol].phase = LifecyclePhase.TGE;
343
+ }
344
+ else if (dao.phase === LifecyclePhase.TGE) {
345
+ const tge = dao.funding[this.getFundingIndex(symbol, FundingType.TGE)];
346
+ if (tge.end > this.blockTimestamp) {
347
+ throw new Error("WaitFundingEnd");
348
+ }
349
+ const success = tge.raised >= tge.minRaise;
350
+ if (success) {
351
+ // deploy token, xToken, staking, daoToken
352
+ this.daos[symbol].deployments[this.chainId][ContractIndices.TOKEN_3] =
353
+ "0xProxyToken";
354
+ this.daos[symbol].deployments[this.chainId][ContractIndices.X_TOKEN_4] =
355
+ "0xProxyXToken";
356
+ this.daos[symbol].deployments[this.chainId][ContractIndices.STAKING_6] =
357
+ "0xProxyStaking";
358
+ this.daos[symbol].deployments[this.chainId][ContractIndices.DAO_TOKEN_5] = "0xProxyDAOToken";
359
+ // todo deploy vesting contracts and allocate token
360
+ // todo seedToken holders became xToken holders by predefined rate
361
+ // todo deploy v2 liquidity from TGE funds at predefined price
362
+ this.daos[symbol].phase = LifecyclePhase.LIVE_CLIFF;
363
+ }
364
+ else {
365
+ // send all raised TGE funds back to funders
366
+ this.daos[symbol].phase = LifecyclePhase.DEVELOPMENT;
367
+ }
368
+ }
369
+ else if (dao.phase === LifecyclePhase.LIVE_CLIFF) {
370
+ // if any vesting started then phase changed
371
+ const isVestingStarted = !!dao.vesting?.filter((v) => v.start < this.blockTimestamp).length;
372
+ if (!isVestingStarted) {
373
+ throw new Error("WaitVestingStart");
374
+ }
375
+ this.daos[symbol].phase = LifecyclePhase.LIVE_VESTING;
376
+ }
377
+ else if (dao.phase === LifecyclePhase.LIVE_VESTING) {
378
+ // if any vesting started then phase changed
379
+ const isVestingEnded = !dao.vesting?.filter((v) => v.end > this.blockTimestamp).length;
380
+ if (!isVestingEnded) {
381
+ throw new Error("WaitVestingEnd");
382
+ }
383
+ this.daos[symbol].phase = LifecyclePhase.LIVE;
384
+ }
385
+ else {
386
+ // nothing to change
387
+ throw new Error("ForeverLive");
388
+ }
389
+ }
390
+ /** @throws Error */
391
+ updateImages(symbol, images) {
392
+ // check DAO symbol
393
+ const dao = this.getDAO(symbol);
394
+ // instant execute for DRAFT
395
+ if (dao.phase === LifecyclePhase.DRAFT) {
396
+ this._onlyOwnerOf(symbol);
397
+ this._updateImages(symbol, images);
398
+ return true;
399
+ }
400
+ // create proposal for other phases
401
+ return this._proposeAction(symbol, DAOAction.UPDATE_IMAGES, {
402
+ images,
403
+ });
404
+ }
405
+ /** @throws Error */
406
+ updateSocials(symbol, socials) {
407
+ // check DAO symbol
408
+ const dao = this.getDAO(symbol);
409
+ // instant execute for DRAFT
410
+ if (dao.phase === LifecyclePhase.DRAFT) {
411
+ this._onlyOwnerOf(symbol);
412
+ this._updateSocials(symbol, socials);
413
+ return true;
414
+ }
415
+ // create proposal for other phases
416
+ return this._proposeAction(symbol, DAOAction.UPDATE_SOCIALS, {
417
+ socials,
418
+ });
419
+ }
420
+ /** @throws Error */
421
+ updateUnits(symbol, units, unitsMetaData) {
422
+ // check DAO symbol
423
+ const dao = this.getDAO(symbol);
424
+ // instant execute for DRAFT
425
+ if (dao.phase === LifecyclePhase.DRAFT) {
426
+ this._onlyOwnerOf(symbol);
427
+ this._updateUnits(symbol, units, unitsMetaData);
428
+ return true;
429
+ }
430
+ // create proposal for other phases
431
+ return this._proposeAction(symbol, DAOAction.UPDATE_UNITS, {
432
+ units,
433
+ unitsMetaData,
434
+ });
435
+ }
436
+ /** @throws Error */
437
+ updateFunding(symbol, funding) {
438
+ // check DAO symbol
439
+ const dao = this.getDAO(symbol);
440
+ // validate payload
441
+ this.validateFunding(dao.phase, [funding]);
442
+ // instant execute for DRAFT
443
+ if (dao.phase === LifecyclePhase.DRAFT) {
444
+ this._onlyOwnerOf(symbol);
445
+ this._updateFunding(symbol, funding);
446
+ return true;
447
+ }
448
+ // create proposal for other phases
449
+ return this._proposeAction(symbol, DAOAction.UPDATE_FUNDING, {
450
+ funding,
451
+ });
452
+ }
453
+ _updateSocials(symbol, socials) {
454
+ this.daos[symbol].socials = socials;
455
+ this._emit(`Action ${DAOAction.UPDATE_SOCIALS}`);
456
+ }
457
+ _updateUnits(symbol, units, unitsMetaData) {
458
+ this.daos[symbol].units = units;
459
+ this.daos[symbol].unitEmitData = unitsMetaData;
460
+ this._emit(`Action ${DAOAction.UPDATE_UNITS}`);
461
+ }
462
+ _updateFunding(symbol, funding) {
463
+ const dao = this.getDAO(symbol);
464
+ const fundingExist = dao.funding.filter((f) => f.type === funding.type).length === 1;
465
+ if (fundingExist) {
466
+ const fundingIndex = this.getFundingIndex(symbol, funding.type);
467
+ this.daos[symbol].funding[fundingIndex] = funding;
468
+ }
469
+ else {
470
+ this.daos[symbol].funding.push(funding);
471
+ }
472
+ this._emit(`Action ${DAOAction.UPDATE_FUNDING}`);
473
+ }
474
+ updateVesting(symbol, vestings) {
475
+ // check DAO symbol
476
+ const dao = this.getDAO(symbol);
477
+ // validate
478
+ this.validateVesting(dao.phase, vestings, this.getTgeData(dao));
479
+ // instant execute for DRAFT
480
+ if (dao.phase === LifecyclePhase.DRAFT) {
481
+ this._onlyOwnerOf(symbol);
482
+ this._updateVesting(symbol, vestings);
483
+ return true;
484
+ }
485
+ // create proposal for other phases
486
+ return this._proposeAction(symbol, DAOAction.UPDATE_VESTING, {
487
+ vestings,
488
+ });
489
+ }
490
+ revenue(symbol, unitIndex, asset, amount) {
491
+ // todo implement Host.whitelistedAssets
492
+ // receiving money, calculating usd (can appear later by Host Agent)
493
+ if (this.daos[symbol]) {
494
+ if (!this.daos[symbol].unitRevenue) {
495
+ this.daos[symbol].unitRevenue = [];
496
+ }
497
+ if (!this.daos[symbol].unitRevenue[unitIndex]) {
498
+ this.daos[symbol].unitRevenue[unitIndex] = {};
499
+ }
500
+ if (!this.daos[symbol].unitRevenue[unitIndex][asset]) {
501
+ this.daos[symbol].unitRevenue[unitIndex][asset] = 0n;
502
+ }
503
+ this.daos[symbol].unitRevenue[unitIndex][asset] += amount;
504
+ }
505
+ }
506
+ fund(symbol, amount) {
507
+ // todo settings.minFunding
508
+ const dao = this.getDAO(symbol);
509
+ if (dao.phase === LifecyclePhase.SEED) {
510
+ const seedIndex = this.getFundingIndex(symbol, FundingType.SEED);
511
+ const seed = dao.funding[seedIndex];
512
+ if (seed.raised + amount >= seed.maxRaise) {
513
+ throw new Error("RaiseMaxExceed");
514
+ }
515
+ // transfer amount of exchangeAsset to seedToken contract
516
+ this.daos[symbol].funding[seedIndex].raised += amount;
517
+ // mint seedToken to user
518
+ return;
519
+ }
520
+ if (dao.phase === LifecyclePhase.TGE) {
521
+ const tgeIndex = this.getFundingIndex(symbol, FundingType.TGE);
522
+ const tge = dao.funding[tgeIndex];
523
+ if (tge.raised + amount >= tge.maxRaise) {
524
+ throw new Error("RaiseMaxExceed");
525
+ }
526
+ // transfer amount of exchangeAsset to tgeToken contract
527
+ this.daos[symbol].funding[tgeIndex].raised += amount;
528
+ // mint tgeToken to user
529
+ return;
530
+ }
531
+ throw new Error("NotFundingPhase");
532
+ }
533
+ receiveVotingResults(proposalId, succeed) {
534
+ const proposal = this.proposals[proposalId];
535
+ if (!proposal) {
536
+ throw new Error("IncorrectProposal");
537
+ }
538
+ if (proposal.status !== VotingStatus.VOTING) {
539
+ throw new Error("AlreadyReceived");
540
+ }
541
+ this.proposals[proposalId].status = succeed
542
+ ? VotingStatus.APPROVED
543
+ : VotingStatus.REJECTED;
544
+ if (succeed) {
545
+ if (proposal.action === DAOAction.UPDATE_IMAGES) {
546
+ this._updateImages(proposal.symbol, proposal.payload.images);
547
+ }
548
+ if (proposal.action === DAOAction.UPDATE_SOCIALS) {
549
+ this._updateSocials(proposal.symbol, proposal.payload.socials);
550
+ }
551
+ if (proposal.action === DAOAction.UPDATE_UNITS) {
552
+ this._updateUnits(proposal.symbol, proposal.payload.units, proposal.payload.unitsMetaData);
553
+ }
554
+ if (proposal.action === DAOAction.UPDATE_FUNDING) {
555
+ this._updateFunding(proposal.symbol, proposal.payload.funding);
556
+ }
557
+ if (proposal.action === DAOAction.UPDATE_VESTING) {
558
+ this._updateVesting(proposal.symbol, proposal.payload.vestings);
559
+ }
560
+ // todo other actions
561
+ }
562
+ }
563
+ /** OFF-CHAIN only **/
564
+ /** @throws Error */
565
+ roadmap(symbol) {
566
+ const dao = this.getDAO(symbol);
567
+ const r = [];
568
+ let tgeRun = 0;
569
+ for (const funding of dao.funding) {
570
+ if (funding.type === FundingType.SEED) {
571
+ r.push({
572
+ phase: LifecyclePhase.INCEPTION,
573
+ });
574
+ r.push({
575
+ phase: LifecyclePhase.SEED,
576
+ start: funding.start,
577
+ end: funding.end,
578
+ });
579
+ }
580
+ if (funding.type === FundingType.TGE) {
581
+ // if SEED was done
582
+ if (r.length > 0) {
583
+ r.push({
584
+ phase: LifecyclePhase.DEVELOPMENT,
585
+ start: r[0].end + 1,
586
+ end: funding.start - 1,
587
+ });
588
+ }
589
+ tgeRun = funding.claim || funding.end;
590
+ r.push({
591
+ phase: LifecyclePhase.TGE,
592
+ start: funding.start,
593
+ end: tgeRun,
594
+ });
595
+ }
596
+ }
597
+ if (dao.vesting.length > 0) {
598
+ let vestingStart = this.blockTimestamp;
599
+ let vestingEnd = this.blockTimestamp;
600
+ for (const vesting of dao.vesting) {
601
+ if (vesting.start < vestingStart) {
602
+ vestingStart = vesting.start;
603
+ }
604
+ if (vesting.end > vestingEnd) {
605
+ vestingEnd = vesting.end;
606
+ }
607
+ }
608
+ r.push({
609
+ phase: LifecyclePhase.LIVE_CLIFF,
610
+ start: tgeRun + 1,
611
+ end: vestingStart - 1,
612
+ });
613
+ r.push({
614
+ phase: LifecyclePhase.LIVE_VESTING,
615
+ start: vestingStart,
616
+ end: vestingEnd,
617
+ });
618
+ r.push({
619
+ phase: LifecyclePhase.LIVE,
620
+ start: vestingEnd + 1,
621
+ });
622
+ }
623
+ return r;
624
+ }
625
+ /** @throws Error */
626
+ tasks(symbol) {
627
+ const dao = this.getDAO(symbol);
628
+ const r = [];
629
+ if (dao.phase === LifecyclePhase.DRAFT) {
630
+ // images
631
+ if (!dao.images.seedToken || !dao.images.token) {
632
+ r.push({
633
+ name: "Need images of token and seedToken",
634
+ });
635
+ }
636
+ // socials
637
+ if (dao.socials.length < 2) {
638
+ r.push({
639
+ name: "Need at least 2 socials",
640
+ });
641
+ }
642
+ // units projected
643
+ if (dao.units.length === 0) {
644
+ r.push({
645
+ name: "Need at least 1 projected unit",
646
+ });
647
+ }
648
+ }
649
+ else if (dao.phase === LifecyclePhase.INCEPTION) {
650
+ // only off-chain tasks, mean SEED will be started anyway
651
+ // todo off-chain tasks like minimal socials users number, units emitted data, etc
652
+ }
653
+ else if (dao.phase === LifecyclePhase.SEED) {
654
+ const seedIndex = this.getFundingIndex(symbol, FundingType.SEED);
655
+ if (dao.funding[seedIndex].raised < dao.funding[seedIndex].minRaise &&
656
+ dao.funding[seedIndex].end > this.blockTimestamp) {
657
+ r.push({
658
+ name: "Need attract minimal seed funding",
659
+ });
660
+ }
661
+ }
662
+ else if (dao.phase === LifecyclePhase.DEVELOPMENT) {
663
+ // check funding
664
+ const tgeExist = dao.funding.filter((f) => f.type === FundingType.TGE).length === 1;
665
+ if (!tgeExist) {
666
+ r.push({
667
+ name: "Need add pre-TGE funding",
668
+ });
669
+ }
670
+ // images
671
+ if (!dao.images.tgeToken || !dao.images.xToken || !dao.images.daoToken) {
672
+ r.push({
673
+ name: "Need images of all DAO tokens",
674
+ });
675
+ }
676
+ // setup vesting allocations
677
+ if (!dao.vesting?.length) {
678
+ r.push({
679
+ name: "Need vesting allocations",
680
+ });
681
+ }
682
+ if (!this.hasRevenue(dao.symbol)) {
683
+ r.push({
684
+ name: "Start generate revenue",
685
+ });
686
+ }
687
+ }
688
+ else if (dao.phase === LifecyclePhase.TGE) {
689
+ const tgeIndex = this.getFundingIndex(symbol, FundingType.TGE);
690
+ if (dao.funding[tgeIndex].raised < dao.funding[tgeIndex].minRaise &&
691
+ dao.funding[tgeIndex].end > this.blockTimestamp) {
692
+ r.push({
693
+ name: "Need attract minimal TGE funding",
694
+ });
695
+ }
696
+ }
697
+ else if (dao.phase === LifecyclePhase.LIVE_CLIFF) {
698
+ // establish and improve
699
+ // build money markets
700
+ // bridge to chains
701
+ }
702
+ else if (dao.phase === LifecyclePhase.LIVE_VESTING) {
703
+ // distribute vesting funds to leverage token
704
+ }
705
+ /*if (dao.phase === LifecyclePhase.LIVE)*/
706
+ // lifetime revenue generating for DAO holders (till ABSORBED proposed feature)
707
+ return r;
708
+ }
709
+ /** Strict on-chain validation */
710
+ /** @throws Error */
711
+ validate(dao) {
712
+ this.validateName(dao.name);
713
+ this.validateSymbol(dao.symbol);
714
+ if (dao.params.vePeriod < this.settings.minVePeriod ||
715
+ dao.params.vePeriod > this.settings.maxVePeriod) {
716
+ throw new Error(`VePeriod(${dao.params.vePeriod})`);
717
+ }
718
+ this.validatePvpFee(dao.params.pvpFee);
719
+ if (!dao.funding.length) {
720
+ throw new Error("NeedFunding");
721
+ }
722
+ // check activity are correct
723
+ this.validateActivity(dao.activity);
724
+ // todo: check funding array has unique funding types
725
+ // todo: check funding dates
726
+ // todo: check funding raise goals
727
+ }
728
+ /** @throws Error */
729
+ getDAO(symbol) {
730
+ if (this.daos[symbol]) {
731
+ return this.daos[symbol];
732
+ }
733
+ throw new Error("DAONotFound");
734
+ }
735
+ getDaoOwner(symbol) {
736
+ const dao = this.getDAO(symbol);
737
+ if (dao.phase === LifecyclePhase.DRAFT) {
738
+ return dao.deployer;
739
+ }
740
+ if ([
741
+ LifecyclePhase.SEED,
742
+ LifecyclePhase.DEVELOPMENT,
743
+ LifecyclePhase.TGE,
744
+ ].includes(dao.phase)) {
745
+ return dao.deployments[(0, chains_1.getChainByName)(dao.initialChain).chainId][ContractIndices.SEED_TOKEN_1];
746
+ }
747
+ return dao.deployments[this.chainId][ContractIndices.DAO_TOKEN_5];
748
+ }
749
+ hasRevenue(symbol) {
750
+ const dao = this.getDAO(symbol);
751
+ if (dao.unitRevenue) {
752
+ for (const unitRevenue of dao.unitRevenue) {
753
+ for (const asset of Object.keys(unitRevenue)) {
754
+ if (unitRevenue[asset] > 0n) {
755
+ return true;
756
+ }
757
+ }
758
+ }
759
+ }
760
+ return false;
761
+ }
762
+ getTgeData(dao) {
763
+ const fundingExist = dao.funding.filter((f) => f.type === FundingType.TGE).length === 1;
764
+ if (fundingExist) {
765
+ const fundingIndex = this.getFundingIndex(dao.symbol, FundingType.TGE);
766
+ return dao.funding[fundingIndex];
767
+ }
768
+ }
769
+ getFundingIndex(symbol, type) {
770
+ const dao = this.getDAO(symbol);
771
+ for (let i = 0; i < dao.funding.length; i++) {
772
+ if (type === dao.funding[i].type) {
773
+ return i;
774
+ }
775
+ }
776
+ throw new Error("FundingNotFound");
777
+ }
778
+ warpDays(days = 7) {
779
+ this.blockTimestamp += days * 86400;
780
+ }
781
+ /** @throws Error */
782
+ _onlyOwnerOf(symbol) {
783
+ if (this.from != this.getDaoOwner(symbol)) {
784
+ throw new Error(`YouAreNotOwnerOf(${symbol})`);
785
+ }
786
+ }
787
+ _emit(event) {
788
+ this.events.push(event);
789
+ }
790
+ validateName(name) {
791
+ if (name.length < this.settings.minNameLength ||
792
+ name.length > this.settings.maxNameLength) {
793
+ throw new Error(`NameLength(${name.length})`);
794
+ }
795
+ }
796
+ validateSymbol(symbol) {
797
+ if (symbol.length < this.settings.minSymbolLength ||
798
+ symbol.length > this.settings.maxSymbolLength) {
799
+ throw new Error(`SymbolLength(${symbol.length})`);
800
+ }
801
+ if (this.usedSymbols[symbol]) {
802
+ throw new Error(`SymbolNotUnique(${symbol})`);
803
+ }
804
+ }
805
+ validatePvpFee(pvpFee) {
806
+ if (pvpFee < this.settings.minPvPFee || pvpFee > this.settings.maxPvPFee) {
807
+ throw new Error(`PvPFee(${pvpFee})`);
808
+ }
809
+ }
810
+ validateFunding(daoPhase, fundings) {
811
+ validation_1.Validation.validateFunding(daoPhase, fundings, this.settings);
812
+ }
813
+ validateActivity(activity) {
814
+ validation_1.Validation.validateActivity(activity);
815
+ }
816
+ validateVesting(daoPhase, vestings, tge) {
817
+ validation_1.Validation.validateVesting(daoPhase, vestings, this.settings, tge);
818
+ }
819
+ _sendCrossChainMessage(type, payload) {
820
+ // todo some stub
821
+ }
822
+ _proposeAction(symbol, action, payload) {
823
+ const dao = this.getDAO(symbol);
824
+ // todo check for initial chain
825
+ // todo get user power
826
+ // todo check proposalThreshold
827
+ // todo validate payload
828
+ const proposalId = Math.round(Math.random() * Math.random()).toString();
829
+ this.proposals[proposalId] = {
830
+ id: proposalId,
831
+ created: this.blockTimestamp,
832
+ action,
833
+ symbol,
834
+ payload,
835
+ status: VotingStatus.VOTING,
836
+ };
837
+ return proposalId;
838
+ }
839
+ _updateImages(symbol, images) {
840
+ this.daos[symbol].images = images;
841
+ this._emit(`Action ${DAOAction.UPDATE_IMAGES}`);
842
+ }
843
+ _updateVesting(symbol, vestings) {
844
+ this.daos[symbol].vesting = vestings;
845
+ this._emit(`Action ${DAOAction.UPDATE_VESTING}`);
846
+ }
847
+ }
848
+ exports.Host = Host;
849
+ var DAOAction;
850
+ (function (DAOAction) {
851
+ DAOAction[DAOAction["UPDATE_IMAGES"] = 0] = "UPDATE_IMAGES";
852
+ DAOAction[DAOAction["UPDATE_SOCIALS"] = 1] = "UPDATE_SOCIALS";
853
+ DAOAction[DAOAction["UPDATE_NAMING"] = 2] = "UPDATE_NAMING";
854
+ DAOAction[DAOAction["UPDATE_UNITS"] = 3] = "UPDATE_UNITS";
855
+ DAOAction[DAOAction["UPDATE_FUNDING"] = 4] = "UPDATE_FUNDING";
856
+ DAOAction[DAOAction["UPDATE_VESTING"] = 5] = "UPDATE_VESTING";
857
+ })(DAOAction || (exports.DAOAction = DAOAction = {}));
858
+ var VotingStatus;
859
+ (function (VotingStatus) {
860
+ VotingStatus[VotingStatus["VOTING"] = 0] = "VOTING";
861
+ VotingStatus[VotingStatus["APPROVED"] = 1] = "APPROVED";
862
+ VotingStatus[VotingStatus["REJECTED"] = 2] = "REJECTED";
863
+ })(VotingStatus || (VotingStatus = {}));
864
+ var CROSS_CHAIN_MESSAGE;
865
+ (function (CROSS_CHAIN_MESSAGE) {
866
+ CROSS_CHAIN_MESSAGE[CROSS_CHAIN_MESSAGE["NEW_DAO_SYMBOL"] = 0] = "NEW_DAO_SYMBOL";
867
+ CROSS_CHAIN_MESSAGE[CROSS_CHAIN_MESSAGE["DAO_RENAME_SYMBOL"] = 1] = "DAO_RENAME_SYMBOL";
868
+ CROSS_CHAIN_MESSAGE[CROSS_CHAIN_MESSAGE["DAO_BRIDGED"] = 2] = "DAO_BRIDGED";
869
+ })(CROSS_CHAIN_MESSAGE || (CROSS_CHAIN_MESSAGE = {}));
870
+ function getUnit(daos, unitId) {
871
+ for (const dao of daos) {
872
+ for (const unit of dao.units) {
873
+ if (unit.unitId === unitId) {
874
+ return unit;
875
+ }
876
+ }
877
+ }
878
+ }
879
+ function getDAOUnit(daos, symbol, unitId) {
880
+ for (const dao of daos) {
881
+ if (dao.symbol.toLowerCase() === symbol.toLowerCase()) {
882
+ for (const unit of dao.units) {
883
+ if (unit.unitId === unitId) {
884
+ return unit;
885
+ }
886
+ }
887
+ }
888
+ }
889
+ }
890
+ function getDAOUnitMetaData(daos, symbol, unitId) {
891
+ for (const dao of daos) {
892
+ if (dao.symbol.toLowerCase() === symbol.toLowerCase()) {
893
+ for (let i = 0; i < dao.units.length; i++) {
894
+ const unit = dao.units[i];
895
+ if (unit.unitId === unitId) {
896
+ return dao.unitEmitData[i];
897
+ }
898
+ }
899
+ }
900
+ }
901
+ }
902
+ function getUnitMetaData(daos, unitId) {
903
+ for (const dao of daos) {
904
+ for (let i = 0; i < dao.units.length; i++) {
905
+ const unit = dao.units[i];
906
+ if (unit.unitId === unitId) {
907
+ return dao.unitEmitData[i];
908
+ }
909
+ }
910
+ }
911
+ }
912
+ function getBridgeTokens(daos) {
913
+ const r = {};
914
+ for (const dao of daos) {
915
+ const deploymentChainIds = Object.keys(dao.deployments);
916
+ if (deploymentChainIds.length > 1) {
917
+ for (const chainId of deploymentChainIds) {
918
+ const tokenAddress = dao.deployments[chainId][ContractIndices.TOKEN_3];
919
+ const tokenBridge = dao.deployments[chainId][ContractIndices.TOKEN_BRIDGE_8];
920
+ const xTokenAddress = dao.deployments[chainId][ContractIndices.X_TOKEN_4];
921
+ const xTokenBridge = dao.deployments[chainId][ContractIndices.X_TOKEN_BRIDGE_9];
922
+ if (tokenAddress && tokenBridge) {
923
+ const tokenData = (0, assets_1.getTokenData)(chainId, tokenAddress);
924
+ if (tokenData) {
925
+ if (!r[chainId]) {
926
+ r[chainId] = [];
927
+ }
928
+ r[chainId].push({
929
+ tokenData,
930
+ bridge: tokenBridge,
931
+ });
932
+ }
933
+ }
934
+ if (xTokenAddress && xTokenBridge) {
935
+ const tokenData = (0, assets_1.getTokenData)(chainId, xTokenAddress);
936
+ if (tokenData) {
937
+ r[chainId].push({
938
+ tokenData,
939
+ bridge: xTokenBridge,
940
+ });
941
+ }
942
+ }
943
+ }
944
+ }
945
+ }
946
+ return r;
947
+ }
948
+ //# sourceMappingURL=host.js.map