UNPKG

16.8 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 "Social",
24 "Education",
25 "Entertainment",
26 "News",
27 "Life",
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 var assetInfo;
40 async.series([
41 function(next) {
42 inquirer.prompt([
43 {
44 type: "password",
45 name: "secret",
46 message: "Enter secret of your testnet account",
47 validate: function (value) {
48 var done = this.async();
49
50 if (!accountHelper.isValidSecret(value)) {
51 done("Secret is not validated by BIP39");
52 return;
53 }
54
55 done(true);
56 }
57 },
58 {
59 type: "password",
60 name: "secondSecret",
61 message: "Enter second secret of your testnet account if you have"
62 }
63 ], function (result) {
64 account = accountHelper.account(result.secret);
65 secondSecret = result.secondSecret;
66 next();
67 })
68 },
69 function(next) {
70 inquirer.prompt([
71 {
72 type: "input",
73 name: "name",
74 message: "Enter DApp name",
75 required: true,
76 validate: function (value) {
77 var done = this.async();
78
79 if (value.length == 0) {
80 done("DApp name is too short, minimum is 1 character");
81 return;
82 }
83
84 if (value.length > 32) {
85 done("DApp name is too long, maximum is 32 characters");
86 return;
87 }
88
89 return done(true)
90 }
91 },
92 {
93 type: "input",
94 name: "description",
95 message: "Enter DApp description",
96 validate: function (value) {
97 var done = this.async();
98
99 if (value.length > 160) {
100 done("DApp description is too long, maximum is 160 characters");
101 return;
102 }
103
104 return done(true);
105 }
106 },
107 {
108 type: "input",
109 name: "tags",
110 message: "Enter DApp tags",
111 validate: function (value) {
112 var done = this.async();
113
114 if (value.length > 160) {
115 done("DApp tags is too long, maximum is 160 characters");
116 return;
117 }
118
119 return done(true);
120 }
121 },
122 {
123 type: "rawlist",
124 name: "category",
125 required: true,
126 message: "Choose DApp category",
127 choices: dappCategories
128 },
129 {
130 type: "input",
131 name: "link",
132 message: "Enter DApp link",
133 required: true,
134 validate: function (value) {
135 var done = this.async();
136
137 if (!valid_url.isUri(value)) {
138 done("Invalid DApp link, must be a valid url");
139 return;
140 }
141 if (value.indexOf(".zip") != value.length - 4) {
142 done("Invalid DApp link, does not link to zip file");
143 return;
144 }
145 if (value.length > 160) {
146 return done("DApp link is too long, maximum is 160 characters");
147 }
148
149 return done(true);
150 }
151 },
152 {
153 type: "input",
154 name: "icon",
155 message: "Enter DApp icon url",
156 validate: function (value) {
157 var done = this.async();
158
159 if (!valid_url.isUri(value)) {
160 return done("Invalid DApp icon, must be a valid url");
161 }
162 var extname = path.extname(value);
163 if (['.png', '.jpg', '.jpeg'].indexOf(extname) == -1) {
164 return done("Invalid DApp icon file type");
165 }
166 if (value.length > 160) {
167 return done("DApp icon url is too long, maximum is 160 characters");
168 }
169
170 return done(true);
171 }
172 }
173 ], function (result) {
174 if (!result.name || !result.link || !result.category) {
175 return next(new Error('invalid dapp params'));
176 }
177 dappParams = {
178 name: result.name,
179 link: result.link,
180 category: dappCategories.indexOf(result.category) + 1,
181 description: result.description || "",
182 tags: result.tags || "",
183 icon: result.icon || "",
184 type: 0
185 };
186 dappTrs = AschJS.dapp.createDapp(account.secret, secondSecret, dappParams);
187 console.log("Generate dapp transaction", dappTrs);
188 next();
189 });
190 },
191 function(next) {
192 inquirer.prompt([
193 {
194 type: "confirm",
195 name: "inbuiltAsset",
196 message: "Do you want publish a inbuilt asset in this dapp?",
197 default: false
198 }
199 ], function (result) {
200 if (!result.inbuiltAsset) {
201 return next();
202 }
203 inquirer.prompt([
204 {
205 type: "input",
206 name: "assetName",
207 message: "Enter asset name, for example: BTC, CNY, USD, MYASSET",
208 default: ''
209 },
210 {
211 type: "input",
212 name: "assetAmount",
213 message: "Enter asset total amount",
214 default: 1000000
215 }
216 ], function (result) {
217 if (!result.assetName || result.assetName === 'XAS') {
218 return next('invalid inbuilt asset name');
219 }
220 var assetAmount = Number(result.assetAmount);
221 if (!assetAmount || isNaN(assetAmount) || assetAmount < 0) {
222 return next('invalid inbuilt asset amount');
223 }
224 assetInfo = {
225 name: result.assetName,
226 amount: assetAmount
227 };
228 next();
229 });
230 });
231 },
232 function(next) {
233 inquirer.prompt([
234 {
235 type: "input",
236 name: "publicKeys",
237 message: "Enter public keys of dapp forgers - hex array, use ',' for separator",
238 default: account.keypair.publicKey,
239 validate: function (value) {
240 var done = this.async();
241
242 var publicKeys = value.split(",");
243
244 if (publicKeys.length == 0) {
245 done("DApp requires at least 1 public key");
246 return;
247 }
248
249 for (var i in publicKeys) {
250 try {
251 var b = new Buffer(publicKeys[i], "hex");
252 if (b.length != 32) {
253 done("Invalid public key: " + publicKeys[i]);
254 return;
255 }
256 } catch (e) {
257 done("Invalid hex for public key: " + publicKeys[i]);
258 return;
259 }
260 }
261 done(true);
262 }
263 }
264 ], function (result) {
265 if (!result.publicKeys) {
266 return next("invalid dapp forger public keys");
267 }
268 console.log("Creating DApp genesis block");
269 dappBlock = dappHelper.new(account, result.publicKeys.split(","), assetInfo);
270 next();
271 });
272 },
273 function(next) {
274 console.log("Fetching Asch Dapps SDK");
275 fs.exists(dappsPath, function (exists) {
276 if (!exists) {
277 fs.mkdir(dappsPath, next);
278 } else {
279 next();
280 }
281 });
282 },
283 function(next) {
284 dappPath = path.join(dappsPath, dappTrs.id);
285 fsExtra.copy(templatePath, dappPath, {clobber: true}, next);
286 },
287 function(next) {
288 console.log("Saving genesis block");
289 var genesisBlockJson = JSON.stringify(dappBlock, null, 2);
290 fs.writeFile(path.join(dappPath, "genesis.json"), genesisBlockJson, "utf8", next);
291 },
292 function(next) {
293 console.log("Saving dapp meta information");
294 var dappParamsJson = JSON.stringify(dappParams, null, 2);
295 fs.writeFile(path.join(dappPath, "dapp.json"), dappParamsJson, "utf8", next);
296 },
297 function (next) {
298 console.log("Registering dapp in localnet");
299 var api = new Api({port: 4096});
300 api.broadcastTransaction(dappTrs, function (err) {
301 if (err) {
302 next("Failed to register dapp: " + err);
303 } else {
304 next();
305 }
306 });
307 }
308 ], function(err) {
309 if (err) {
310 console.log(err);
311 } else {
312 setTimeout(function () {
313 console.log("Done (DApp id is " + dappTrs.id + ")");
314 }, 10000);
315 }
316 });
317}
318
319function changeDapp() {
320 inquirer.prompt([
321 {
322 type: "confirm",
323 name: "confirmed",
324 message: "Existing blockchain will be replaced, are you sure?",
325 default: false
326 }
327 ], function (result) {
328 if (result.confirmed) {
329 inquirer.prompt([
330 {
331 type: "password",
332 name: "secret",
333 message: "Enter secret of your testnet account",
334 validate: function (value) {
335 var done = this.async();
336 if (!accountHelper.isValidSecret(value)) {
337 done("Secret is not validated by BIP39");
338 return;
339 }
340 done(true);
341 }
342 },
343 {
344 type: "input",
345 name: "dappId",
346 message: "Enter DApp id (folder name of dapp)",
347 required: true
348 },
349 ], function (result) {
350 var account = accountHelper.account(result.secret);
351 var dappId = result.dappId;
352 var publicKeys = [];
353
354 var dappPath = path.join(".", "dapps", dappId);
355 var dappGenesis = JSON.parse(fs.readFileSync(path.join(dappPath, "genesis.json"), "utf8"));
356 inquirer.prompt([
357 {
358 type: "confirm",
359 name: "inbuiltAsset",
360 message: "Do you want publish a inbuilt asset in this dapp?",
361 default: false
362 }
363 ], function (result) {
364 var assetInfo;
365 if (result.inbuiltAsset) {
366 inquirer.prompt([
367 {
368 type: "input",
369 name: "assetName",
370 message: "Enter asset name, for example: BTC, CNY, USD, MYASSET",
371 default: ''
372 },
373 {
374 type: "input",
375 name: "assetAmount",
376 message: "Enter asset total amount",
377 default: 1000000
378 }
379 ], function (result) {
380 if (!result.assetName || result.assetName === 'XAS') {
381 return next('invalid inbuilt asset name');
382 }
383 var assetAmount = Number(result.assetAmount);
384 if (!assetAmount || isNaN(assetAmount) || assetAmount < 0) {
385 return next('invalid inbuilt asset amount');
386 }
387 assetInfo = {
388 name: result.assetName,
389 amount: assetAmount
390 };
391 });
392 }
393
394 inquirer.prompt([
395 {
396 type: "confirm",
397 name: "confirmed",
398 message: "Continue with exists forgers public keys",
399 required: true,
400 }], function (result) {
401 if (result.confirmed) {
402 publicKeys = dappGenesis.delegates;
403 }
404
405 inquirer.prompt([
406 {
407 type: "input",
408 name: "publicKeys",
409 message: "Enter public keys of dapp forgers - hex array, use ',' for separator",
410 default: account.keypair.publicKey,
411 validate: function (value) {
412 var done = this.async();
413
414 var publicKeys = value.split(",");
415
416 if (publicKeys.length == 0) {
417 done("DApp requires at least 1 public key");
418 return;
419 }
420
421 for (var i in publicKeys) {
422 try {
423 var b = new Buffer(publicKeys[i], "hex");
424 if (b.length != 32) {
425 done("Invalid public key: " + publicKeys[i]);
426 return;
427 }
428 } catch (e) {
429 done("Invalid hex for public key: " + publicKeys[i]);
430 return;
431 }
432 }
433
434 done(true);
435 }
436 }
437 ], function (result) {
438 console.log("Creating DApp genesis block");
439
440 var dappBlock = dappHelper.new(account, result.publicKeys.split(","), assetInfo);
441 var dappGenesisBlockJson = JSON.stringify(dappBlock, null, 2);
442
443 try {
444 fs.writeFileSync(path.join(dappPath, "genesis.json"), dappGenesisBlockJson, "utf8");
445 } catch (e) {
446 return console.log(err);
447 }
448
449 console.log("Done");
450 });
451 });
452 });
453 });
454 }
455 });
456}
457
458function depositDapp() {
459 inquirer.prompt([
460 {
461 type: "password",
462 name: "secret",
463 message: "Enter secret",
464 validate: function (value) {
465 return value.length > 0 && value.length < 100;
466 },
467 required: true
468 },
469 {
470 type: "input",
471 name: "amount",
472 message: "Enter amount",
473 validate: function (value) {
474 return !isNaN(parseInt(value));
475 },
476 required: true
477 },
478 {
479 type: "input",
480 name: "dappId",
481 message: "DApp Id",
482 required: true
483 },
484 {
485 type: "input",
486 name: "secondSecret",
487 message: "Enter secondary secret (if defined)",
488 validate: function (value) {
489 return value.length < 100;
490 },
491 required: false
492 }
493 ], function (result) {
494 var realAmount = parseFloat((parseInt(result.amount) * 100000000).toFixed(0));
495 var body = {
496 secret: result.secret,
497 dappId: result.dappId,
498 amount: realAmount
499 };
500
501 if (result.secondSecret && result.secondSecret.length > 0) {
502 body.secondSecret = result.secondSecret;
503 }
504
505 inquirer.prompt([
506 {
507 type: "input",
508 name: "host",
509 message: "Host and port",
510 default: "localhost:4096",
511 required: true
512 }
513 ], function (result) {
514 request({
515 url: "http://" + result.host + "/api/dapps/transaction",
516 method: "put",
517 json: true,
518 body: body
519 }, function (err, resp, body) {
520 console.log(err, body);
521 if (err) {
522 return console.log(err.toString());
523 }
524
525 if (body.success) {
526 console.log(body.transactionId);
527 return;
528 } else {
529 return console.log(body.error);
530 }
531 });
532 });
533 });
534}
535
536function withdrawalDapp() {
537 inquirer.prompt([
538 {
539 type: "password",
540 name: "secret",
541 message: "Enter secret",
542 validate: function (value) {
543 return value.length > 0 && value.length < 100;
544 },
545 required: true
546 },
547 {
548 type: "input",
549 name: "amount",
550 message: "Amount",
551 validate: function (value) {
552 return !isNaN(parseInt(value));
553 },
554 required: true
555 },
556 {
557 type: "input",
558 name: "dappId",
559 message: "Enter DApp id",
560 validate: function (value) {
561 var isAddress = /^[0-9]+$/g;
562 return isAddress.test(value);
563 },
564 required: true
565 }], function (result) {
566
567 var body = {
568 secret: result.secret,
569 amount: Number(result.amount)
570 };
571
572 request({
573 url: "http://localhost:4096/api/dapps/" + result.dappId + "/api/withdrawal",
574 method: "post",
575 json: true,
576 body: body
577 }, function (err, resp, body) {
578 if (err) {
579 return console.log(err.toString());
580 }
581
582 if (body.success) {
583 console.log(body.transactionId);
584 } else {
585 return console.log(body.error);
586 }
587 });
588 });
589}
590
591function uninstallDapp() {
592 inquirer.prompt([
593 {
594 type: "input",
595 name: "dappId",
596 message: "Enter dapp id",
597 validate: function (value) {
598 return value.length > 0 && value.length < 100;
599 },
600 required: true
601 },
602 {
603 type: "input",
604 name: "host",
605 message: "Host and port",
606 default: "localhost:4096",
607 required: true
608 },
609 {
610 type: "password",
611 name: "masterpassword",
612 message: "Enter dapp master password",
613 required: true
614 }], function (result) {
615
616 var body = {
617 id: String(result.dappId),
618 master: String(result.masterpassword)
619 };
620
621 request({
622 url: "http://" + result.host + "/api/dapps/uninstall",
623 method: "post",
624 json: true,
625 body: body
626 }, function (err, resp, body) {
627 if (err) {
628 return console.log(err.toString());
629 }
630
631 if (body.success) {
632 console.log("Done!");
633 } else {
634 return console.log(body.error);
635 }
636 });
637 });
638}
639
640function installDapp() {
641 inquirer.prompt([
642 {
643 type: "input",
644 name: "dappId",
645 message: "Enter dapp id",
646 validate: function (value) {
647 return value.length > 0 && value.length < 100;
648 },
649 required: true
650 },
651 {
652 type: "input",
653 name: "host",
654 message: "Host and port",
655 default: "localhost:4096",
656 required: true
657 },
658 {
659 type: "password",
660 name: "masterpassword",
661 message: "Enter dapp master password",
662 required: true
663 }], function (result) {
664
665 var body = {
666 id: String(result.dappId),
667 master: String(result.masterpassword)
668 };
669
670 request({
671 url: "http://" + result.host + "/api/dapps/install",
672 method: "post",
673 json: true,
674 body: body
675 }, function (err, resp, body) {
676 if (err) {
677 return console.log(err.toString());
678 }
679
680 if (body.success) {
681 console.log("Done!", body.path);
682 } else {
683 return console.log(body.error);
684 }
685 });
686 });
687}
688
689module.exports = function (program) {
690 program
691 .command("dapps")
692 .description("manage your dapps")
693 .option("-a, --add", "add new dapp")
694 .option("-c, --change", "change dapp genesis block")
695 .option("-d, --deposit", "deposit funds to dapp")
696 .option("-w, --withdrawal", "withdraw funds from dapp")
697 .option("-i, --install", "install dapp")
698 .option("-u, --uninstall", "uninstall dapp")
699 .action(function (options) {
700 if (options.add) {
701 addDapp();
702 } else if (options.change) {
703 changeDapp();
704 } else if (options.deposit) {
705 depositDapp();
706 } else if (options.withdrawal) {
707 withdrawalDapp();
708 } else if (options.install) {
709 installDapp();
710 } else if (options.uninstall) {
711 uninstallDapp();
712 } else {
713 console.log("'node dapps -h' to get help");
714 }
715 });
716}
\No newline at end of file