UNPKG

12.6 kBJavaScriptView Raw
1
2var inquirer = require("inquirer");
3var gift = require("gift");
4var fs = require("fs");
5var async = require('async');
6var path = require("path");
7var rmdir = require("rmdir");
8var npm = require("npm");
9var request = require("request");
10var valid_url = require("valid-url");
11var fsExtra = require('fs-extra');
12var AschJS = require('asch-js');
13var accountHelper = require("../helpers/account.js");
14var blockHelper = require("../helpers/block.js");
15var dappHelper = require("../helpers/dapp.js");
16var Api = require("../helpers/api.js");
17
18var templatePath = path.join(__dirname, "..", "template");
19
20var dappCategories = [
21 "Common",
22 "Business",
23 "Catalogs",
24 "Education",
25 "Entertainment",
26 "Multimedia",
27 "Networking",
28 "Utilities",
29 "Games"
30];
31function addDapp() {
32 var account;
33 var secondSecret;
34 var dappParams;
35 var dappTrs;
36 var dappBlock;
37 var dappsPath = path.join(".", "dapps");
38 var dappPath;
39 async.series([
40 function(next) {
41 inquirer.prompt([
42 {
43 type: "password",
44 name: "secret",
45 message: "Enter secret of your testnet account",
46 validate: function (value) {
47 var done = this.async();
48
49 if (!accountHelper.isValidSecret(value)) {
50 done("Secret is not validated by BIP39");
51 return;
52 }
53
54 done(true);
55 }
56 },
57 {
58 type: "password",
59 name: "secondSecret",
60 message: "Enter second secret of your testnet account if you have"
61 }
62 ], function (result) {
63 account = accountHelper.account(result.secret);
64 secondSecret = result.secondSecret;
65 next();
66 })
67 },
68 function(next) {
69 inquirer.prompt([
70 {
71 type: "input",
72 name: "name",
73 message: "Enter DApp name",
74 required: true,
75 validate: function (value) {
76 var done = this.async();
77
78 if (value.length == 0) {
79 done("DApp name is too short, minimum is 1 character");
80 return;
81 }
82
83 if (value.length > 32) {
84 done("DApp name is too long, maximum is 32 characters");
85 return;
86 }
87
88 return done(true)
89 }
90 },
91 {
92 type: "input",
93 name: "description",
94 message: "Enter DApp description",
95 validate: function (value) {
96 var done = this.async();
97
98 if (value.length > 160) {
99 done("DApp description is too long, maximum is 160 characters");
100 return;
101 }
102
103 return done(true);
104 }
105 },
106 {
107 type: "input",
108 name: "tags",
109 message: "Enter DApp tags",
110 validate: function (value) {
111 var done = this.async();
112
113 if (value.length > 160) {
114 done("DApp tags is too long, maximum is 160 characters");
115 return;
116 }
117
118 return done(true);
119 }
120 },
121 {
122 type: "rawlist",
123 name: "category",
124 required: true,
125 message: "Choose DApp category",
126 choices: dappCategories
127 },
128 {
129 type: "input",
130 name: "link",
131 message: "Enter DApp link",
132 required: true,
133 validate: function (value) {
134 var done = this.async();
135
136 if (!valid_url.isUri(value)) {
137 done("Invalid DApp link, must be a valid url");
138 return;
139 }
140 if (value.indexOf(".zip") != value.length - 4) {
141 done("Invalid DApp link, does not link to zip file");
142 return;
143 }
144 if (value.length > 160) {
145 return done("DApp link is too long, maximum is 160 characters");
146 }
147
148 return done(true);
149 }
150 },
151 {
152 type: "input",
153 name: "icon",
154 message: "Enter DApp icon url",
155 validate: function (value) {
156 var done = this.async();
157
158 if (!valid_url.isUri(value)) {
159 return done("Invalid DApp icon, must be a valid url");
160 }
161 var extname = path.extname(value);
162 if (['.png', '.jpg', '.jpeg'].indexOf(extname) == -1) {
163 return done("Invalid DApp icon file type");
164 }
165 if (value.length > 160) {
166 return done("DApp icon url is too long, maximum is 160 characters");
167 }
168
169 return done(true);
170 }
171 }
172 ], function (result) {
173 if (!result.name || !result.link || !result.category) {
174 return next(new Error('invalid dapp params'));
175 }
176 dappParams = {
177 name: result.name,
178 link: result.link,
179 category: dappCategories.indexOf(result.category) + 1,
180 description: result.description || "",
181 tags: result.tags || "",
182 icon: result.icon || "",
183 type: 0
184 };
185 dappTrs = AschJS.dapp.createDapp(account.secret, secondSecret, dappParams);
186 console.log("Generate dapp transaction", dappTrs);
187 next();
188 });
189 },
190 function(next) {
191 inquirer.prompt([
192 {
193 type: "input",
194 name: "publicKeys",
195 message: "Enter public keys of dapp forgers - hex array, use ',' for separator",
196 default: account.keypair.publicKey,
197 validate: function (value) {
198 var done = this.async();
199
200 var publicKeys = value.split(",");
201
202 if (publicKeys.length == 0) {
203 done("DApp requires at least 1 public key");
204 return;
205 }
206
207 for (var i in publicKeys) {
208 try {
209 var b = new Buffer(publicKeys[i], "hex");
210 if (b.length != 32) {
211 done("Invalid public key: " + publicKeys[i]);
212 return;
213 }
214 } catch (e) {
215 done("Invalid hex for public key: " + publicKeys[i]);
216 return;
217 }
218 }
219 done(true);
220 }
221 }
222 ], function (result) {
223 if (!result.publicKeys) {
224 return next("invalid dapp forger public keys");
225 }
226 console.log("Creating DApp genesis block");
227 dappBlock = dappHelper.new(account, result.publicKeys.split(","));
228 next();
229 });
230 },
231 function(next) {
232 console.log("Fetching Asch Dapps SDK");
233 fs.exists(dappsPath, function (exists) {
234 if (!exists) {
235 fs.mkdir(dappsPath, next);
236 } else {
237 next();
238 }
239 });
240 },
241 function(next) {
242 dappPath = path.join(dappsPath, dappTrs.id);
243 fsExtra.copy(templatePath, dappPath, {clobber: true}, next);
244 },
245 function(next) {
246 console.log("Saving genesis block");
247 var genesisBlockJson = JSON.stringify(dappBlock, null, 2);
248 fs.writeFile(path.join(dappPath, "genesis.json"), genesisBlockJson, "utf8", next);
249 },
250 function(next) {
251 console.log("Saving dapp meta information");
252 var dappParamsJson = JSON.stringify(dappParams, null, 2);
253 fs.writeFile(path.join(dappPath, "dapp.json"), dappParamsJson, "utf8", next);
254 },
255 function (next) {
256 console.log("Registering dapp in localnet");
257 var api = new Api({port: 4096});
258 api.broadcastTransaction(dappTrs, function (err) {
259 if (err) {
260 next("Failed to register dapp: " + err);
261 } else {
262 next();
263 }
264 });
265 }
266 ], function(err) {
267 if (err) {
268 console.log(err);
269 } else {
270 setTimeout(function () {
271 console.log("Done (DApp id is " + dappTrs.id + ")");
272 }, 10000);
273 }
274 });
275}
276
277function changeDapp() {
278 inquirer.prompt([
279 {
280 type: "confirm",
281 name: "confirmed",
282 message: "Existing blockchain will be replaced, are you sure?",
283 default: false
284 }
285 ], function (result) {
286 if (result.confirmed) {
287 inquirer.prompt([
288 {
289 type: "password",
290 name: "secret",
291 message: "Enter secret of your testnet account",
292 validate: function (value) {
293 var done = this.async();
294
295 if (value.length == 0) {
296 done("Secret is too short, minimum is 1 character");
297 return;
298 }
299
300 if (value.length > 100) {
301 done("Secret is too long, maximum is 100 characters");
302 return;
303 }
304
305 done(true);
306 }
307 },
308 {
309 type: "input",
310 name: "dappId",
311 message: "Enter DApp id (folder name of dapp)",
312 required: true
313 },
314 ], function (result) {
315 var account = accountHelper.account(result.secret);
316 var dappId = result.dappId;
317 var publicKeys = [];
318
319 var dappPath = path.join(".", "dapps", dappId);
320 var dappGenesis = JSON.parse(fs.readFileSync(path.join(dappPath, "genesis.json"), "utf8"));
321
322 inquirer.prompt([
323 {
324 type: "confirm",
325 name: "confirmed",
326 message: "Continue with exists forgers public keys",
327 required: true,
328 }], function (result) {
329 if (result.confirmed) {
330 publicKeys = dappGenesis.delegates;
331 }
332
333 inquirer.prompt([
334 {
335 type: "input",
336 name: "publicKeys",
337 message: "Enter public keys of dapp forgers - hex array, use ',' for separator",
338 default: account.keypair.publicKey,
339 validate: function (value) {
340 var done = this.async();
341
342 var publicKeys = value.split(",");
343
344 if (publicKeys.length == 0) {
345 done("DApp requires at least 1 public key");
346 return;
347 }
348
349 for (var i in publicKeys) {
350 try {
351 var b = new Buffer(publicKeys[i], "hex");
352 if (b.length != 32) {
353 done("Invalid public key: " + publicKeys[i]);
354 return;
355 }
356 } catch (e) {
357 done("Invalid hex for public key: " + publicKeys[i]);
358 return;
359 }
360 }
361
362 done(true);
363 }
364 }
365 ], function (result) {
366 console.log("Creating DApp genesis block");
367
368 var dappBlock = dappHelper.new(account, dappGenesis, result.publicKeys.split(","));
369 var dappGenesisBlockJson = JSON.stringify(dappBlock, null, 2);
370
371 try {
372 fs.writeFileSync(path.join(dappPath, "genesis.json"), dappGenesisBlockJson, "utf8");
373 } catch (e) {
374 return console.log(err);
375 }
376
377 console.log("Done");
378 });
379 });
380 });
381 }
382 });
383}
384
385function depositDapp() {
386 inquirer.prompt([
387 {
388 type: "password",
389 name: "secret",
390 message: "Enter secret",
391 validate: function (value) {
392 return value.length > 0 && value.length < 100;
393 },
394 required: true
395 },
396 {
397 type: "input",
398 name: "amount",
399 message: "Enter amount",
400 validate: function (value) {
401 return !isNaN(parseInt(value));
402 },
403 required: true
404 },
405 {
406 type: "input",
407 name: "dappId",
408 message: "DApp Id",
409 required: true
410 },
411 {
412 type: "input",
413 name: "secondSecret",
414 message: "Enter secondary secret (if defined)",
415 validate: function (value) {
416 return value.length < 100;
417 },
418 required: false
419 }
420 ], function (result) {
421 var body = {
422 secret: result.secret,
423 dappId: result.dappId,
424 amount: parseInt(result.amount)
425 };
426
427 if (result.secondSecret && result.secondSecret.length > 0) {
428 body.secondSecret = result.secondSecret;
429 }
430
431 inquirer.prompt([
432 {
433 type: "input",
434 name: "host",
435 message: "Host and port",
436 default: "localhost:4096",
437 required: true
438 }
439 ], function (result) {
440 request({
441 url: "http://" + result.host + "/api/dapps/transaction",
442 method: "put",
443 json: true,
444 body: body
445 }, function (err, resp, body) {
446 console.log(err, body);
447 if (err) {
448 return console.log(err.toString());
449 }
450
451 if (body.success) {
452 console.log(body.transactionId);
453 return;
454 } else {
455 return console.log(body.error);
456 }
457 });
458 });
459 });
460}
461
462function withdrawalDapp() {
463 inquirer.prompt([
464 {
465 type: "password",
466 name: "secret",
467 message: "Enter secret",
468 validate: function (value) {
469 return value.length > 0 && value.length < 100;
470 },
471 required: true
472 },
473 {
474 type: "input",
475 name: "amount",
476 message: "Amount",
477 validate: function (value) {
478 return !isNaN(parseInt(value));
479 },
480 required: true
481 },
482 {
483 type: "input",
484 name: "dappId",
485 message: "Enter DApp id",
486 validate: function (value) {
487 var isAddress = /^[0-9]+$/g;
488 return isAddress.test(value);
489 },
490 required: true
491 }], function (result) {
492
493 var body = {
494 secret: result.secret,
495 amount: Number(result.amount)
496 };
497
498 request({
499 url: "http://localhost:4096/api/dapps/" + result.dappId + "/api/withdrawal",
500 method: "post",
501 json: true,
502 body: body
503 }, function (err, resp, body) {
504 if (err) {
505 return console.log(err.toString());
506 }
507
508 if (body.success) {
509 console.log(body.transactionId);
510 } else {
511 return console.log(body.error);
512 }
513 });
514 });
515}
516
517module.exports = function (program) {
518 program
519 .command("dapps")
520 .description("manage your dapps")
521 .option("-a, --add", "add new dapp")
522 .option("-c, --change", "change dapp genesis block")
523 .option("-d, --deposit", "deposit funds to dapp")
524 .option("-w, --withdrawal", "withdraw funds from dapp")
525 .action(function (options) {
526 if (options.add) {
527 addDapp();
528 } else if (options.change) {
529 changeDapp();
530 } else if (options.deposit) {
531 depositDapp();
532 } else if (options.withdrawal) {
533 withdrawalDapp();
534 } else {
535 console.log("'node dapps -h' to get help");
536 }
537 });
538}
\No newline at end of file