1 | const _ = require('lodash')
|
2 | const CoinKey = require('@scrypta/coinkey')
|
3 | const crypto = require('crypto')
|
4 | const CryptoJS = require('crypto-js')
|
5 | const secp256k1 = require('secp256k1')
|
6 | const cs = require('coinstring')
|
7 | const axios = require('axios')
|
8 | const Trx = require('./trx/trx')
|
9 | const ScryptaDB = require('./db')
|
10 | const NodeRSA = require('node-rsa');
|
11 | const { sum, round, subtract } = require('mathjs')
|
12 | const { captureRejectionSymbol } = require('events')
|
13 | const { isUndefined } = require('lodash')
|
14 |
|
15 | const lyraInfo = {
|
16 | mainnet: {
|
17 | private: 0xae,
|
18 | public: 0x30,
|
19 | scripthash: 0x0d
|
20 | },
|
21 | testnet: {
|
22 | private: 0xae,
|
23 | public: 0x7f,
|
24 | scripthash: 0x13
|
25 | }
|
26 | }
|
27 |
|
28 | global['io'] = { server: null, client: null, sockets: {} }
|
29 | global['nodes'] = {}
|
30 | global['connected'] = {}
|
31 | global['cache'] = []
|
32 |
|
33 | module.exports = class ScryptaCore {
|
34 | constructor(isBrowser = false) {
|
35 | this.RAWsAPIKey = ''
|
36 | this.PubAddress = ''
|
37 | this.mainnetIdaNodes = ['https://idanodejs01.scryptachain.org', 'https://idanodejs02.scryptachain.org', 'https://idanodejs03.scryptachain.org', 'https://idanodejs04.scryptachain.org', 'https://idanodejs05.scryptachain.org', 'https://idanodejs06.scryptachain.org']
|
38 | this.testnetIdaNodes = ['https://testnet.scryptachain.org']
|
39 | this.staticnodes = false
|
40 | this.debug = false
|
41 | this.MAX_OPRETURN = 7500
|
42 | this.testnet = false
|
43 | this.portP2P = 42226
|
44 | this.sidechain = ''
|
45 | this.idanode = ''
|
46 | this.isBrowser = isBrowser
|
47 | this.math = {}
|
48 | this.math.sum = sum
|
49 | this.math.round = round
|
50 | this.math.subtract = subtract
|
51 |
|
52 | if (isBrowser) {
|
53 | this.importBrowserSID()
|
54 | }
|
55 | this.clearCache()
|
56 | }
|
57 |
|
58 |
|
59 | returnNodes() {
|
60 | const app = this
|
61 | return new Promise(async response => {
|
62 | if (this.staticnodes === false) {
|
63 | if (this.testnet === true) {
|
64 | response(app.testnetIdaNodes)
|
65 | } else {
|
66 | const db = new ScryptaDB(app.isBrowser)
|
67 | let idanodes = await db.get('nodes')
|
68 | try {
|
69 | let nodes_git = await axios.get('https://raw.githubusercontent.com/scryptachain/scrypta-idanode-network/master/peers')
|
70 | let raw_nodes = nodes_git.data.split("\n")
|
71 | let nodes = []
|
72 | for (let x in raw_nodes) {
|
73 | let node = raw_nodes[x].split(':')
|
74 | let url = 'https://idanodejs' + node[0] + '.scryptachain.org'
|
75 | await db.put('nodes', url)
|
76 | nodes.push(url)
|
77 | }
|
78 | response(nodes)
|
79 | } catch (e) {
|
80 | if (idanodes.length > 0) {
|
81 | response(idanodes)
|
82 | } else {
|
83 |
|
84 | response(app.mainnetIdaNodes)
|
85 | }
|
86 | }
|
87 | }
|
88 | } else {
|
89 | if(this.testnet === false){
|
90 | response(app.mainnetIdaNodes)
|
91 | }else{
|
92 | response(app.testnetIdaNodes)
|
93 | }
|
94 | }
|
95 | })
|
96 | }
|
97 |
|
98 | post(endpoint, params, node = '') {
|
99 | const app = this
|
100 | return new Promise(async response => {
|
101 | if (node === '') {
|
102 | node = await app.connectNode()
|
103 | }
|
104 | let res
|
105 | try{
|
106 | res = await axios.post(node + endpoint, params, { timeout: 20000 }).catch(err => {
|
107 | console.log("ERROR ON IDANODE " + node + ": " + err.message)
|
108 | response(false)
|
109 | })
|
110 | }catch(e){
|
111 | node = await app.connectNode()
|
112 | res = await axios.post(node + endpoint, params, { timeout: 20000 }).catch(err => {
|
113 | console.log("ERROR ON IDANODE " + node + ": " + err.message)
|
114 | response(false)
|
115 | })
|
116 | }
|
117 |
|
118 | if(res !== undefined && res.data !== undefined){
|
119 | response(res.data)
|
120 | }else{
|
121 | console.log("ERROR ON IDANODE " + node + ": " + err.message)
|
122 | response(false)
|
123 | }
|
124 | })
|
125 | }
|
126 |
|
127 | get(endpoint, node = '') {
|
128 | const app = this
|
129 | return new Promise(async response => {
|
130 | if (node === '') {
|
131 | node = await app.connectNode()
|
132 | }
|
133 | let res
|
134 | try{
|
135 | res = await axios.get(node + endpoint, { timeout: 20000 }).catch(err => {
|
136 | console.log("ERROR ON IDANODE " + node + ": " + err.message)
|
137 | response(false)
|
138 | })
|
139 | }catch(e){
|
140 | node = await app.connectNode()
|
141 | res = await axios.get(node + endpoint, { timeout: 20000 }).catch(err => {
|
142 | console.log("ERROR ON IDANODE " + node + ": " + err.message)
|
143 | response(false)
|
144 | })
|
145 | }
|
146 | if (res !== undefined && res.data !== undefined) {
|
147 | response(res.data)
|
148 | }else{
|
149 | response(false)
|
150 | }
|
151 | })
|
152 | }
|
153 |
|
154 | testnet(value = true) {
|
155 | this.testnet = value
|
156 | }
|
157 |
|
158 | async checkNode(node) {
|
159 | return new Promise(response => {
|
160 | axios.get(node + '/wallet/getinfo', { timeout: 20000 }).catch(err => {
|
161 | response(false)
|
162 | }).then(result => {
|
163 | response(result)
|
164 | })
|
165 | })
|
166 | }
|
167 |
|
168 | async connectNode() {
|
169 | const app = this
|
170 | return new Promise(async response => {
|
171 | if (app.idanode === '') {
|
172 | let connected = false
|
173 | if(app.debug === true){
|
174 | console.log('CONNECTING TO FIRST AVAILABLE IDANODE')
|
175 | }
|
176 | while (connected === false) {
|
177 | let node = await this.returnFirstNode()
|
178 | if (node !== false) {
|
179 | connected = true
|
180 | app.idanode = node
|
181 | if(app.debug === true){
|
182 | console.log('CONNECTED TO ' + app.idanode)
|
183 | }
|
184 | response(node)
|
185 | }
|
186 | }
|
187 | } else {
|
188 | let check = await app.checkNode(app.idanode)
|
189 | if (check !== false && check.data.toindex <= 1) {
|
190 | if(app.debug === true){
|
191 | console.log('CONNECTED IDANODE ' + app.idanode + ' STILL VALID')
|
192 | }
|
193 | response(app.idanode)
|
194 | } else {
|
195 | app.idanode = ''
|
196 | let connected = false
|
197 | if(app.debug === true){
|
198 | console.log('CONNECTED IDANODE ' + app.idanode + ' NOT VALID ANYMORE, CONNECTING TO NEW IDANODE')
|
199 | }
|
200 | while (connected === false) {
|
201 | let node = await this.returnFirstNode()
|
202 | if (node !== false) {
|
203 | connected = true
|
204 | app.idanode = node
|
205 | response(node)
|
206 | }
|
207 | }
|
208 | }
|
209 | }
|
210 | })
|
211 | }
|
212 |
|
213 | async returnLastChecksum(version) {
|
214 | const app = this
|
215 | return new Promise(async response => {
|
216 | const db = new ScryptaDB(app.isBrowser)
|
217 | let last = await db.get('checksums', 'version', version)
|
218 | if (last === false) {
|
219 | try {
|
220 | let checksums_git = await axios.get('https://raw.githubusercontent.com/scryptachain/scrypta-idanodejs/master/checksum')
|
221 | let checksums = checksums_git.data.split("\n")
|
222 | for (let x in checksums) {
|
223 | let checksum = checksums[x].split(':')
|
224 | if (checksum[0] === version) {
|
225 | await db.put('checksums', {
|
226 | version: version,
|
227 | checksum: checksum[1]
|
228 | })
|
229 | response(checksum[1])
|
230 | }
|
231 | }
|
232 | } catch (e) {
|
233 | console.log(e)
|
234 | response(false)
|
235 | }
|
236 | } else {
|
237 | response(last.checksum)
|
238 | }
|
239 | })
|
240 | }
|
241 |
|
242 | async returnFirstNode() {
|
243 | const app = this
|
244 | return new Promise(async response => {
|
245 | let nodes = await this.returnNodes()
|
246 | var checknodes = this.shuffle(nodes)
|
247 | let connected = false
|
248 | for (var i = 0; i < checknodes.length; i++) {
|
249 | try {
|
250 | axios.get(checknodes[i] + '/wallet/getinfo', { timeout: 20000 }).then(async check => {
|
251 | let checksum = await app.returnLastChecksum(check.data.version)
|
252 | let isValid = true
|
253 | if (checksum !== false) {
|
254 | if (check.data.checksum !== checksum) {
|
255 | isValid = false
|
256 | }
|
257 | }
|
258 | if (check.data.blocks !== undefined && connected === false && check.data.toindex === 0 && isValid) {
|
259 | connected = true
|
260 | if (check.config.url !== undefined) {
|
261 | response(check.config.url.replace('/wallet/getinfo', ''))
|
262 | }
|
263 | }
|
264 | }).catch(err => {
|
265 | response(false)
|
266 | })
|
267 | } catch (err) {
|
268 |
|
269 | }
|
270 | }
|
271 | setTimeout(function () {
|
272 | if (connected === false) {
|
273 | response(false)
|
274 | }
|
275 | }, 1500)
|
276 | })
|
277 | }
|
278 |
|
279 |
|
280 | async clearCache(force = false) {
|
281 | const app = this
|
282 | return new Promise(async response => {
|
283 | const db = new ScryptaDB(app.isBrowser)
|
284 | if (force) {
|
285 | await db.destroy('sxidcache')
|
286 | await db.destroy('txidcache')
|
287 | }
|
288 | await db.destroy('usxocache')
|
289 | await db.destroy('utxocache')
|
290 | response(true)
|
291 | })
|
292 | }
|
293 |
|
294 | async returnTXIDCache() {
|
295 | const app = this
|
296 | return new Promise(async response => {
|
297 | const db = new ScryptaDB(app.isBrowser)
|
298 | let cache = await db.get('txidcache')
|
299 | response(cache)
|
300 | })
|
301 | }
|
302 |
|
303 | async pushTXIDtoCache(txid) {
|
304 | const app = this
|
305 | return new Promise(async response => {
|
306 | const db = new ScryptaDB(app.isBrowser)
|
307 | await db.put('txidcache', txid)
|
308 | response(true)
|
309 | })
|
310 | }
|
311 |
|
312 | async returnUTXOCache() {
|
313 | const app = this
|
314 | return new Promise(async response => {
|
315 | const db = new ScryptaDB(app.isBrowser)
|
316 | let cache = await db.get('utxocache')
|
317 | response(cache)
|
318 | })
|
319 | }
|
320 |
|
321 | async pushUTXOtoCache(utxo) {
|
322 | const app = this
|
323 | return new Promise(async response => {
|
324 | const db = new ScryptaDB(app.isBrowser)
|
325 | await db.put('utxocache', utxo)
|
326 | response(true)
|
327 | })
|
328 | }
|
329 |
|
330 | async returnSXIDCache() {
|
331 | const app = this
|
332 | return new Promise(async response => {
|
333 | const db = new ScryptaDB(app.isBrowser)
|
334 | let cache = await db.get('sxidcache')
|
335 | response(cache)
|
336 | })
|
337 | }
|
338 |
|
339 | async pushSXIDtoCache(sxid) {
|
340 | const app = this
|
341 | return new Promise(async response => {
|
342 | const db = new ScryptaDB(app.isBrowser)
|
343 | await db.put('sxidcache', sxid)
|
344 | response(true)
|
345 | })
|
346 | }
|
347 |
|
348 | async returnUSXOCache() {
|
349 | const app = this
|
350 | return new Promise(async response => {
|
351 | const db = new ScryptaDB(app.isBrowser)
|
352 | let cache = await db.get('usxocache')
|
353 | response(cache)
|
354 | })
|
355 | }
|
356 |
|
357 | async pushUSXOtoCache(usxo) {
|
358 | const app = this
|
359 | return new Promise(async response => {
|
360 | const db = new ScryptaDB(app.isBrowser)
|
361 | await db.put('usxocache', usxo)
|
362 | response(true)
|
363 | })
|
364 | }
|
365 |
|
366 |
|
367 | sleep(ms) {
|
368 | return new Promise(resolve => setTimeout(resolve, ms));
|
369 | }
|
370 |
|
371 |
|
372 | async cryptData(data, password) {
|
373 | return new Promise(response => {
|
374 | let iv = crypto.randomBytes(16)
|
375 | let key = crypto.createHash('sha256').update(String(password)).digest('base64').substr(0, 32)
|
376 | let cipher = crypto.createCipheriv('aes-256-ctr', key, iv);
|
377 | let encrypted = cipher.update(data);
|
378 | encrypted = Buffer.concat([encrypted, cipher.final()]);
|
379 | let hex = iv.toString('hex') + '*' + encrypted.toString('hex')
|
380 | response(hex)
|
381 | })
|
382 | }
|
383 |
|
384 | async decryptData(data, password, buffer = false) {
|
385 | return new Promise(response => {
|
386 | try {
|
387 | if(data.indexOf('*') === -1){
|
388 |
|
389 | var decipher = crypto.createDecipher('aes-256-cbc', password)
|
390 | var dec = decipher.update(data, 'hex', 'utf8')
|
391 | dec += decipher.final('utf8')
|
392 | response(dec)
|
393 | }else{
|
394 | let textParts = data.split('*');
|
395 | let iv = Buffer.from(textParts.shift(), 'hex')
|
396 | let encryptedText = Buffer.from(textParts.join('*'), 'hex')
|
397 | let key = crypto.createHash('sha256').update(String(password)).digest('base64').substr(0, 32)
|
398 | let decipher = crypto.createDecipheriv('aes-256-ctr', key, iv)
|
399 | let decrypted = decipher.update(encryptedText)
|
400 | decrypted = Buffer.concat([decrypted, decipher.final()])
|
401 | if(buffer === false){
|
402 | response(decrypted.toString())
|
403 | }else{
|
404 | response(decrypted)
|
405 | }
|
406 | }
|
407 | } catch (e) {
|
408 | response(false)
|
409 | }
|
410 | })
|
411 | }
|
412 |
|
413 |
|
414 | async cryptFile(file, password) {
|
415 | return new Promise(response => {
|
416 |
|
417 | const reader = new FileReader();
|
418 | reader.onload = function () {
|
419 | var buf = Buffer(reader.result)
|
420 | var cipher = crypto.createCipher('aes-256-cbc', password)
|
421 | var crypted = Buffer.concat([cipher.update(buf), cipher.final()])
|
422 | response(crypted.toString('hex'))
|
423 | };
|
424 |
|
425 | reader.readAsArrayBuffer(file);
|
426 | })
|
427 | }
|
428 |
|
429 |
|
430 | async decryptFile(file, password) {
|
431 | return new Promise(response => {
|
432 | try {
|
433 | let buf = Buffer(file, 'hex')
|
434 | var decipher = crypto.createDecipher('aes-256-cbc', password)
|
435 | var decrypted = Buffer.concat([decipher.update(buf), decipher.final()])
|
436 | response(decrypted)
|
437 | } catch (e) {
|
438 | response(false)
|
439 | }
|
440 | })
|
441 | }
|
442 |
|
443 |
|
444 | async createAddress(password, saveKey = true) {
|
445 |
|
446 | let params = lyraInfo.mainnet
|
447 | if (this.testnet === true) {
|
448 | params = lyraInfo.testnet
|
449 | }
|
450 | var ck = new CoinKey.createRandom(params)
|
451 |
|
452 | var lyrapub = ck.publicAddress;
|
453 | var lyraprv = ck.privateWif;
|
454 | var lyrakey = ck.publicKey.toString('hex');
|
455 |
|
456 | var wallet = {
|
457 | prv: lyraprv,
|
458 | key: lyrakey
|
459 | }
|
460 |
|
461 | var walletstore = await this.buildWallet(password, lyrapub, wallet, saveKey)
|
462 |
|
463 | var response = {
|
464 | pub: lyrapub,
|
465 | key: lyrakey,
|
466 | prv: lyraprv,
|
467 | walletstore: walletstore
|
468 | }
|
469 | return response;
|
470 | }
|
471 |
|
472 | async buildWallet(password, pub, wallet, saveKey) {
|
473 | const app = this
|
474 | const db = new ScryptaDB(app.isBrowser)
|
475 | return new Promise(async response => {
|
476 |
|
477 | let wallethex = await this.cryptData(JSON.stringify(wallet), password)
|
478 | var walletstore = pub + ':' + wallethex;
|
479 |
|
480 | if (saveKey === true) {
|
481 | let check = await db.get('wallet', 'address', pub)
|
482 | if (!check) {
|
483 | await db.put('wallet', {
|
484 | address: pub,
|
485 | wallet: walletstore
|
486 | })
|
487 | } else {
|
488 | await db.update('wallet', 'address', pub, {
|
489 | address: pub,
|
490 | wallet: walletstore
|
491 | })
|
492 | }
|
493 | }
|
494 |
|
495 | response(walletstore)
|
496 | })
|
497 | }
|
498 |
|
499 | async initAddress(address) {
|
500 | const app = this
|
501 | const node = await app.connectNode();
|
502 | const response = await axios.post(node + '/init', { address: address, airdrop: true })
|
503 | return response;
|
504 | }
|
505 |
|
506 | async getPublicKey(privateWif) {
|
507 | var ck = new CoinKey.fromWif(privateWif);
|
508 | var pubkey = ck.publicKey.toString('hex');
|
509 | return pubkey;
|
510 | }
|
511 |
|
512 | async getAddressFromPubKey(pubKey) {
|
513 | return new Promise(response => {
|
514 | let params = lyraInfo.mainnet
|
515 | if (this.testnet === true) {
|
516 | params = lyraInfo.testnet
|
517 | }
|
518 | let pubkeybuffer = Buffer.from(pubKey, 'hex')
|
519 | var sha = crypto.createHash('sha256').update(pubkeybuffer).digest()
|
520 | let pubKeyHash = crypto.createHash('rmd160').update(sha).digest()
|
521 | var hash160Buf = Buffer.from(pubKeyHash, 'hex')
|
522 | response(cs.encode(hash160Buf, params.public))
|
523 | })
|
524 | }
|
525 |
|
526 | async importBrowserSID() {
|
527 | const app = this
|
528 | const db = new ScryptaDB(app.isBrowser)
|
529 | if (app.isBrowser) {
|
530 | let SID = localStorage.getItem('SID')
|
531 | if (SID !== null) {
|
532 | let SIDS = SID.split(':')
|
533 | let check = await db.get('wallet', 'address', SIDS[0])
|
534 | if (!check) {
|
535 | await db.put('wallet', {
|
536 | address: SIDS[0],
|
537 | wallet: SIDS[0] + ':' + SIDS[1]
|
538 | })
|
539 | }
|
540 | }
|
541 | }
|
542 | }
|
543 |
|
544 |
|
545 | importPrivateKey(key, password) {
|
546 | return new Promise(async response => {
|
547 | let lyrakey = await this.getPublicKey(key)
|
548 | let lyrapub = await this.getAddressFromPubKey(lyrakey)
|
549 |
|
550 | var wallet = {
|
551 | prv: key,
|
552 | key: lyrakey
|
553 | }
|
554 | var walletstore = await this.buildWallet(password, lyrapub, wallet, true)
|
555 |
|
556 | response({
|
557 | pub: lyrapub,
|
558 | key: lyrakey,
|
559 | prv: key,
|
560 | walletstore: walletstore
|
561 | })
|
562 | })
|
563 | }
|
564 |
|
565 | returnKey(address) {
|
566 | const app = this
|
567 | return new Promise(async response => {
|
568 | if (address.length === 34) {
|
569 | const db = new ScryptaDB(app.isBrowser)
|
570 | let doc = await db.get('wallet', 'address', address)
|
571 | if (doc !== undefined) {
|
572 | response(doc.wallet)
|
573 | } else {
|
574 | response(false)
|
575 | }
|
576 | } else {
|
577 | response(address)
|
578 | }
|
579 | })
|
580 | }
|
581 |
|
582 | async readKey(password, key) {
|
583 | let wallet = await this.returnKey(key)
|
584 | if (wallet !== false) {
|
585 | if (password !== '') {
|
586 | var SIDS = key.split(':');
|
587 | try {
|
588 | let decrypted = await this.decryptData(SIDS[1], password)
|
589 | return Promise.resolve(JSON.parse(decrypted));
|
590 | } catch (ex) {
|
591 |
|
592 | return Promise.resolve(false);
|
593 | }
|
594 | }
|
595 | } else {
|
596 | return false
|
597 | }
|
598 | }
|
599 |
|
600 |
|
601 | async listUnspent(address) {
|
602 | const app = this
|
603 | const node = await app.connectNode();
|
604 | var unspent = await app.get('/unspent/' + address)
|
605 | return unspent.unspent
|
606 | }
|
607 |
|
608 | async sendRawTransaction(rawtransaction) {
|
609 | const app = this
|
610 | var txid = await app.post('/sendrawtransaction',
|
611 | { rawtransaction: rawtransaction }
|
612 | ).catch(function (err) {
|
613 | console.log(err)
|
614 | })
|
615 | return txid.data
|
616 | }
|
617 |
|
618 | async decodeRawTransaction(rawtransaction) {
|
619 | const app = this
|
620 | const node = await app.connectNode();
|
621 | if (node !== undefined) {
|
622 | var transaction = await axios.post(
|
623 | node + '/decoderawtransaction',
|
624 | { rawtransaction: rawtransaction }
|
625 | ).catch(function (err) {
|
626 | console.log(err)
|
627 | })
|
628 | return transaction.data.transaction
|
629 | } else {
|
630 | return Promise.resolve(false)
|
631 | }
|
632 | }
|
633 |
|
634 | async build(key, password, send = false, to, amount, metadata = '', fees = 0.001) {
|
635 | var SID = key;
|
636 | var MAX_OPRETURN = this.MAX_OPRETURN
|
637 | if (password !== '') {
|
638 | var SIDS = SID.split(':');
|
639 | try {
|
640 | let decrypted = await this.decryptData(SIDS[1], password)
|
641 | decrypted = JSON.parse(decrypted)
|
642 | var trx = Trx.transaction();
|
643 | var from = SIDS[0]
|
644 | var unspent = []
|
645 | var inputs = []
|
646 | var cache = await this.returnUTXOCache()
|
647 | if (cache !== undefined && cache.length > 0) {
|
648 | for (var x = 0; x < cache.length; x++) {
|
649 | if(this.debug){
|
650 | console.log(cache[x])
|
651 | }
|
652 | if(cache[x].address === SIDS[0]){
|
653 | unspent.push(cache[x])
|
654 | }
|
655 | }
|
656 | }
|
657 | var listunspent = await this.listUnspent(from)
|
658 | for (var x = 0; x < listunspent.length; x++) {
|
659 | unspent.push(listunspent[x])
|
660 | }
|
661 | if(this.debug){
|
662 | console.log('UNSPENT', unspent, unspent.length)
|
663 | }
|
664 | if (unspent.length > 0) {
|
665 | var inputamount = 0;
|
666 | var amountneed = amount + fees;
|
667 | for (var i = 0; i < unspent.length; i++) {
|
668 | if (inputamount <= amountneed) {
|
669 | var txid = unspent[i]['txid'];
|
670 | var index = unspent[i]['vout'];
|
671 | var script = unspent[i]['scriptPubKey'];
|
672 | var cache = await this.returnTXIDCache()
|
673 | if (cache.indexOf(txid + ':' + index) === -1 && inputs.indexOf(txid + ':' + index) === -1) {
|
674 | trx.addinput(txid, index, script);
|
675 | inputamount += unspent[i]['amount']
|
676 | inputs.push(txid + ':' + index)
|
677 | }else if(this.debug){
|
678 | console.log('INPUT ALREADY IN CACHE ' + txid + ':' + index)
|
679 | }
|
680 | }
|
681 | }
|
682 | if (inputamount >= amountneed) {
|
683 | var change = inputamount - amountneed;
|
684 | if (amount > 0.00001) {
|
685 | trx.addoutput(to, amount);
|
686 | }
|
687 | if (change > 0.00001) {
|
688 | trx.addoutput(from, change);
|
689 | }
|
690 | if (metadata !== '') {
|
691 | if (metadata.length <= MAX_OPRETURN) {
|
692 |
|
693 | trx.addmetadata(metadata);
|
694 | } else {
|
695 |
|
696 | }
|
697 | }
|
698 | var wif = decrypted.prv;
|
699 | var signed = trx.sign(wif, 1);
|
700 | if (send === false) {
|
701 | return Promise.resolve({
|
702 | inputs: inputs,
|
703 | signed: signed
|
704 | });
|
705 | } else {
|
706 | var txid = await this.sendRawTransaction(signed)
|
707 | if(this.debug){
|
708 | console.log(txid)
|
709 | }
|
710 | if (txid !== undefined && txid !== null && txid.length === 64) {
|
711 | for (let i in inputs) {
|
712 | await this.pushTXIDtoCache(inputs[i])
|
713 | }
|
714 |
|
715 | return Promise.resolve(txid)
|
716 | }else{
|
717 | return Promise.resolve(false)
|
718 | }
|
719 | }
|
720 | } else {
|
721 | if(this.debug){ console.log('NOT ENOUGH FUNDS') }
|
722 | return Promise.resolve(false)
|
723 | }
|
724 | } else {
|
725 |
|
726 | return Promise.resolve(false)
|
727 | }
|
728 | } catch (error) {
|
729 | console.log(error)
|
730 | return Promise.resolve(false);
|
731 | }
|
732 | }
|
733 | }
|
734 |
|
735 | async send(key, password, to, amount, metadata = '') {
|
736 | let wallet = await this.returnKey(key)
|
737 | if (wallet !== false) {
|
738 | if (password !== '' && to !== '') {
|
739 | var SIDS = wallet.split(':');
|
740 | try {
|
741 | let decrypted = await this.decryptData(SIDS[1], password)
|
742 | if(decrypted !== false){
|
743 | var txid = ''
|
744 | var i = 0
|
745 | var rawtransaction
|
746 | while (txid !== null && txid !== undefined && txid.length !== 64) {
|
747 | var fees = 0.001 + (i / 1000)
|
748 | rawtransaction = await this.build(wallet, password, false, to, amount, metadata, fees)
|
749 | if(rawtransaction === false){
|
750 | Promise.resolve(false)
|
751 | }
|
752 | txid = await this.sendRawTransaction(rawtransaction.signed)
|
753 | if(this.debug){
|
754 | console.log(rawtransaction, txid)
|
755 | }
|
756 | if (txid !== null && txid !== false && txid.length === 64) {
|
757 | for (let i in rawtransaction.inputs) {
|
758 | await this.pushTXIDtoCache(rawtransaction.inputs[i])
|
759 | }
|
760 |
|
761 | var decoded = await this.decodeRawTransaction(rawtransaction.signed)
|
762 | if (decoded.vout[1].scriptPubKey.addresses !== undefined) {
|
763 | let unspent = {
|
764 | txid: decoded.txid,
|
765 | vout: 1,
|
766 | address: decoded.vout[1].scriptPubKey.addresses[0],
|
767 | scriptPubKey: decoded.vout[1].scriptPubKey.hex,
|
768 | amount: decoded.vout[1].value
|
769 | }
|
770 | await this.pushUTXOtoCache(unspent)
|
771 | }
|
772 | } else {
|
773 | txid = null
|
774 | }
|
775 | i++;
|
776 | }
|
777 | return Promise.resolve(txid)
|
778 | }else{
|
779 | return Promise.resolve(false)
|
780 | }
|
781 | } catch (e) {
|
782 | return Promise.resolve(false)
|
783 | }
|
784 | } else {
|
785 | return false
|
786 | }
|
787 | } else {
|
788 | return false
|
789 | }
|
790 | }
|
791 |
|
792 |
|
793 | usePlanum(sidechain) {
|
794 | const app = this
|
795 | app.sidechain = sidechain
|
796 | }
|
797 |
|
798 | async listPlanumUnspent(address) {
|
799 | return new Promise(async response => {
|
800 | const app = this
|
801 | let unspent = []
|
802 |
|
803 |
|
804 | var cache = await this.returnUSXOCache()
|
805 | if (cache !== undefined && cache.length > 0) {
|
806 | for (var x = 0; x < cache.length; x++) {
|
807 | unspent.push(cache[x])
|
808 | }
|
809 | }
|
810 |
|
811 | if (app.sidechain !== '') {
|
812 | let unspentnode = await app.post('/sidechain/listunspent', { sidechain_address: app.sidechain, dapp_address: address })
|
813 | if (unspentnode.unspent !== undefined) {
|
814 | for (let x in unspentnode.unspent) {
|
815 | unspent.push(unspentnode.unspent[x])
|
816 | }
|
817 | response(unspent)
|
818 | } else {
|
819 | response(false)
|
820 | }
|
821 | } else {
|
822 | response(false)
|
823 | }
|
824 | })
|
825 | }
|
826 |
|
827 | async sendPlanumAsset(key, password, to, amount, changeaddress = '', memo = '') {
|
828 | const app = this
|
829 | let wallet = await this.returnKey(key)
|
830 | if (wallet !== false) {
|
831 | if (password !== '' && to !== '') {
|
832 | var SIDS = wallet.split(':');
|
833 | let decrypted
|
834 | try {
|
835 | decrypted = await this.decryptData(SIDS[1], password)
|
836 | decrypted = JSON.parse(decrypted)
|
837 | } catch (e) {
|
838 | return false
|
839 | }
|
840 | if(decrypted.prv !== undefined){
|
841 | const address = SIDS[0]
|
842 | var sxid = ''
|
843 | let unspent = await app.listPlanumUnspent(address)
|
844 | let check_sidechain = await app.post('/sidechain/get', { sidechain_address: app.sidechain })
|
845 | let sidechainObj = check_sidechain.sidechain[0]
|
846 | const decimals = sidechainObj.data.genesis.decimals
|
847 | if (unspent.length > 0) {
|
848 | let inputs = []
|
849 | let outputs = {}
|
850 | let amountinput = 0
|
851 | amount = app.math.round(amount, decimals)
|
852 | let usedtx = []
|
853 | let checkto = await app.get('/validate/' + to)
|
854 | if (checkto.data.isvalid === false) {
|
855 | return Promise.resolve(false)
|
856 | }
|
857 |
|
858 | for (let i in unspent) {
|
859 | if (amountinput < amount) {
|
860 | delete unspent[i]._id
|
861 | delete unspent[i].sidechain
|
862 | delete unspent[i].address
|
863 | delete unspent[i].block
|
864 | delete unspent[i].redeemblock
|
865 | delete unspent[i].redeemed
|
866 | let cache = await this.returnSXIDCache()
|
867 | if (cache.indexOf(unspent[i].sxid + ':' + unspent[i].vout) === -1) {
|
868 | inputs.push(unspent[i])
|
869 | usedtx.push(unspent[i].sxid + ':' + unspent[i].vout)
|
870 | let toadd = app.math.round(unspent[i].amount, decimals)
|
871 | amountinput = app.math.sum(amountinput, toadd)
|
872 | amountinput = app.math.round(amountinput, decimals)
|
873 | }
|
874 | }
|
875 | }
|
876 |
|
877 | let totaloutputs = 0
|
878 | amountinput = app.math.round(amountinput, decimals)
|
879 | amount = app.math.round(amount, decimals)
|
880 | if (amountinput >= amount) {
|
881 |
|
882 | if (to === sidechainObj.address && sidechainObj.data.burnable === false) {
|
883 |
|
884 | return Promise.resolve(false)
|
885 |
|
886 | } else {
|
887 |
|
888 | outputs[to] = amount
|
889 | totaloutputs = app.math.sum(totaloutputs, amount)
|
890 |
|
891 | let change = app.math.subtract(amountinput, amount)
|
892 | change = app.math.round(change, decimals)
|
893 |
|
894 | if (to !== address) {
|
895 | if (change > 0 && changeaddress === '') {
|
896 | outputs[address] = change
|
897 | totaloutputs = app.math.sum(totaloutputs, change)
|
898 | } else if (change > 0 && changeaddress !== '') {
|
899 |
|
900 | let checkchange = await app.get('validate/' + change)
|
901 | if (checkchange.data.isvalid === true) {
|
902 | outputs[changeaddress] = change
|
903 | totaloutputs = app.math.sum(totaloutputs, change)
|
904 | } else {
|
905 |
|
906 | outputs[address] = change
|
907 | totaloutputs = app.math.sum(totaloutputs, change)
|
908 | }
|
909 | }
|
910 | } else {
|
911 | if (change > 0) {
|
912 | outputs[address] = app.math.sum(change, amount)
|
913 | outputs[address] = app.math.round(outputs[address], sidechainObj.data.genesis.decimals)
|
914 | totaloutputs = app.math.sum(totaloutputs, change)
|
915 | }
|
916 | }
|
917 |
|
918 | totaloutputs = app.math.round(totaloutputs, sidechainObj.data.genesis.decimals)
|
919 |
|
920 | if (inputs.length > 0 && totaloutputs > 0) {
|
921 | let transaction = {}
|
922 | transaction["sidechain"] = app.sidechain
|
923 | transaction["inputs"] = inputs
|
924 | transaction["outputs"] = outputs
|
925 | transaction["memo"] = memo
|
926 | transaction["time"] = new Date().getTime()
|
927 |
|
928 | let signtx = await app.signMessage(decrypted.prv, JSON.stringify(transaction))
|
929 |
|
930 | let tx = {
|
931 | transaction: transaction,
|
932 | signature: signtx.signature,
|
933 | pubkey: decrypted.key,
|
934 | sxid: signtx.hash
|
935 | }
|
936 |
|
937 | let validatetransaction = await app.post('/sidechain/validate',
|
938 | {
|
939 | transaction: tx,
|
940 | address: address,
|
941 | sxid: signtx.hash,
|
942 | signature: signtx.signature,
|
943 | pubkey: decrypted.key
|
944 | }
|
945 | )
|
946 |
|
947 | if (validatetransaction.errors === undefined && validatetransaction.valid === true && signtx.hash !== undefined) {
|
948 | let sent = false
|
949 | let txs = []
|
950 | let retry = 0
|
951 | while (sent === false) {
|
952 | let written = await app.write(key, password, JSON.stringify(tx), '', '', 'chain://')
|
953 | if (written !== false && written.txs !== undefined && written.txs.length >= 1 && written.txs[0] !== null) {
|
954 | for (let x in usedtx) {
|
955 | await app.pushSXIDtoCache(usedtx[x])
|
956 | }
|
957 | let vout = 0
|
958 | for (let x in outputs) {
|
959 | let unspent = {
|
960 | sxid: tx.sxid,
|
961 | vout: vout,
|
962 | address: x,
|
963 | amount: outputs[x],
|
964 | sidechain: tx.transaction['sidechain']
|
965 | }
|
966 | if (unspent.address === address) {
|
967 | await app.pushUSXOtoCache(unspent)
|
968 | }
|
969 | vout++
|
970 | }
|
971 | sent = true
|
972 | txs = written.txs
|
973 | } else {
|
974 | retry++
|
975 | await app.sleep(2000)
|
976 | }
|
977 | if (retry > 10) {
|
978 | sent = true
|
979 | }
|
980 | }
|
981 | if (txs.length >= 1) {
|
982 | return Promise.resolve(tx.sxid)
|
983 | } else {
|
984 | return Promise.resolve(false)
|
985 | }
|
986 | } else {
|
987 | return Promise.resolve(false)
|
988 | }
|
989 |
|
990 | } else {
|
991 | return Promise.resolve(false)
|
992 | }
|
993 | }
|
994 | } else {
|
995 | return Promise.resolve(false)
|
996 | }
|
997 | } else {
|
998 |
|
999 | return false
|
1000 | }
|
1001 | }else{
|
1002 | return false
|
1003 | }
|
1004 | } else {
|
1005 | return false
|
1006 | }
|
1007 | } else {
|
1008 | return false
|
1009 | }
|
1010 | }
|
1011 |
|
1012 |
|
1013 | async write(key, password, metadata, collection = '', refID = '', protocol = '', uuid = '') {
|
1014 | if (password !== '' && metadata !== '') {
|
1015 | let wallet = await this.returnKey(key)
|
1016 | if (wallet !== false) {
|
1017 | var SIDS = wallet.split(':');
|
1018 | var MAX_OPRETURN = this.MAX_OPRETURN
|
1019 | try {
|
1020 |
|
1021 | let decrypted = await this.decryptData(SIDS[1], password)
|
1022 | if(decrypted !== false){
|
1023 | let address = SIDS[0]
|
1024 |
|
1025 | if (uuid === '') {
|
1026 | var Uuid = require('uuid/v4')
|
1027 | uuid = Uuid().replace(new RegExp('-', 'g'), '.')
|
1028 | }
|
1029 |
|
1030 | if (collection !== '') {
|
1031 | collection = '!*!' + collection
|
1032 | } else {
|
1033 | collection = '!*!'
|
1034 | }
|
1035 |
|
1036 | if (refID !== '') {
|
1037 | refID = '!*!' + refID
|
1038 | } else {
|
1039 | refID = '!*!'
|
1040 | }
|
1041 |
|
1042 | if (protocol !== '') {
|
1043 | protocol = '!*!' + protocol
|
1044 | } else {
|
1045 | protocol = '!*!'
|
1046 | }
|
1047 |
|
1048 | var dataToWrite = '*!*' + uuid + collection + refID + protocol + '*=>' + metadata + '*!*'
|
1049 | if (dataToWrite.length <= MAX_OPRETURN) {
|
1050 | var txid = ''
|
1051 | var i = 0
|
1052 | var totalfees = 0
|
1053 | var retries = 0
|
1054 | while (txid.length !== 64) {
|
1055 | var fees = 0.001 + (i / 1000)
|
1056 | var rawtransaction = await this.build(wallet, password, false, address, 0, dataToWrite, fees)
|
1057 | if(this.debug){
|
1058 | console.log(rawtransaction.signed)
|
1059 | }
|
1060 | if (rawtransaction.signed !== false) {
|
1061 | txid = await this.sendRawTransaction(rawtransaction.signed)
|
1062 | if(this.debug){
|
1063 | console.log(txid)
|
1064 | }
|
1065 | if (txid !== undefined && txid !== null && txid.length === 64) {
|
1066 | totalfees += fees
|
1067 | for (let i in rawtransaction.inputs) {
|
1068 | await this.pushTXIDtoCache(rawtransaction.inputs[i])
|
1069 | }
|
1070 |
|
1071 | var decoded = await this.decodeRawTransaction(rawtransaction.signed)
|
1072 | if (decoded.vout[0].scriptPubKey.addresses !== undefined) {
|
1073 | let unspent = {
|
1074 | txid: decoded.txid,
|
1075 | vout: 0,
|
1076 | address: decoded.vout[0].scriptPubKey.addresses[0],
|
1077 | scriptPubKey: decoded.vout[0].scriptPubKey.hex,
|
1078 | amount: decoded.vout[0].value
|
1079 | }
|
1080 | await this.pushUTXOtoCache(unspent)
|
1081 | }
|
1082 | }else{
|
1083 | txid = ''
|
1084 | }
|
1085 | }
|
1086 | i++;
|
1087 | retries ++;
|
1088 | if(retries > 9){
|
1089 | txid = '0000000000000000000000000000000000000000000000000000000000000000'
|
1090 | }
|
1091 | }
|
1092 |
|
1093 | if(txid !== '0000000000000000000000000000000000000000000000000000000000000000'){
|
1094 | return Promise.resolve({
|
1095 | uuid: uuid,
|
1096 | address: wallet,
|
1097 | fees: totalfees,
|
1098 | collection: collection.replace('!*!', ''),
|
1099 | refID: refID.replace('!*!', ''),
|
1100 | protocol: protocol.replace('!*!', ''),
|
1101 | dimension: dataToWrite.length,
|
1102 | chunks: 1,
|
1103 | stored: dataToWrite,
|
1104 | txs: [txid]
|
1105 | })
|
1106 | }else{
|
1107 | return Promise.resolve(false)
|
1108 | }
|
1109 |
|
1110 | } else {
|
1111 |
|
1112 | var txs = []
|
1113 | var chunklength = MAX_OPRETURN - 6
|
1114 | var chunkdatalimit = chunklength - 3
|
1115 | var dataToWriteLength = dataToWrite.length
|
1116 | var nchunks = Math.ceil(dataToWriteLength / chunklength)
|
1117 | var last = nchunks - 1
|
1118 | var chunks = []
|
1119 |
|
1120 | for (var i = 0; i < nchunks; i++) {
|
1121 | var start = i * chunklength
|
1122 | var end = start + chunklength
|
1123 | var chunk = dataToWrite.substring(start, end)
|
1124 |
|
1125 | if (i === 0) {
|
1126 | var startnext = (i + 1) * chunklength
|
1127 | var endnext = startnext + chunklength
|
1128 | var prevref = ''
|
1129 | var nextref = dataToWrite.substring(startnext, endnext).substring(0, 3)
|
1130 | } else if (i === last) {
|
1131 | var startprev = (i - 1) * chunklength
|
1132 | var endprev = startprev + chunklength
|
1133 | var nextref = ''
|
1134 | var prevref = dataToWrite.substr(startprev, endprev).substr(chunkdatalimit, 3)
|
1135 | } else {
|
1136 | var sni = i + 1
|
1137 | var startnext = sni * chunklength
|
1138 | var endnext = startnext + chunklength
|
1139 | var nextref = dataToWrite.substring(startnext, endnext).substring(0, 3)
|
1140 | var spi = i - 1
|
1141 | var startprev = spi * chunklength
|
1142 | var endprev = startprev + chunklength
|
1143 | var prevref = dataToWrite.substr(startprev, endprev).substr(chunkdatalimit, 3)
|
1144 | }
|
1145 | chunk = prevref + chunk + nextref
|
1146 | chunks.push(chunk)
|
1147 | }
|
1148 |
|
1149 | var totalfees = 0
|
1150 |
|
1151 | for (var cix = 0; cix < chunks.length; cix++) {
|
1152 | var txid = ''
|
1153 | var i = 0
|
1154 | var rawtransaction
|
1155 | while (txid !== null && txid !== undefined && txid.length !== 64) {
|
1156 | var fees = 0.001 + (i / 1000)
|
1157 |
|
1158 | rawtransaction = await this.build(wallet, password, false, address, 0, chunks[cix], fees)
|
1159 | txid = await this.sendRawTransaction(rawtransaction.signed)
|
1160 |
|
1161 | if (txid !== null && txid !== false && txid.length === 64) {
|
1162 | for (let i in rawtransaction.inputs) {
|
1163 | await this.pushTXIDtoCache(rawtransaction.inputs[i])
|
1164 | }
|
1165 | totalfees += fees
|
1166 | txs.push(txid)
|
1167 |
|
1168 | var decoded = await this.decodeRawTransaction(rawtransaction.signed)
|
1169 | if (decoded.vout[0].scriptPubKey.addresses !== undefined) {
|
1170 | let unspent = {
|
1171 | txid: decoded.txid,
|
1172 | vout: 0,
|
1173 | address: decoded.vout[0].scriptPubKey.addresses[0],
|
1174 | scriptPubKey: decoded.vout[0].scriptPubKey.hex,
|
1175 | amount: decoded.vout[0].value
|
1176 | }
|
1177 | await this.pushUTXOtoCache(unspent)
|
1178 | }
|
1179 | } else {
|
1180 | txid = null
|
1181 | }
|
1182 | i++;
|
1183 | }
|
1184 | }
|
1185 |
|
1186 | return Promise.resolve({
|
1187 | uuid: uuid,
|
1188 | address: wallet,
|
1189 | fees: totalfees,
|
1190 | collection: collection.replace('!*!', ''),
|
1191 | refID: refID.replace('!*!', ''),
|
1192 | protocol: protocol.replace('!*!', ''),
|
1193 | dimension: dataToWrite.length,
|
1194 | chunks: nchunks,
|
1195 | stored: dataToWrite,
|
1196 | txs: txs
|
1197 | })
|
1198 |
|
1199 | }
|
1200 | }else{
|
1201 | return Promise.resolve(false);
|
1202 | }
|
1203 | } catch (error) {
|
1204 | console.log(error)
|
1205 | return Promise.resolve(false);
|
1206 | }
|
1207 | } else {
|
1208 | return false
|
1209 | }
|
1210 | }
|
1211 | }
|
1212 |
|
1213 | async update(key, password, metadata, collection = '', refID = '', protocol = '', uuid) {
|
1214 | return new Promise(response => {
|
1215 | if (uuid !== undefined) {
|
1216 | let written = this.write(key, password, metadata, collection, refID, protocol, uuid)
|
1217 | response(written)
|
1218 | } else {
|
1219 | response(false)
|
1220 | }
|
1221 | })
|
1222 | }
|
1223 |
|
1224 | async invalidate(key, password, uuid) {
|
1225 | return new Promise(response => {
|
1226 | if (uuid !== undefined) {
|
1227 | let metadata = 'END'
|
1228 | let written = this.write(key, password, metadata, '', '', '', uuid)
|
1229 | response(written)
|
1230 | } else {
|
1231 | response(false)
|
1232 | }
|
1233 | })
|
1234 | }
|
1235 |
|
1236 |
|
1237 | async signMessage(key, message) {
|
1238 | return new Promise(response => {
|
1239 |
|
1240 | let params = lyraInfo.mainnet
|
1241 | if (this.testnet === true) {
|
1242 | params = lyraInfo.testnet
|
1243 | }
|
1244 | var ck = CoinKey.fromWif(key, params);
|
1245 |
|
1246 | let hash = CryptoJS.SHA256(message);
|
1247 | let msg = Buffer.from(hash.toString(CryptoJS.enc.Hex), 'hex');
|
1248 |
|
1249 | let privKey = ck.privateKey
|
1250 |
|
1251 | const sigObj = secp256k1.sign(msg, privKey)
|
1252 | const pubKey = secp256k1.publicKeyCreate(privKey)
|
1253 |
|
1254 | response({
|
1255 | message: message,
|
1256 | hash: hash.toString(CryptoJS.enc.Hex),
|
1257 | signature: sigObj.signature.toString('hex'),
|
1258 | pubkey: pubKey.toString('hex'),
|
1259 | address: ck.publicAddress
|
1260 | })
|
1261 | })
|
1262 | }
|
1263 |
|
1264 | async verifyMessage(pubkey, signature, message) {
|
1265 | return new Promise(async response => {
|
1266 |
|
1267 | let hash = CryptoJS.SHA256(message);
|
1268 | let msg = Buffer.from(hash.toString(CryptoJS.enc.Hex), 'hex')
|
1269 |
|
1270 | let buf = Buffer.from(signature, 'hex')
|
1271 | let pubKey = Buffer.from(pubkey, 'hex')
|
1272 | let verified = secp256k1.verify(msg, buf, pubKey)
|
1273 | let address = await this.getAddressFromPubKey(pubkey)
|
1274 | if (verified === true) {
|
1275 | response({
|
1276 | address: address,
|
1277 | pubkey: pubkey,
|
1278 | signature: signature,
|
1279 | hash: hash.toString(CryptoJS.enc.Hex),
|
1280 | message: message,
|
1281 | })
|
1282 | } else {
|
1283 | response(false)
|
1284 | }
|
1285 | })
|
1286 | }
|
1287 |
|
1288 |
|
1289 |
|
1290 | async connectP2P(callback) {
|
1291 | const app = this
|
1292 | let nodes = await this.returnNodes()
|
1293 | const db = new ScryptaDB(app.isBrowser)
|
1294 |
|
1295 | for (let x in nodes) {
|
1296 | let node = nodes[x]
|
1297 | let check = await app.checkNode(node)
|
1298 | if (check !== false) {
|
1299 | let ready = await app.get('/wallet/getinfo', node)
|
1300 | if(ready.blocks !== undefined){
|
1301 | try{
|
1302 | console.log('Bootstrap connection to ' + node.replace('https://', 'https://p2p.'))
|
1303 | global['nodes'][node] = require('socket.io-client')(node.replace('https://', 'https://p2p.'), { reconnect: true })
|
1304 | global['nodes'][node].on('connect', function () {
|
1305 | console.log('Connected to peer: ' + global['nodes'][node].io.uri)
|
1306 | global['connected'][node] = true
|
1307 | })
|
1308 | global['nodes'][node].on('disconnect', function () {
|
1309 |
|
1310 | global['connected'][node] = false
|
1311 | })
|
1312 |
|
1313 |
|
1314 | global['nodes'][node].on('message', async function (data) {
|
1315 | if(data.pubkey === undefined && data.pubKey !== undefined){
|
1316 | data.pubkey = data.pubKey
|
1317 | }
|
1318 | let verified = await app.verifyMessage(data.pubkey, data.signature, data.message)
|
1319 | if (verified !== false && global['cache'].indexOf(data.signature) === -1) {
|
1320 | global['cache'].push(data.signature)
|
1321 | let check = await db.get('messages', 'signature', data.signature)
|
1322 | if (!check) {
|
1323 | await db.put('messages', {
|
1324 | signature: data.signature,
|
1325 | message: data.message,
|
1326 | pubkey: data.pubKey,
|
1327 | address: data.address
|
1328 | }).catch(err => {
|
1329 |
|
1330 | }).then(success => {
|
1331 | callback(data)
|
1332 | })
|
1333 | }
|
1334 | }
|
1335 | })
|
1336 | }catch(e){
|
1337 | console.log("CAN'T CONNECT TO " + node)
|
1338 | }
|
1339 | }
|
1340 | }
|
1341 | }
|
1342 | }
|
1343 |
|
1344 | async broadcast(key, password, protocol, message, socketID = '', nodeID = '') {
|
1345 | const app = this
|
1346 | key = await this.returnKey(key)
|
1347 | let wallet = await this.readKey(password, key)
|
1348 | if (wallet !== false) {
|
1349 | let signed = await app.signMessage(wallet.prv, message)
|
1350 |
|
1351 | return new Promise(async response => {
|
1352 | if (nodeID === '') {
|
1353 | for (let id in global['nodes']) {
|
1354 | global['nodes'][id].emit(protocol, signed)
|
1355 | }
|
1356 | } else {
|
1357 | if (global['nodes'][nodeID]) {
|
1358 | global['nodes'][nodeID].emit(protocol, signed)
|
1359 | }
|
1360 | }
|
1361 | response(message)
|
1362 | })
|
1363 | }
|
1364 | }
|
1365 |
|
1366 |
|
1367 | returnIdentities() {
|
1368 | const app = this
|
1369 | return new Promise(response => {
|
1370 | const db = new ScryptaDB(app.isBrowser)
|
1371 | let wallet = db.get('wallet')
|
1372 | response(wallet)
|
1373 | })
|
1374 | }
|
1375 |
|
1376 | returnIdentity(address) {
|
1377 | const app = this
|
1378 | return new Promise(response => {
|
1379 | const db = new ScryptaDB(app.isBrowser)
|
1380 | let wallet = db.get('wallet', 'address', address)
|
1381 | if (wallet !== false) {
|
1382 | response(wallet)
|
1383 | } else {
|
1384 | response(false)
|
1385 | }
|
1386 | })
|
1387 | }
|
1388 |
|
1389 | createRSAKeys(address, password) {
|
1390 | const app = this
|
1391 | return new Promise(async response => {
|
1392 | let wallet = await app.returnKey(address)
|
1393 | const db = new ScryptaDB(app.isBrowser)
|
1394 | let SIDS = wallet.split(':')
|
1395 | let stored = await db.get('wallet', 'address', SIDS[0])
|
1396 | if (stored.rsa === undefined) {
|
1397 | let key = await app.readKey(password, wallet)
|
1398 | if (key !== false) {
|
1399 | const key = new NodeRSA({ b: 2048 });
|
1400 | let pub = key.exportKey('pkcs8-public-pem');
|
1401 | let prv = key.exportKey('pkcs8-pem');
|
1402 |
|
1403 | let prvhex = await this.cryptData(prv, password)
|
1404 | let checkdecryption = await this.decryptData(prvhex, password)
|
1405 | if (checkdecryption === prv) {
|
1406 | stored.rsa = {
|
1407 | pub: pub,
|
1408 | prv: prvhex
|
1409 | }
|
1410 | await db.update('wallet', 'address', stored.address, stored)
|
1411 | response(true)
|
1412 | } else {
|
1413 | response(false)
|
1414 | }
|
1415 | } else {
|
1416 | response(false)
|
1417 | }
|
1418 | } else {
|
1419 | response(wallet.rsa)
|
1420 | }
|
1421 | })
|
1422 | }
|
1423 |
|
1424 | setDefaultIdentity(address) {
|
1425 | const app = this
|
1426 | return new Promise(async response => {
|
1427 | const db = new ScryptaDB(app.isBrowser)
|
1428 | let wallet = await db.get('wallet', 'address', address)
|
1429 | if (wallet !== false && wallet !== null) {
|
1430 | if (app.isBrowser) {
|
1431 |
|
1432 | localStorage.setItem('SID', wallet.wallet)
|
1433 | response(true)
|
1434 | } else {
|
1435 | await db.destroy('identity')
|
1436 | await db.put('identity', wallet)
|
1437 | response(true)
|
1438 | }
|
1439 | } else {
|
1440 | response(false)
|
1441 | }
|
1442 | })
|
1443 | }
|
1444 |
|
1445 | returnDefaultIdentity() {
|
1446 | const app = this
|
1447 | return new Promise(async response => {
|
1448 | const db = new ScryptaDB(app.isBrowser)
|
1449 | if (app.isBrowser) {
|
1450 | if (localStorage.getItem('SID') !== null) {
|
1451 | response(localStorage.getItem('SID'))
|
1452 | } else {
|
1453 | let wallet = await db.get('wallet')
|
1454 | if (wallet !== false && wallet[0] !== undefined) {
|
1455 | localStorage.setItem('SID', wallet[0].wallet)
|
1456 | response(wallet)
|
1457 | } else {
|
1458 | response(false)
|
1459 | }
|
1460 | }
|
1461 | } else {
|
1462 | let wallet = await db.get('identity')
|
1463 | if (wallet !== false && wallet[0] !== undefined) {
|
1464 | response(wallet[0])
|
1465 | } else {
|
1466 | response(false)
|
1467 | }
|
1468 | }
|
1469 | })
|
1470 | }
|
1471 |
|
1472 | fetchIdentities(address) {
|
1473 | return new Promise(async response => {
|
1474 | const app = this
|
1475 | if (wallet !== false) {
|
1476 | let identities = app.post('/read', { dapp_address: address, protocol: 'I://' }).catch(err => {
|
1477 | response(err)
|
1478 | })
|
1479 | response(identities.data)
|
1480 | } else {
|
1481 | response(false)
|
1482 | }
|
1483 | })
|
1484 | }
|
1485 |
|
1486 | shuffle(array) {
|
1487 | var currentIndex = array.length, temporaryValue, randomIndex;
|
1488 |
|
1489 | while (0 !== currentIndex) {
|
1490 |
|
1491 | randomIndex = Math.floor(Math.random() * currentIndex);
|
1492 | currentIndex -= 1;
|
1493 |
|
1494 | temporaryValue = array[currentIndex];
|
1495 | array[currentIndex] = array[randomIndex];
|
1496 | array[randomIndex] = temporaryValue;
|
1497 | }
|
1498 |
|
1499 | return array;
|
1500 | }
|
1501 | }
|