@stabilitydao/host 0.2.1 → 0.2.2
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.
- package/out/activity/builder.d.ts +135 -0
- package/out/activity/builder.d.ts.map +1 -0
- package/out/activity/builder.js +17 -0
- package/out/activity/builder.js.map +1 -0
- package/out/activity/index.d.ts +18 -0
- package/out/activity/index.d.ts.map +1 -0
- package/out/activity/index.js +31 -0
- package/out/activity/index.js.map +1 -0
- package/out/agents.d.ts +21 -0
- package/out/agents.d.ts.map +1 -0
- package/out/agents.js +16 -0
- package/out/agents.js.map +1 -0
- package/out/api.d.ts +47 -0
- package/out/api.d.ts.map +1 -0
- package/out/api.js +3 -0
- package/out/api.js.map +1 -0
- package/out/assets.d.ts +13 -0
- package/out/assets.d.ts.map +1 -0
- package/out/assets.js +1515 -0
- package/out/assets.js.map +1 -0
- package/out/chains.d.ts +105 -0
- package/out/chains.d.ts.map +1 -0
- package/out/chains.js +591 -0
- package/out/chains.js.map +1 -0
- package/out/host.d.ts +407 -0
- package/out/host.d.ts.map +1 -0
- package/out/host.js +765 -0
- package/out/host.js.map +1 -0
- package/out/index.d.ts +10 -0
- package/out/index.d.ts.map +1 -0
- package/out/index.js.map +1 -0
- package/out/storage/daoMetaData.d.ts +5 -0
- package/out/storage/daoMetaData.d.ts.map +1 -0
- package/out/storage/daoMetaData.js +311 -0
- package/out/storage/daoMetaData.js.map +1 -0
- package/out/storage/daos.d.ts +3 -0
- package/out/storage/daos.d.ts.map +1 -0
- package/out/storage/daos.js +303 -0
- package/out/storage/daos.js.map +1 -0
- package/package.json +7 -1
- package/.github/workflows/npm.yml +0 -19
- package/.github/workflows/prettier.yml +0 -25
- package/.github/workflows/test.yml +0 -29
- package/.prettierignore +0 -4
- package/.prettierrc +0 -1
- package/jest.config.js +0 -9
- package/logo.png +0 -0
- package/src/activity/builder.ts +0 -141
- package/src/activity/index.ts +0 -34
- package/src/agents.ts +0 -31
- package/src/api.ts +0 -51
- package/src/assets.ts +0 -1579
- package/src/chains.ts +0 -604
- package/src/host.ts +0 -1212
- package/src/index.ts +0 -36
- package/src/storage/daoMetaData.ts +0 -312
- package/src/storage/daos.ts +0 -306
- package/tests/assets.test.ts +0 -61
- package/tests/chains.test.ts +0 -22
- package/tests/host.test.ts +0 -811
- package/tsconfig.json +0 -18
- /package/{src → out}/tokenlist.json +0 -0
package/out/host.js
ADDED
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
Host prototype.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DAOAction = exports.Host = exports.UnitComponentCategory = exports.UnitStatus = exports.UnitType = exports.FundingType = exports.LifecyclePhase = exports.HOST_DESCRIPTION = void 0;
|
|
7
|
+
exports.getDAOUnit = getDAOUnit;
|
|
8
|
+
exports.getDAOUnitMetaData = getDAOUnitMetaData;
|
|
9
|
+
const chains_1 = require("./chains");
|
|
10
|
+
exports.HOST_DESCRIPTION = "A Cozy Home for DAOs";
|
|
11
|
+
/**
|
|
12
|
+
Lifecycle phase represents DAO tokenomics stage.
|
|
13
|
+
*/
|
|
14
|
+
var LifecyclePhase;
|
|
15
|
+
(function (LifecyclePhase) {
|
|
16
|
+
/** Created */
|
|
17
|
+
LifecyclePhase["DRAFT"] = "DRAFT";
|
|
18
|
+
/**
|
|
19
|
+
Initial funding. DAO project passed requirements.
|
|
20
|
+
Since SEED started a DAO become real DAO:
|
|
21
|
+
- noncustodial
|
|
22
|
+
- tokenized share holdings
|
|
23
|
+
- collective management via voting
|
|
24
|
+
*/
|
|
25
|
+
LifecyclePhase["SEED"] = "SEED";
|
|
26
|
+
/** Seed was not success. Raised funds sent back to seeders. */
|
|
27
|
+
LifecyclePhase["SEED_FAILED"] = "SEED_FAILED";
|
|
28
|
+
/** Using SEED funds to launch MVP / Unit generating */
|
|
29
|
+
LifecyclePhase["DEVELOPMENT"] = "DEVELOPMENT";
|
|
30
|
+
/** TGE is funding event for token liquidity and DAO developments (optionally) */
|
|
31
|
+
LifecyclePhase["TGE"] = "TGE";
|
|
32
|
+
/** Delay before any vesting allocation started */
|
|
33
|
+
LifecyclePhase["LIVE_CLIFF"] = "LIVE_CLIFF";
|
|
34
|
+
/** Vesting period active */
|
|
35
|
+
LifecyclePhase["LIVE_VESTING"] = "LIVE_VESTING";
|
|
36
|
+
/** Vesting ended - token fully distributed */
|
|
37
|
+
LifecyclePhase["LIVE"] = "LIVE";
|
|
38
|
+
})(LifecyclePhase || (exports.LifecyclePhase = LifecyclePhase = {}));
|
|
39
|
+
var FundingType;
|
|
40
|
+
(function (FundingType) {
|
|
41
|
+
FundingType["SEED"] = "SEED";
|
|
42
|
+
FundingType["TGE"] = "TGE";
|
|
43
|
+
})(FundingType || (exports.FundingType = FundingType = {}));
|
|
44
|
+
/** Supported unit types */
|
|
45
|
+
var UnitType;
|
|
46
|
+
(function (UnitType) {
|
|
47
|
+
/** VE-token early exit fees */
|
|
48
|
+
UnitType["PVP"] = "PVP";
|
|
49
|
+
/** Decentralized finance protocol */
|
|
50
|
+
UnitType["DEFI_PROTOCOL"] = "DEFI_PROTOCOL";
|
|
51
|
+
/** Maximum Extractable Value opportunities searcher and submitter. */
|
|
52
|
+
UnitType["MEV_SEARCHER"] = "MEV_SEARCHER";
|
|
53
|
+
/** Software as a Service business */
|
|
54
|
+
//SAAS = "SAAS",
|
|
55
|
+
})(UnitType || (exports.UnitType = UnitType = {}));
|
|
56
|
+
/** Unit status can be changed automatically on DAO lifecycle phase changes or manually by DAO holders */
|
|
57
|
+
var UnitStatus;
|
|
58
|
+
(function (UnitStatus) {
|
|
59
|
+
UnitStatus["RESEARCH"] = "RESEARCH";
|
|
60
|
+
UnitStatus["BUILDING"] = "BUILDING";
|
|
61
|
+
UnitStatus["LIVE"] = "LIVE";
|
|
62
|
+
})(UnitStatus || (exports.UnitStatus = UnitStatus = {}));
|
|
63
|
+
/** Supported categories of running units. */
|
|
64
|
+
var UnitComponentCategory;
|
|
65
|
+
(function (UnitComponentCategory) {
|
|
66
|
+
UnitComponentCategory["CHAIN_SUPPORT"] = "CHAIN_SUPPORT";
|
|
67
|
+
UnitComponentCategory["ENGINE_SUPPORT"] = "ENGINE_SUPPORT";
|
|
68
|
+
UnitComponentCategory["DEFI_STRATEGY"] = "DEFI_STRATEGY";
|
|
69
|
+
UnitComponentCategory["MEV_STRATEGY"] = "MEV_STRATEGY";
|
|
70
|
+
})(UnitComponentCategory || (exports.UnitComponentCategory = UnitComponentCategory = {}));
|
|
71
|
+
//export type UnitComponent = StrategyShortId | ChainName | LendingEngine;
|
|
72
|
+
/**
|
|
73
|
+
Typescript implementation of the Host
|
|
74
|
+
Object of this class is Host instance deployed on a single blockchain.
|
|
75
|
+
|
|
76
|
+
@class
|
|
77
|
+
*/
|
|
78
|
+
class Host {
|
|
79
|
+
constructor(chainId) {
|
|
80
|
+
/** Chain block timestamp */
|
|
81
|
+
this.blockTimestamp = Math.floor(new Date().getTime() / 1000);
|
|
82
|
+
/** Local DAOs storage (in form of a mapping) */
|
|
83
|
+
this.daos = {};
|
|
84
|
+
/** Actual DAO symbols at all blockchains */
|
|
85
|
+
this.usedSymbols = {};
|
|
86
|
+
/** All emitted events */
|
|
87
|
+
this.events = [];
|
|
88
|
+
/** Governance proposals. Can be created only at initialChain of DAO. */
|
|
89
|
+
this.proposals = {};
|
|
90
|
+
/** Current user address */
|
|
91
|
+
this.from = "0x00";
|
|
92
|
+
this.settings = {
|
|
93
|
+
priceDao: 1000,
|
|
94
|
+
priceUnit: 1000,
|
|
95
|
+
priceOracle: 1000,
|
|
96
|
+
priceBridge: 1000,
|
|
97
|
+
minNameLength: 1,
|
|
98
|
+
maxNameLength: 20,
|
|
99
|
+
minSymbolLength: 1,
|
|
100
|
+
maxSymbolLength: 7,
|
|
101
|
+
minVePeriod: 14,
|
|
102
|
+
maxVePeriod: 365 * 4,
|
|
103
|
+
minPvPFee: 10,
|
|
104
|
+
maxPvPFee: 100,
|
|
105
|
+
minFundingDuration: 1,
|
|
106
|
+
maxFundingDuration: 180,
|
|
107
|
+
};
|
|
108
|
+
this.chainId = chainId;
|
|
109
|
+
}
|
|
110
|
+
static getTokensNaming(name, symbol) {
|
|
111
|
+
return {
|
|
112
|
+
seedName: `${name} SEED`,
|
|
113
|
+
seedSymbol: `seed${symbol}`,
|
|
114
|
+
tgeName: `${name} PRESALE`,
|
|
115
|
+
tgeSymbol: `sale${symbol}`,
|
|
116
|
+
tokenName: name,
|
|
117
|
+
tokenSymbol: symbol,
|
|
118
|
+
xName: `x${name}`,
|
|
119
|
+
xSymbol: `x${symbol}`,
|
|
120
|
+
daoName: `${name} DAO`,
|
|
121
|
+
daoSymbol: `${symbol}_DAO`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
static isLiveDAO(phase) {
|
|
125
|
+
return [
|
|
126
|
+
LifecyclePhase.LIVE_CLIFF,
|
|
127
|
+
LifecyclePhase.LIVE_VESTING,
|
|
128
|
+
LifecyclePhase.LIVE,
|
|
129
|
+
].includes(phase);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Create new DAO
|
|
133
|
+
* @throws Error
|
|
134
|
+
*/
|
|
135
|
+
createDAO(name, symbol, activity, params, funding, metaDataLocation) {
|
|
136
|
+
const dao = {
|
|
137
|
+
phase: LifecyclePhase.DRAFT,
|
|
138
|
+
name,
|
|
139
|
+
symbol,
|
|
140
|
+
activity,
|
|
141
|
+
socials: [],
|
|
142
|
+
images: {},
|
|
143
|
+
deployments: {},
|
|
144
|
+
units: [],
|
|
145
|
+
params,
|
|
146
|
+
chainSettings: {
|
|
147
|
+
bbRate: 50,
|
|
148
|
+
},
|
|
149
|
+
initialChain: chains_1.chains[this.chainId].name,
|
|
150
|
+
funding,
|
|
151
|
+
vesting: [],
|
|
152
|
+
governanceSettings: {},
|
|
153
|
+
deployer: this.from,
|
|
154
|
+
daoMetaDataLocation: metaDataLocation,
|
|
155
|
+
unitsMetaData: [],
|
|
156
|
+
};
|
|
157
|
+
this.validate(dao);
|
|
158
|
+
this.daos[dao.symbol] = dao;
|
|
159
|
+
this.usedSymbols[dao.symbol] = true;
|
|
160
|
+
this._emit("DAO created");
|
|
161
|
+
this._sendCrossChainMessage(CROSS_CHAIN_MESSAGE.NEW_DAO_SYMBOL, {
|
|
162
|
+
symbol,
|
|
163
|
+
});
|
|
164
|
+
return dao;
|
|
165
|
+
}
|
|
166
|
+
/** Add live compatible DAO */
|
|
167
|
+
addLiveDAO(dao) {
|
|
168
|
+
// todo _onlyVerifier
|
|
169
|
+
this.validate(dao);
|
|
170
|
+
this.daos[dao.symbol] = dao;
|
|
171
|
+
this.usedSymbols[dao.symbol] = true;
|
|
172
|
+
this._emit("DAO created");
|
|
173
|
+
this._sendCrossChainMessage(CROSS_CHAIN_MESSAGE.NEW_DAO_SYMBOL, {
|
|
174
|
+
symbol: dao.symbol,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
getDAOMetaData(daoMetaData, symbol) {
|
|
178
|
+
const dao = this.getDAO(symbol);
|
|
179
|
+
if (dao.daoMetaDataLocation === "local") {
|
|
180
|
+
return daoMetaData[symbol.toLowerCase()];
|
|
181
|
+
}
|
|
182
|
+
return {};
|
|
183
|
+
}
|
|
184
|
+
/** Change lifecycle phase of a DAO */
|
|
185
|
+
changePhase(symbol) {
|
|
186
|
+
// anybody can call this
|
|
187
|
+
const dao = this.getDAO(symbol);
|
|
188
|
+
const currentTasks = this.tasks(symbol);
|
|
189
|
+
if (currentTasks.length > 0) {
|
|
190
|
+
throw new Error("SolveTasksFirst");
|
|
191
|
+
}
|
|
192
|
+
if (dao.phase === LifecyclePhase.DRAFT) {
|
|
193
|
+
const seed = dao.funding[this.getFundingIndex(symbol, FundingType.SEED)];
|
|
194
|
+
if (seed.start > this.blockTimestamp) {
|
|
195
|
+
throw new Error("WaitFundingStart");
|
|
196
|
+
}
|
|
197
|
+
// SEED can be started not later than 1 week after must start
|
|
198
|
+
// todo settings.maxSeedStartDelay
|
|
199
|
+
if (seed.start < this.blockTimestamp &&
|
|
200
|
+
this.blockTimestamp - seed.start > 7 * 86400) {
|
|
201
|
+
throw new Error("TooLateSoSetupFundingAgain");
|
|
202
|
+
}
|
|
203
|
+
/*// SEED can be started not later than 1 week before end
|
|
204
|
+
if (seed.end - this.blockTimestamp < 7 * 86400) {
|
|
205
|
+
throw new Error("TooLateSoSetupFundingAgain")
|
|
206
|
+
}*/
|
|
207
|
+
// deploy seedToken
|
|
208
|
+
this.daos[symbol].deployments[this.chainId] = {
|
|
209
|
+
seedToken: "0xProxyDeployed",
|
|
210
|
+
};
|
|
211
|
+
this.daos[symbol].phase = LifecyclePhase.SEED;
|
|
212
|
+
}
|
|
213
|
+
else if (dao.phase === LifecyclePhase.SEED) {
|
|
214
|
+
const seed = dao.funding[this.getFundingIndex(symbol, FundingType.SEED)];
|
|
215
|
+
if (seed.end > this.blockTimestamp) {
|
|
216
|
+
throw new Error("WaitFundingEnd");
|
|
217
|
+
}
|
|
218
|
+
const sucess = seed.raised >= seed.minRaise;
|
|
219
|
+
if (sucess) {
|
|
220
|
+
this.daos[symbol].phase = LifecyclePhase.DEVELOPMENT;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
// send all raised back to seeders
|
|
224
|
+
this.daos[symbol].phase = LifecyclePhase.SEED_FAILED;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else if (dao.phase === LifecyclePhase.DEVELOPMENT) {
|
|
228
|
+
const tge = dao.funding[this.getFundingIndex(symbol, FundingType.TGE)];
|
|
229
|
+
if (tge.start > this.blockTimestamp) {
|
|
230
|
+
throw new Error("WaitFundingStart");
|
|
231
|
+
}
|
|
232
|
+
// deploy tgeToken
|
|
233
|
+
this.daos[symbol].deployments[this.chainId].tgeToken =
|
|
234
|
+
"0xProxyDeployedTge";
|
|
235
|
+
this.daos[symbol].phase = LifecyclePhase.TGE;
|
|
236
|
+
}
|
|
237
|
+
else if (dao.phase === LifecyclePhase.TGE) {
|
|
238
|
+
const tge = dao.funding[this.getFundingIndex(symbol, FundingType.TGE)];
|
|
239
|
+
if (tge.end > this.blockTimestamp) {
|
|
240
|
+
throw new Error("WaitFundingEnd");
|
|
241
|
+
}
|
|
242
|
+
const success = tge.raised >= tge.minRaise;
|
|
243
|
+
if (success) {
|
|
244
|
+
// deploy token, xToken, staking, daoToken
|
|
245
|
+
this.daos[symbol].deployments[this.chainId].token = "0xProxyToken";
|
|
246
|
+
this.daos[symbol].deployments[this.chainId].xToken = "0xProxyXToken";
|
|
247
|
+
this.daos[symbol].deployments[this.chainId].staking = "0xProxyStaking";
|
|
248
|
+
this.daos[symbol].deployments[this.chainId].daoToken =
|
|
249
|
+
"0xProxyDAOToken";
|
|
250
|
+
// todo deploy vesting contracts and allocate token
|
|
251
|
+
// todo seedToken holders became xToken holders by predefined rate
|
|
252
|
+
// todo deploy v2 liquidity from TGE funds at predefined price
|
|
253
|
+
this.daos[symbol].phase = LifecyclePhase.LIVE_CLIFF;
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
// send all raised TGE funds back to funders
|
|
257
|
+
this.daos[symbol].phase = LifecyclePhase.DEVELOPMENT;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else if (dao.phase === LifecyclePhase.LIVE_CLIFF) {
|
|
261
|
+
// if any vesting started then phase changed
|
|
262
|
+
const isVestingStarted = !!dao.vesting?.filter((v) => v.start < this.blockTimestamp).length;
|
|
263
|
+
if (!isVestingStarted) {
|
|
264
|
+
throw new Error("WaitVestingStart");
|
|
265
|
+
}
|
|
266
|
+
this.daos[symbol].phase = LifecyclePhase.LIVE_VESTING;
|
|
267
|
+
}
|
|
268
|
+
else if (dao.phase === LifecyclePhase.LIVE_VESTING) {
|
|
269
|
+
// if any vesting started then phase changed
|
|
270
|
+
const isVestingEnded = !dao.vesting?.filter((v) => v.end > this.blockTimestamp).length;
|
|
271
|
+
if (!isVestingEnded) {
|
|
272
|
+
throw new Error("WaitVestingEnd");
|
|
273
|
+
}
|
|
274
|
+
this.daos[symbol].phase = LifecyclePhase.LIVE;
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
// nothing to change
|
|
278
|
+
throw new Error("ForeverLive");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/** @throws Error */
|
|
282
|
+
updateImages(symbol, images) {
|
|
283
|
+
// check DAO symbol
|
|
284
|
+
const dao = this.getDAO(symbol);
|
|
285
|
+
// instant execute for DRAFT
|
|
286
|
+
if (dao.phase === LifecyclePhase.DRAFT) {
|
|
287
|
+
this._onlyOwnerOf(symbol);
|
|
288
|
+
this._updateImages(symbol, images);
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
// create proposal for other phases
|
|
292
|
+
return this._proposeAction(symbol, DAOAction.UPDATE_IMAGES, {
|
|
293
|
+
images,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
/** @throws Error */
|
|
297
|
+
updateSocials(symbol, socials) {
|
|
298
|
+
// check DAO symbol
|
|
299
|
+
const dao = this.getDAO(symbol);
|
|
300
|
+
// instant execute for DRAFT
|
|
301
|
+
if (dao.phase === LifecyclePhase.DRAFT) {
|
|
302
|
+
this._onlyOwnerOf(symbol);
|
|
303
|
+
this._updateSocials(symbol, socials);
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
306
|
+
// create proposal for other phases
|
|
307
|
+
return this._proposeAction(symbol, DAOAction.UPDATE_SOCIALS, {
|
|
308
|
+
socials,
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
/** @throws Error */
|
|
312
|
+
updateUnits(symbol, units, unitsMetaData) {
|
|
313
|
+
// check DAO symbol
|
|
314
|
+
const dao = this.getDAO(symbol);
|
|
315
|
+
// instant execute for DRAFT
|
|
316
|
+
if (dao.phase === LifecyclePhase.DRAFT) {
|
|
317
|
+
this._onlyOwnerOf(symbol);
|
|
318
|
+
this._updateUnits(symbol, units, unitsMetaData);
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
// create proposal for other phases
|
|
322
|
+
return this._proposeAction(symbol, DAOAction.UPDATE_UNITS, {
|
|
323
|
+
units,
|
|
324
|
+
unitsMetaData,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
/** @throws Error */
|
|
328
|
+
updateFunding(symbol, funding) {
|
|
329
|
+
// check DAO symbol
|
|
330
|
+
const dao = this.getDAO(symbol);
|
|
331
|
+
// validate payload
|
|
332
|
+
this._validateFunding(dao.phase, [funding]);
|
|
333
|
+
// instant execute for DRAFT
|
|
334
|
+
if (dao.phase === LifecyclePhase.DRAFT) {
|
|
335
|
+
this._onlyOwnerOf(symbol);
|
|
336
|
+
this._updateFunding(symbol, funding);
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
// create proposal for other phases
|
|
340
|
+
return this._proposeAction(symbol, DAOAction.UPDATE_FUNDING, {
|
|
341
|
+
funding,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
_updateSocials(symbol, socials) {
|
|
345
|
+
this.daos[symbol].socials = socials;
|
|
346
|
+
this._emit(`Action ${DAOAction.UPDATE_SOCIALS}`);
|
|
347
|
+
}
|
|
348
|
+
_updateUnits(symbol, units, unitsMetaData) {
|
|
349
|
+
this.daos[symbol].units = units;
|
|
350
|
+
this.daos[symbol].unitsMetaData = unitsMetaData;
|
|
351
|
+
this._emit(`Action ${DAOAction.UPDATE_UNITS}`);
|
|
352
|
+
}
|
|
353
|
+
_updateFunding(symbol, funding) {
|
|
354
|
+
const dao = this.getDAO(symbol);
|
|
355
|
+
const fundingExist = dao.funding.filter((f) => f.type === funding.type).length === 1;
|
|
356
|
+
if (fundingExist) {
|
|
357
|
+
const fundingIndex = this.getFundingIndex(symbol, funding.type);
|
|
358
|
+
this.daos[symbol].funding[fundingIndex] = funding;
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
this.daos[symbol].funding.push(funding);
|
|
362
|
+
}
|
|
363
|
+
this._emit(`Action ${DAOAction.UPDATE_FUNDING}`);
|
|
364
|
+
}
|
|
365
|
+
updateVesting(symbol, vestings) {
|
|
366
|
+
// check DAO symbol
|
|
367
|
+
const dao = this.getDAO(symbol);
|
|
368
|
+
// validate
|
|
369
|
+
this._validateVesting(dao.phase, vestings);
|
|
370
|
+
// instant execute for DRAFT
|
|
371
|
+
if (dao.phase === LifecyclePhase.DRAFT) {
|
|
372
|
+
this._onlyOwnerOf(symbol);
|
|
373
|
+
this._updateVesting(symbol, vestings);
|
|
374
|
+
return true;
|
|
375
|
+
}
|
|
376
|
+
// create proposal for other phases
|
|
377
|
+
return this._proposeAction(symbol, DAOAction.UPDATE_VESTING, {
|
|
378
|
+
vestings,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
fund(symbol, amount) {
|
|
382
|
+
// todo settings.minFunding
|
|
383
|
+
const dao = this.getDAO(symbol);
|
|
384
|
+
if (dao.phase === LifecyclePhase.SEED) {
|
|
385
|
+
const seedIndex = this.getFundingIndex(symbol, FundingType.SEED);
|
|
386
|
+
const seed = dao.funding[seedIndex];
|
|
387
|
+
if (seed.raised + amount >= seed.maxRaise) {
|
|
388
|
+
throw new Error("RaiseMaxExceed");
|
|
389
|
+
}
|
|
390
|
+
// transfer amount of exchangeAsset to seedToken contract
|
|
391
|
+
this.daos[symbol].funding[seedIndex].raised += amount;
|
|
392
|
+
// mint seedToken to user
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
if (dao.phase === LifecyclePhase.TGE) {
|
|
396
|
+
const tgeIndex = this.getFundingIndex(symbol, FundingType.TGE);
|
|
397
|
+
const tge = dao.funding[tgeIndex];
|
|
398
|
+
if (tge.raised + amount >= tge.maxRaise) {
|
|
399
|
+
throw new Error("RaiseMaxExceed");
|
|
400
|
+
}
|
|
401
|
+
// transfer amount of exchangeAsset to tgeToken contract
|
|
402
|
+
this.daos[symbol].funding[tgeIndex].raised += amount;
|
|
403
|
+
// mint tgeToken to user
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
throw new Error("NotFundingPhase");
|
|
407
|
+
}
|
|
408
|
+
receiveVotingResults(proposalId, succeed) {
|
|
409
|
+
const proposal = this.proposals[proposalId];
|
|
410
|
+
if (!proposal) {
|
|
411
|
+
throw new Error("IncorrectProposal");
|
|
412
|
+
}
|
|
413
|
+
if (proposal.status !== VotingStatus.VOTING) {
|
|
414
|
+
throw new Error("AlreadyReceived");
|
|
415
|
+
}
|
|
416
|
+
this.proposals[proposalId].status = succeed
|
|
417
|
+
? VotingStatus.APPROVED
|
|
418
|
+
: VotingStatus.REJECTED;
|
|
419
|
+
if (succeed) {
|
|
420
|
+
if (proposal.action === DAOAction.UPDATE_IMAGES) {
|
|
421
|
+
this._updateImages(proposal.symbol, proposal.payload.images);
|
|
422
|
+
}
|
|
423
|
+
if (proposal.action === DAOAction.UPDATE_SOCIALS) {
|
|
424
|
+
this._updateSocials(proposal.symbol, proposal.payload.socials);
|
|
425
|
+
}
|
|
426
|
+
if (proposal.action === DAOAction.UPDATE_UNITS) {
|
|
427
|
+
this._updateUnits(proposal.symbol, proposal.payload.units, proposal.payload.unitsMetaData);
|
|
428
|
+
}
|
|
429
|
+
if (proposal.action === DAOAction.UPDATE_FUNDING) {
|
|
430
|
+
this._updateFunding(proposal.symbol, proposal.payload.funding);
|
|
431
|
+
}
|
|
432
|
+
if (proposal.action === DAOAction.UPDATE_VESTING) {
|
|
433
|
+
this._updateVesting(proposal.symbol, proposal.payload.vestings);
|
|
434
|
+
}
|
|
435
|
+
// todo other actions
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
/** OFF-CHAIN only **/
|
|
439
|
+
/** @throws Error */
|
|
440
|
+
roadmap(symbol) {
|
|
441
|
+
const dao = this.getDAO(symbol);
|
|
442
|
+
const r = [];
|
|
443
|
+
let tgeRun = 0;
|
|
444
|
+
for (const funding of dao.funding) {
|
|
445
|
+
if (funding.type === FundingType.SEED) {
|
|
446
|
+
r.push({
|
|
447
|
+
phase: LifecyclePhase.SEED,
|
|
448
|
+
start: funding.start,
|
|
449
|
+
end: funding.end,
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
if (funding.type === FundingType.TGE) {
|
|
453
|
+
// if SEED was done
|
|
454
|
+
if (r.length > 0) {
|
|
455
|
+
r.push({
|
|
456
|
+
phase: LifecyclePhase.DEVELOPMENT,
|
|
457
|
+
start: r[0].end + 1,
|
|
458
|
+
end: funding.start - 1,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
tgeRun = funding.claim || funding.end;
|
|
462
|
+
r.push({
|
|
463
|
+
phase: LifecyclePhase.TGE,
|
|
464
|
+
start: funding.start,
|
|
465
|
+
end: tgeRun,
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
if (dao.vesting.length > 0) {
|
|
470
|
+
let vestingStart = this.blockTimestamp;
|
|
471
|
+
let vestingEnd = this.blockTimestamp;
|
|
472
|
+
for (const vesting of dao.vesting) {
|
|
473
|
+
if (vesting.start < vestingStart) {
|
|
474
|
+
vestingStart = vesting.start;
|
|
475
|
+
}
|
|
476
|
+
if (vesting.end > vestingEnd) {
|
|
477
|
+
vestingEnd = vesting.end;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
r.push({
|
|
481
|
+
phase: LifecyclePhase.LIVE_CLIFF,
|
|
482
|
+
start: tgeRun + 1,
|
|
483
|
+
end: vestingStart - 1,
|
|
484
|
+
});
|
|
485
|
+
r.push({
|
|
486
|
+
phase: LifecyclePhase.LIVE_VESTING,
|
|
487
|
+
start: vestingStart,
|
|
488
|
+
end: vestingEnd,
|
|
489
|
+
});
|
|
490
|
+
r.push({
|
|
491
|
+
phase: LifecyclePhase.LIVE,
|
|
492
|
+
start: vestingEnd + 1,
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
return r;
|
|
496
|
+
}
|
|
497
|
+
/** @throws Error */
|
|
498
|
+
tasks(symbol) {
|
|
499
|
+
const dao = this.getDAO(symbol);
|
|
500
|
+
const r = [];
|
|
501
|
+
if (dao.phase === LifecyclePhase.DRAFT) {
|
|
502
|
+
// images
|
|
503
|
+
if (!dao.images.seedToken || !dao.images.token) {
|
|
504
|
+
r.push({
|
|
505
|
+
name: "Need images of token and seedToken",
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
// socials
|
|
509
|
+
if (dao.socials.length < 2) {
|
|
510
|
+
r.push({
|
|
511
|
+
name: "Need at least 2 socials",
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
// units projected
|
|
515
|
+
if (dao.units.length === 0) {
|
|
516
|
+
r.push({
|
|
517
|
+
name: "Need at least 1 projected unit",
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
else if (dao.phase === LifecyclePhase.SEED) {
|
|
522
|
+
const seedIndex = this.getFundingIndex(symbol, FundingType.SEED);
|
|
523
|
+
if (dao.funding[seedIndex].raised < dao.funding[seedIndex].minRaise &&
|
|
524
|
+
dao.funding[seedIndex].end > this.blockTimestamp) {
|
|
525
|
+
r.push({
|
|
526
|
+
name: "Need attract minimal seed funding",
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
else if (dao.phase === LifecyclePhase.DEVELOPMENT) {
|
|
531
|
+
// check funding
|
|
532
|
+
const tgeExist = dao.funding.filter((f) => f.type === FundingType.TGE).length === 1;
|
|
533
|
+
if (!tgeExist) {
|
|
534
|
+
r.push({
|
|
535
|
+
name: "Need add pre-TGE funding",
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
// images
|
|
539
|
+
if (!dao.images.tgeToken || !dao.images.xToken || !dao.images.daoToken) {
|
|
540
|
+
r.push({
|
|
541
|
+
name: "Need images of all DAO tokens",
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
// setup vesting allocations
|
|
545
|
+
if (!dao.vesting?.length) {
|
|
546
|
+
r.push({
|
|
547
|
+
name: "Need vesting allocations",
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
if (dao.unitsMetaData?.filter((unitMetaData) => unitMetaData.status === UnitStatus.LIVE).length === 0) {
|
|
551
|
+
r.push({
|
|
552
|
+
name: "Run revenue generating units",
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
else if (dao.phase === LifecyclePhase.TGE) {
|
|
557
|
+
const tgeIndex = this.getFundingIndex(symbol, FundingType.TGE);
|
|
558
|
+
if (dao.funding[tgeIndex].raised < dao.funding[tgeIndex].minRaise &&
|
|
559
|
+
dao.funding[tgeIndex].end > this.blockTimestamp) {
|
|
560
|
+
r.push({
|
|
561
|
+
name: "Need attract minimal TGE funding",
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
else if (dao.phase === LifecyclePhase.LIVE_CLIFF) {
|
|
566
|
+
// establish and improve
|
|
567
|
+
// build money markets
|
|
568
|
+
// bridge to chains
|
|
569
|
+
}
|
|
570
|
+
else if (dao.phase === LifecyclePhase.LIVE_VESTING) {
|
|
571
|
+
// distribute vesting funds to leverage token
|
|
572
|
+
}
|
|
573
|
+
/*if (dao.phase === LifecyclePhase.LIVE)*/
|
|
574
|
+
// lifetime revenue generating for DAO holders (till ABSORBED proposed feature)
|
|
575
|
+
return r;
|
|
576
|
+
}
|
|
577
|
+
/** Strict on-chain validation */
|
|
578
|
+
/** @throws Error */
|
|
579
|
+
validate(dao) {
|
|
580
|
+
this._validateName(dao.name);
|
|
581
|
+
this._validateSymbol(dao.symbol);
|
|
582
|
+
if (dao.params.vePeriod < this.settings.minVePeriod ||
|
|
583
|
+
dao.params.vePeriod > this.settings.maxVePeriod) {
|
|
584
|
+
throw new Error(`VePeriod(${dao.params.vePeriod})`);
|
|
585
|
+
}
|
|
586
|
+
this._validatePvpFee(dao.params.pvpFee);
|
|
587
|
+
if (!dao.funding.length) {
|
|
588
|
+
throw new Error("NeedFunding");
|
|
589
|
+
}
|
|
590
|
+
// todo: check activity are correct
|
|
591
|
+
// todo: check funding array has unique funding types
|
|
592
|
+
// todo: check funding dates
|
|
593
|
+
// todo: check funding raise goals
|
|
594
|
+
}
|
|
595
|
+
/** @throws Error */
|
|
596
|
+
getDAO(symbol) {
|
|
597
|
+
if (this.daos[symbol]) {
|
|
598
|
+
return this.daos[symbol];
|
|
599
|
+
}
|
|
600
|
+
throw new Error("DAONotFound");
|
|
601
|
+
}
|
|
602
|
+
getDaoOwner(symbol) {
|
|
603
|
+
const dao = this.getDAO(symbol);
|
|
604
|
+
if (dao.phase === LifecyclePhase.DRAFT) {
|
|
605
|
+
return dao.deployer;
|
|
606
|
+
}
|
|
607
|
+
if ([
|
|
608
|
+
LifecyclePhase.SEED,
|
|
609
|
+
LifecyclePhase.DEVELOPMENT,
|
|
610
|
+
LifecyclePhase.TGE,
|
|
611
|
+
].includes(dao.phase)) {
|
|
612
|
+
return dao.deployments[(0, chains_1.getChainByName)(dao.initialChain).chainId]
|
|
613
|
+
.seedToken;
|
|
614
|
+
}
|
|
615
|
+
return dao.deployments[this.chainId]?.daoToken;
|
|
616
|
+
}
|
|
617
|
+
getFundingIndex(symbol, type) {
|
|
618
|
+
const dao = this.getDAO(symbol);
|
|
619
|
+
for (let i = 0; i < dao.funding.length; i++) {
|
|
620
|
+
if (type === dao.funding[i].type) {
|
|
621
|
+
return i;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
throw new Error("FundingNotFound");
|
|
625
|
+
}
|
|
626
|
+
warpDays(days = 7) {
|
|
627
|
+
this.blockTimestamp += days * 86400;
|
|
628
|
+
}
|
|
629
|
+
/** @throws Error */
|
|
630
|
+
_onlyOwnerOf(symbol) {
|
|
631
|
+
if (this.from != this.getDaoOwner(symbol)) {
|
|
632
|
+
throw new Error(`YouAreNotOwnerOf(${symbol})`);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
_emit(event) {
|
|
636
|
+
this.events.push(event);
|
|
637
|
+
}
|
|
638
|
+
_validateName(name) {
|
|
639
|
+
if (name.length < this.settings.minNameLength ||
|
|
640
|
+
name.length > this.settings.maxNameLength) {
|
|
641
|
+
throw new Error(`NameLength(${name.length})`);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
_validateSymbol(symbol) {
|
|
645
|
+
if (symbol.length < this.settings.minSymbolLength ||
|
|
646
|
+
symbol.length > this.settings.maxSymbolLength) {
|
|
647
|
+
throw new Error(`SymbolLength(${symbol.length})`);
|
|
648
|
+
}
|
|
649
|
+
if (this.usedSymbols[symbol]) {
|
|
650
|
+
throw new Error(`SymbolNotUnique(${symbol})`);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
_validatePvpFee(pvpFee) {
|
|
654
|
+
if (pvpFee < this.settings.minPvPFee || pvpFee > this.settings.maxPvPFee) {
|
|
655
|
+
throw new Error(`PvPFee(${pvpFee})`);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
_validateFunding(daoPhase, fundings) {
|
|
659
|
+
for (const funding of fundings) {
|
|
660
|
+
if (funding.type === FundingType.SEED &&
|
|
661
|
+
daoPhase !== LifecyclePhase.DRAFT) {
|
|
662
|
+
throw new Error("TooLateToUpdateSuchFunding");
|
|
663
|
+
}
|
|
664
|
+
if (funding.type === FundingType.TGE &&
|
|
665
|
+
![
|
|
666
|
+
LifecyclePhase.DRAFT,
|
|
667
|
+
LifecyclePhase.SEED,
|
|
668
|
+
LifecyclePhase.DEVELOPMENT,
|
|
669
|
+
].includes(daoPhase)) {
|
|
670
|
+
throw new Error("TooLateToUpdateSuchFunding");
|
|
671
|
+
}
|
|
672
|
+
// todo check min round duration
|
|
673
|
+
// todo check max round duration
|
|
674
|
+
// todo check start date delay
|
|
675
|
+
// todo check min amount
|
|
676
|
+
// todo check max amount
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
_validateVesting(daoPhase, vestings) {
|
|
680
|
+
if ([
|
|
681
|
+
LifecyclePhase.LIVE_CLIFF,
|
|
682
|
+
LifecyclePhase.LIVE_VESTING,
|
|
683
|
+
LifecyclePhase.LIVE,
|
|
684
|
+
].includes(daoPhase)) {
|
|
685
|
+
throw new Error("TooLateToUpdateVesting");
|
|
686
|
+
}
|
|
687
|
+
for (const vesting of vestings) {
|
|
688
|
+
// todo check vesting consistency
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
_sendCrossChainMessage(type, payload) {
|
|
692
|
+
// todo some stub
|
|
693
|
+
}
|
|
694
|
+
_proposeAction(symbol, action, payload) {
|
|
695
|
+
const dao = this.getDAO(symbol);
|
|
696
|
+
// todo check for initial chain
|
|
697
|
+
// todo get user power
|
|
698
|
+
// todo check proposalThreshold
|
|
699
|
+
// todo validate payload
|
|
700
|
+
const proposalId = Math.round(Math.random() * Math.random()).toString();
|
|
701
|
+
this.proposals[proposalId] = {
|
|
702
|
+
id: proposalId,
|
|
703
|
+
created: this.blockTimestamp,
|
|
704
|
+
action,
|
|
705
|
+
symbol,
|
|
706
|
+
payload,
|
|
707
|
+
status: VotingStatus.VOTING,
|
|
708
|
+
};
|
|
709
|
+
return proposalId;
|
|
710
|
+
}
|
|
711
|
+
_updateImages(symbol, images) {
|
|
712
|
+
this.daos[symbol].images = images;
|
|
713
|
+
this._emit(`Action ${DAOAction.UPDATE_IMAGES}`);
|
|
714
|
+
}
|
|
715
|
+
_updateVesting(symbol, vestings) {
|
|
716
|
+
this.daos[symbol].vesting = vestings;
|
|
717
|
+
this._emit(`Action ${DAOAction.UPDATE_VESTING}`);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
exports.Host = Host;
|
|
721
|
+
var DAOAction;
|
|
722
|
+
(function (DAOAction) {
|
|
723
|
+
DAOAction[DAOAction["UPDATE_IMAGES"] = 0] = "UPDATE_IMAGES";
|
|
724
|
+
DAOAction[DAOAction["UPDATE_SOCIALS"] = 1] = "UPDATE_SOCIALS";
|
|
725
|
+
DAOAction[DAOAction["UPDATE_NAMING"] = 2] = "UPDATE_NAMING";
|
|
726
|
+
DAOAction[DAOAction["UPDATE_UNITS"] = 3] = "UPDATE_UNITS";
|
|
727
|
+
DAOAction[DAOAction["UPDATE_FUNDING"] = 4] = "UPDATE_FUNDING";
|
|
728
|
+
DAOAction[DAOAction["UPDATE_VESTING"] = 5] = "UPDATE_VESTING";
|
|
729
|
+
})(DAOAction || (exports.DAOAction = DAOAction = {}));
|
|
730
|
+
var VotingStatus;
|
|
731
|
+
(function (VotingStatus) {
|
|
732
|
+
VotingStatus[VotingStatus["VOTING"] = 0] = "VOTING";
|
|
733
|
+
VotingStatus[VotingStatus["APPROVED"] = 1] = "APPROVED";
|
|
734
|
+
VotingStatus[VotingStatus["REJECTED"] = 2] = "REJECTED";
|
|
735
|
+
})(VotingStatus || (VotingStatus = {}));
|
|
736
|
+
var CROSS_CHAIN_MESSAGE;
|
|
737
|
+
(function (CROSS_CHAIN_MESSAGE) {
|
|
738
|
+
CROSS_CHAIN_MESSAGE[CROSS_CHAIN_MESSAGE["NEW_DAO_SYMBOL"] = 0] = "NEW_DAO_SYMBOL";
|
|
739
|
+
CROSS_CHAIN_MESSAGE[CROSS_CHAIN_MESSAGE["DAO_RENAME_SYMBOL"] = 1] = "DAO_RENAME_SYMBOL";
|
|
740
|
+
CROSS_CHAIN_MESSAGE[CROSS_CHAIN_MESSAGE["DAO_BRIDGED"] = 2] = "DAO_BRIDGED";
|
|
741
|
+
})(CROSS_CHAIN_MESSAGE || (CROSS_CHAIN_MESSAGE = {}));
|
|
742
|
+
function getDAOUnit(daos, symbol, unitId) {
|
|
743
|
+
for (const dao of daos) {
|
|
744
|
+
if (dao.symbol.toLowerCase() === symbol.toLowerCase()) {
|
|
745
|
+
for (const unit of dao.units) {
|
|
746
|
+
if (unit.unitId === unitId) {
|
|
747
|
+
return unit;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
function getDAOUnitMetaData(daos, symbol, unitId) {
|
|
754
|
+
for (const dao of daos) {
|
|
755
|
+
if (dao.symbol.toLowerCase() === symbol.toLowerCase()) {
|
|
756
|
+
for (let i = 0; i < dao.units.length; i++) {
|
|
757
|
+
const unit = dao.units[i];
|
|
758
|
+
if (unit.unitId === unitId) {
|
|
759
|
+
return dao.unitsMetaData[i];
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
//# sourceMappingURL=host.js.map
|