From ed1c5eae82355688f262f597f5c14b56d6ab2350 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Wed, 5 May 2021 10:40:35 +0300 Subject: [PATCH 01/57] Remove package-lock --- .gitignore | 1 - package-lock.json | 1919 --------------------------------------------- package.json | 2 +- 3 files changed, 1 insertion(+), 1921 deletions(-) delete mode 100644 package-lock.json diff --git a/.gitignore b/.gitignore index c760344..f081cae 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ logs/ .vscode/ test.js package-lock.json - diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index ae77a2f..0000000 --- a/package-lock.json +++ /dev/null @@ -1,1919 +0,0 @@ -{ - "name": "adamant-api", - "version": "0.1.18", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/runtime": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", - "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", - "requires": { - "regenerator-runtime": "^0.13.2" - } - }, - "@types/bn.js": { - "version": "4.11.5", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.5.tgz", - "integrity": "sha512-AEAZcIZga0JgVMHNtl1CprA/hXX7/wPt79AgR4XqaDt7jyj3QWYw6LPoOiznPtugDmlubUnAahMs2PFxGcQrng==", - "requires": { - "@types/node": "*" - } - }, - "@types/concat-stream": { - "version": "1.6.0", - "resolved": "http://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.0.tgz", - "integrity": "sha1-OU2+C7X+5Gs42JZzXoto7yOQ0A0=", - "requires": { - "@types/node": "*" - } - }, - "@types/form-data": { - "version": "0.0.33", - "resolved": "http://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", - "integrity": "sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=", - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "9.6.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.39.tgz", - "integrity": "sha512-c3OkjgNpSMdHan56WhklP0FMOk5ocilKz2Mpa0NOGzu8jw5YERjCf9FG0epYB1+TxScv/oI4uJ204u2mUg7Hcw==" - }, - "@types/qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-mNhVdZHdtKHMMxbqzNK3RzkBcN1cux3AvuCYGTvjEIQT2uheH3eCAyYsbMbh2Bq8nXkeOWs1kyDiF7geWRFQ4Q==" - }, - "aes-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=" - }, - "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" - }, - "base-x": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.5.tgz", - "integrity": "sha512-C3picSgzPSLE+jW3tcBzJoGwitOtazb5B+5YmAxZm2ybmTi9LNgAtDO/jjVEBZwHoXmDBZ9m/IELj3elJVRBcA==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bignumber.js": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-8.0.1.tgz", - "integrity": "sha512-zAySveTJXkgLYCBi0b14xzfnOs+f3G6x36I8w2a1+PFQpWk/dp0mI0F+ZZK2bu+3ELewDcSyP+Cfq++NcHX7sg==" - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "bip66": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", - "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "bitcore-lib": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/bitcore-lib/-/bitcore-lib-0.15.0.tgz", - "integrity": "sha512-AeXLWhiivF6CDFzrABZHT4jJrflyylDWTi32o30rF92HW9msfuKpjzrHtFKYGa9w0kNVv5HABQjCB3OEav4PhQ==", - "requires": { - "bn.js": "=4.11.8", - "bs58": "=4.0.1", - "buffer-compare": "=1.1.1", - "elliptic": "=6.4.0", - "inherits": "=2.0.1", - "lodash": "=4.17.4" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" - } - } - }, - "bitcore-mnemonic": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bitcore-mnemonic/-/bitcore-mnemonic-1.5.0.tgz", - "integrity": "sha512-sbeP4xwkindLMfIQhVxj6rZSDMwtiKmfc1DqvwpR6Yg+Qo4I4WHO5pvzb12Y04uDh1N3zgD45esHhfH0HHmE4g==", - "requires": { - "bitcore-lib": "^0.15.0", - "unorm": "^1.3.3" - } - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", - "requires": { - "base-x": "^3.0.2" - } - }, - "buffer-compare": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-compare/-/buffer-compare-1.1.1.tgz", - "integrity": "sha1-W+e+hTr4kZjR9N3AkNHWakiu9ZY=" - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, - "buffer-to-arraybuffer": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", - "integrity": "sha1-YGSkD6dutDxyOrqe+PbhIW0QURo=" - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" - }, - "bytebuffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", - "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", - "requires": { - "long": "~3" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "chloride-test": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/chloride-test/-/chloride-test-1.2.2.tgz", - "integrity": "sha1-F4aGqF6SeARREulujHkXk/mhCuo=", - "requires": { - "json-buffer": "^2.0.11" - } - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "coinstring": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/coinstring/-/coinstring-2.3.0.tgz", - "integrity": "sha1-zbYzY6lhUCQEolr7gsLibV/2J6Q=", - "requires": { - "bs58": "^2.0.1", - "create-hash": "^1.1.1" - }, - "dependencies": { - "bs58": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-2.0.1.tgz", - "integrity": "sha1-VZCNWPGYKrogCPob7Y+RmYopv40=" - } - } - }, - "combined-stream": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", - "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "crypto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", - "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "dom-walk": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", - "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" - }, - "drbg.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", - "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", - "requires": { - "browserify-aes": "^1.0.6", - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4" - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ed2curve": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ed2curve/-/ed2curve-0.2.1.tgz", - "integrity": "sha1-Iuaqo1aePE2/Tu+ilhLsMp5YGQw=", - "requires": { - "tweetnacl": "0.x.x" - } - }, - "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - }, - "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-keys": "^1.0.12" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "eth-ens-namehash": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", - "integrity": "sha1-IprEbsqG1S4MmR58sq74P/D2i88=", - "requires": { - "idna-uts46-hx": "^2.3.1", - "js-sha3": "^0.5.7" - } - }, - "eth-lib": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", - "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - }, - "ethereum-common": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.0.18.tgz", - "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=" - }, - "ethereumjs-tx": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz", - "integrity": "sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA==", - "requires": { - "ethereum-common": "^0.0.18", - "ethereumjs-util": "^5.0.0" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } - } - }, - "ethereumjs-util": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", - "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "0.1.6", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "ethers": { - "version": "4.0.28", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.28.tgz", - "integrity": "sha512-5JTHrPoFLqf+xCAI3pKwXSOgWBSJJoAUdPtPLr1ZlKbSKiIFMkPlRNovmZS3jhIw5sHW1YoVWOaJ6ZR2gKRbwg==", - "requires": { - "@types/node": "^10.3.2", - "aes-js": "3.0.0", - "bn.js": "^4.4.0", - "elliptic": "6.3.3", - "hash.js": "1.1.3", - "js-sha3": "0.5.7", - "scrypt-js": "2.0.4", - "setimmediate": "1.0.4", - "uuid": "2.0.1", - "xmlhttprequest": "1.8.0" - }, - "dependencies": { - "@types/node": { - "version": "10.14.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.8.tgz", - "integrity": "sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw==" - }, - "elliptic": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", - "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "inherits": "^2.0.1" - } - }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "uuid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", - "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" - } - } - }, - "ethjs-unit": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", - "integrity": "sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk=", - "requires": { - "bn.js": "4.11.6", - "number-to-bn": "1.7.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" - } - } - }, - "ethjs-util": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", - "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", - "requires": { - "is-hex-prefixed": "1.0.0", - "strip-hex-prefix": "1.0.0" - } - }, - "eventemitter3": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", - "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "requires": { - "is-callable": "^1.1.3" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "get-port": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", - "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "global": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", - "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", - "requires": { - "min-document": "^2.19.0", - "process": "~0.5.1" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" - }, - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "hash.js": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz", - "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hdkey": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/hdkey/-/hdkey-1.1.1.tgz", - "integrity": "sha512-DvHZ5OuavsfWs5yfVJZestsnc3wzPvLWNk6c2nRUfo6X+OtxypGt20vDDf7Ba+MJzjL3KS1og2nw2eBbLCOUTA==", - "requires": { - "coinstring": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "http-basic": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-7.0.0.tgz", - "integrity": "sha1-gvClBr6UJzLsje6+6A50bvVzbbo=", - "requires": { - "@types/concat-stream": "^1.6.0", - "@types/node": "^9.4.1", - "caseless": "~0.12.0", - "concat-stream": "^1.4.6", - "http-response-object": "^3.0.1", - "parse-cache-control": "^1.0.1" - } - }, - "http-response-object": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.1.tgz", - "integrity": "sha512-6L0Fkd6TozA8kFSfh9Widst0wfza3U1Ex2RjJ6zNDK0vR1U1auUR6jY4Nn2Xl7CCy0ikFmxW1XcspVpb9RvwTg==", - "requires": { - "@types/node": "^9.3.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "idna-uts46-hx": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", - "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", - "requires": { - "punycode": "2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", - "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=" - } - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" - }, - "is-function": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz", - "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=" - }, - "is-hex-prefixed": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", - "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=" - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "requires": { - "has": "^1.0.1" - } - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "requires": { - "has-symbols": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "js-sha3": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "json-buffer": { - "version": "2.0.11", - "resolved": "http://registry.npmjs.org/json-buffer/-/json-buffer-2.0.11.tgz", - "integrity": "sha1-PkQf2jCYvo0eMXGtWRvGKjPi1V8=" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "keccak": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-1.4.0.tgz", - "integrity": "sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw==", - "requires": { - "bindings": "^1.2.1", - "inherits": "^2.0.3", - "nan": "^2.2.1", - "safe-buffer": "^5.1.0" - } - }, - "lodash": { - "version": "4.17.4", - "resolved": "http://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" - }, - "long": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", - "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" - }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "mime-db": { - "version": "1.37.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", - "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" - }, - "mime-types": { - "version": "2.1.21", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", - "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", - "requires": { - "mime-db": "~1.37.0" - } - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" - }, - "min-document": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "requires": { - "dom-walk": "^0.1.0" - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" - }, - "number-to-bn": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", - "integrity": "sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA=", - "requires": { - "bn.js": "4.11.6", - "strip-hex-prefix": "1.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" - } - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "parse-cache-control": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", - "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104=" - }, - "parse-headers": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.2.tgz", - "integrity": "sha512-/LypJhzFmyBIDYP9aDVgeyEb5sQfbfY5mnDq4hVhlQ69js87wXfmEI5V3xI6vvXasqebp0oCytYFLxsBVfCzSg==", - "requires": { - "for-each": "^0.3.3", - "string.prototype.trim": "^1.1.2" - } - }, - "pbkdf2": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", - "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "process": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", - "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, - "promise": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.2.tgz", - "integrity": "sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw==", - "requires": { - "asap": "~2.0.6" - } - }, - "psl": { - "version": "1.1.32", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz", - "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==" - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "query-string": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", - "requires": { - "decode-uri-component": "^0.2.0", - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, - "querystringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", - "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "regenerator-runtime": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", - "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==" - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "rlp": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.3.tgz", - "integrity": "sha512-l6YVrI7+d2vpW6D6rS05x2Xrmq8oW7v3pieZOJKBEdjuTF4Kz/iwk55Zyh1Zaz+KOB2kC8+2jZlp2u9L4tTzCQ==", - "requires": { - "bn.js": "^4.11.1", - "safe-buffer": "^5.1.1" - } - }, - "rxjs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", - "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "scrypt": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/scrypt/-/scrypt-6.0.3.tgz", - "integrity": "sha1-BOAUpWgrU/pQwtXM4WfXGcBthw0=", - "optional": true, - "requires": { - "nan": "^2.0.8" - } - }, - "scrypt-js": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", - "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==" - }, - "scrypt.js": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/scrypt.js/-/scrypt.js-0.3.0.tgz", - "integrity": "sha512-42LTc1nyFsyv/o0gcHtDztrn+aqpkaCNt5Qh7ATBZfhEZU7IC/0oT/qbBH+uRNoAPvs2fwiOId68FDEoSRA8/A==", - "requires": { - "scrypt": "^6.0.2", - "scryptsy": "^1.2.1" - } - }, - "scryptsy": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-1.2.1.tgz", - "integrity": "sha1-oyJfpLJST4AnAHYeKFW987LZIWM=", - "requires": { - "pbkdf2": "^3.0.3" - } - }, - "secp256k1": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.7.1.tgz", - "integrity": "sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g==", - "requires": { - "bindings": "^1.5.0", - "bip66": "^1.1.5", - "bn.js": "^4.11.8", - "create-hash": "^1.2.0", - "drbg.js": "^1.0.1", - "elliptic": "^6.4.1", - "nan": "^2.14.0", - "safe-buffer": "^5.1.2" - }, - "dependencies": { - "elliptic": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", - "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - } - } - }, - "setimmediate": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", - "integrity": "sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48=" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "simple-concat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", - "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" - }, - "simple-get": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", - "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", - "requires": { - "decompress-response": "^3.3.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "sodium-browserify-tweetnacl": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/sodium-browserify-tweetnacl/-/sodium-browserify-tweetnacl-0.2.3.tgz", - "integrity": "sha1-tVN//LufdOvEQ7i2ohGykej8vI4=", - "requires": { - "chloride-test": "^1.1.0", - "ed2curve": "^0.1.4", - "sha.js": "^2.4.8", - "tweetnacl": "^0.14.1", - "tweetnacl-auth": "^0.3.0" - }, - "dependencies": { - "ed2curve": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/ed2curve/-/ed2curve-0.1.4.tgz", - "integrity": "sha1-lKRCSLuH2jXbDv968KpXYWgRf1k=", - "requires": { - "tweetnacl": "0.x.x" - } - } - } - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" - }, - "string.prototype.trim": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", - "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.0", - "function-bind": "^1.0.2" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-hex-prefix": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", - "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", - "requires": { - "is-hex-prefixed": "1.0.0" - } - }, - "sync-request": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.0.0.tgz", - "integrity": "sha512-jGNIAlCi9iU4X3Dm4oQnNQshDD3h0/1A7r79LyqjbjUnj69sX6mShAXlhRXgImsfVKtTcnra1jfzabdZvp+Lmw==", - "requires": { - "http-response-object": "^3.0.1", - "sync-rpc": "^1.2.1", - "then-request": "^6.0.0" - } - }, - "sync-rpc": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.4.tgz", - "integrity": "sha512-Iug+t1ICVFenUcTnDu8WXFnT+k8IVoLKGh8VA3eXUtl2Rt9SjKX3YEv33OenABqpTPL9QEaHv1+CNn2LK8vMow==", - "requires": { - "get-port": "^3.1.0" - } - }, - "then-request": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.0.tgz", - "integrity": "sha512-xA+7uEMc+jsQIoyySJ93Ad08Kuqnik7u6jLS5hR91Z3smAoCfL3M8/MqMlobAa9gzBfO9pA88A/AntfepkkMJQ==", - "requires": { - "@types/concat-stream": "^1.6.0", - "@types/form-data": "0.0.33", - "@types/node": "^8.0.0", - "@types/qs": "^6.2.31", - "caseless": "~0.12.0", - "concat-stream": "^1.6.0", - "form-data": "^2.2.0", - "http-basic": "^7.0.0", - "http-response-object": "^3.0.1", - "promise": "^8.0.0", - "qs": "^6.4.0" - }, - "dependencies": { - "@types/node": { - "version": "8.10.38", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.38.tgz", - "integrity": "sha512-EibsnbJerd0hBFaDjJStFrVbVBAtOy4dgL8zZFw0uOvPqzBAX59Ci8cgjg3+RgJIWhsB5A4c+pi+D4P9tQQh/A==" - } - } - }, - "timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - } - } - }, - "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "tweetnacl-auth": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/tweetnacl-auth/-/tweetnacl-auth-0.3.1.tgz", - "integrity": "sha1-t1vC3xVkm7hOi5qjwGacbEvODSU=", - "requires": { - "tweetnacl": "0.x.x" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "unorm": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.4.1.tgz", - "integrity": "sha1-NkIA1fE2RsqLzURJAnEzVhR5IwA=" - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { - "punycode": "^2.1.0" - } - }, - "url-parse": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", - "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", - "requires": { - "querystringify": "^2.0.0", - "requires-port": "^1.0.0" - } - }, - "url-set-query": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", - "integrity": "sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk=" - }, - "utf8": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.1.tgz", - "integrity": "sha1-LgHbAvfY0JRPdxBPFgnrDDBM92g=" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "web3": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.0.0-beta.55.tgz", - "integrity": "sha512-yJpwy4IUA3T/F9hWzYQVn0GbJCrAaZ0KTIO3iuqkhaYH0Y09KV7k4GzFi4hN7hT4cFTj4yIKaeVCwQ5kzvi2Vg==", - "requires": { - "@babel/runtime": "^7.3.1", - "@types/node": "^10.12.18", - "web3-core": "1.0.0-beta.55", - "web3-eth": "1.0.0-beta.55", - "web3-eth-personal": "1.0.0-beta.55", - "web3-net": "1.0.0-beta.55", - "web3-providers": "1.0.0-beta.55", - "web3-shh": "1.0.0-beta.55", - "web3-utils": "1.0.0-beta.55" - }, - "dependencies": { - "@types/node": { - "version": "10.14.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.8.tgz", - "integrity": "sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw==" - } - } - }, - "web3-core": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.0.0-beta.55.tgz", - "integrity": "sha512-AMMp7TLEtE7u8IJAu/THrRhBTZyZzeo7Y6GiWYNwb5+KStC9hIGLr9cI1KX9R6ZioTOLRHrqT7awDhnJ1ku2mg==", - "requires": { - "@babel/runtime": "^7.3.1", - "@types/bn.js": "^4.11.4", - "@types/node": "^10.12.18", - "lodash": "^4.17.11", - "web3-core-method": "1.0.0-beta.55", - "web3-providers": "1.0.0-beta.55", - "web3-utils": "1.0.0-beta.55" - }, - "dependencies": { - "@types/node": { - "version": "10.14.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.8.tgz", - "integrity": "sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw==" - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } - } - }, - "web3-core-helpers": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.55.tgz", - "integrity": "sha512-suj9Xy/lIqajaYLJTEjr2rlFgu6hGYwChHmf8+qNrC2luZA6kirTamtB9VThWMxbywx7p0bqQFjW6zXogAgWhg==", - "requires": { - "@babel/runtime": "^7.3.1", - "lodash": "^4.17.11", - "web3-core": "1.0.0-beta.55", - "web3-eth-iban": "1.0.0-beta.55", - "web3-utils": "1.0.0-beta.55" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } - } - }, - "web3-core-method": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.0.0-beta.55.tgz", - "integrity": "sha512-w1cW/s2ji9qGELHk2uMJCn1ooay0JJLVoPD1nvmsW6OTRWcVjxa62nJrFQhe6P5lEb83Xk9oHgmCxZoVUHibOw==", - "requires": { - "@babel/runtime": "^7.3.1", - "eventemitter3": "3.1.0", - "lodash": "^4.17.11", - "rxjs": "^6.4.0", - "web3-core": "1.0.0-beta.55", - "web3-core-helpers": "1.0.0-beta.55", - "web3-core-subscriptions": "1.0.0-beta.55", - "web3-utils": "1.0.0-beta.55" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } - } - }, - "web3-core-subscriptions": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.55.tgz", - "integrity": "sha512-pb3oQbUzK7IoyXwag8TYInQddg0rr7BHxKc+Pbs/92hVNQ5ps4iGMVJKezdrjlQ1IJEEUiDIglXl4LZ1hIuMkw==", - "requires": { - "@babel/runtime": "^7.3.1", - "eventemitter3": "^3.1.0", - "lodash": "^4.17.11" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } - } - }, - "web3-eth": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.0.0-beta.55.tgz", - "integrity": "sha512-F3zJ9I1gOgQdNGfi2Dy2lmj6OqCMJoRN01XHhQZagq0HY1JYMfObtfMi5E3L+qsegsSddHbqp4YY57tKx6uxpA==", - "requires": { - "@babel/runtime": "^7.3.1", - "ethereumjs-tx": "^1.3.7", - "rxjs": "^6.4.0", - "web3-core": "1.0.0-beta.55", - "web3-core-helpers": "1.0.0-beta.55", - "web3-core-method": "1.0.0-beta.55", - "web3-core-subscriptions": "1.0.0-beta.55", - "web3-eth-abi": "1.0.0-beta.55", - "web3-eth-accounts": "1.0.0-beta.55", - "web3-eth-contract": "1.0.0-beta.55", - "web3-eth-ens": "1.0.0-beta.55", - "web3-eth-iban": "1.0.0-beta.55", - "web3-eth-personal": "1.0.0-beta.55", - "web3-net": "1.0.0-beta.55", - "web3-providers": "1.0.0-beta.55", - "web3-utils": "1.0.0-beta.55" - } - }, - "web3-eth-abi": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.55.tgz", - "integrity": "sha512-3h1xnm/vYmKUXTOYAOP0OsB5uijQV76pNNRGKOB6Dq6GR1pbcbD3WrB/4I643YA8l91t5FRzFzUiA3S77R2iqw==", - "requires": { - "@babel/runtime": "^7.3.1", - "ethers": "^4.0.27", - "lodash": "^4.17.11", - "web3-utils": "1.0.0-beta.55" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } - } - }, - "web3-eth-accounts": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.55.tgz", - "integrity": "sha512-VfzvwpSDHXqRVelIxsBVhgbV9BkFvhJ/q+bKhnVUUXV0JAhMK/7uC92TsqKk4EBYuqpHyZ1jjqrL4n03fMU7zw==", - "requires": { - "@babel/runtime": "^7.3.1", - "browserify-cipher": "^1.0.1", - "eth-lib": "0.2.8", - "lodash": "^4.17.11", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "scrypt.js": "0.3.0", - "uuid": "3.3.2", - "web3-core": "1.0.0-beta.55", - "web3-core-helpers": "1.0.0-beta.55", - "web3-core-method": "1.0.0-beta.55", - "web3-providers": "1.0.0-beta.55", - "web3-utils": "1.0.0-beta.55" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } - } - }, - "web3-eth-contract": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.55.tgz", - "integrity": "sha512-v6oB1wfH039/A5sTb4ZTKX++fcBTHEkuQGpq50ATIDoxP/UTz2+6S+iL+3sCJTsByPw2/Bni/HM7NmLkXqzg/Q==", - "requires": { - "@babel/runtime": "^7.3.1", - "@types/bn.js": "^4.11.4", - "lodash": "^4.17.11", - "web3-core": "1.0.0-beta.55", - "web3-core-helpers": "1.0.0-beta.55", - "web3-core-method": "1.0.0-beta.55", - "web3-core-subscriptions": "1.0.0-beta.55", - "web3-eth-abi": "1.0.0-beta.55", - "web3-eth-accounts": "1.0.0-beta.55", - "web3-providers": "1.0.0-beta.55", - "web3-utils": "1.0.0-beta.55" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } - } - }, - "web3-eth-ens": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.0.0-beta.55.tgz", - "integrity": "sha512-jEL17coO0FJXb7KYq4+7DhVXj0Rh+wHfZ86jOvFUvJsRaUHfqK2TlMatuhD2mbrmxpBYb6oMPnXVnNK9bnD5Rg==", - "requires": { - "@babel/runtime": "^7.3.1", - "eth-ens-namehash": "2.0.8", - "lodash": "^4.17.11", - "web3-core": "1.0.0-beta.55", - "web3-core-helpers": "1.0.0-beta.55", - "web3-core-method": "1.0.0-beta.55", - "web3-eth-abi": "1.0.0-beta.55", - "web3-eth-accounts": "1.0.0-beta.55", - "web3-eth-contract": "1.0.0-beta.55", - "web3-net": "1.0.0-beta.55", - "web3-providers": "1.0.0-beta.55", - "web3-utils": "1.0.0-beta.55" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } - } - }, - "web3-eth-iban": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.55.tgz", - "integrity": "sha512-a2Fxsb5Mssa+jiXgjUdIzJipE0175IcQXJbZLpKft2+zeSJWNTbaa3PQD2vPPpIM4W789q06N+f9Zc0Fyls+1g==", - "requires": { - "@babel/runtime": "^7.3.1", - "bn.js": "4.11.8", - "web3-utils": "1.0.0-beta.55" - } - }, - "web3-eth-personal": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.55.tgz", - "integrity": "sha512-H0mahLQx6Oj7lpgTamKAswr3rHChRUZijeWAar2Hj7BABQlLRKwx8n09nYhxggvvLYQNQS90JjvQue7rAo2LQQ==", - "requires": { - "@babel/runtime": "^7.3.1", - "web3-core": "1.0.0-beta.55", - "web3-core-helpers": "1.0.0-beta.55", - "web3-core-method": "1.0.0-beta.55", - "web3-eth-accounts": "1.0.0-beta.55", - "web3-net": "1.0.0-beta.55", - "web3-providers": "1.0.0-beta.55", - "web3-utils": "1.0.0-beta.55" - } - }, - "web3-net": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.0.0-beta.55.tgz", - "integrity": "sha512-do2WY8+/GArJSWX7k/zZ7nBnV9Y3n6LhPYkwT3LeFqDzD515bKwlomaNC8hOaTc6UQyXIoPprYTK2FevL7jrZw==", - "requires": { - "@babel/runtime": "^7.3.1", - "lodash": "^4.17.11", - "web3-core": "1.0.0-beta.55", - "web3-core-helpers": "1.0.0-beta.55", - "web3-core-method": "1.0.0-beta.55", - "web3-providers": "1.0.0-beta.55", - "web3-utils": "1.0.0-beta.55" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } - } - }, - "web3-providers": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-providers/-/web3-providers-1.0.0-beta.55.tgz", - "integrity": "sha512-MNifc7W+iF6rykpbDR1MuX152jshWdZXHAU9Dk0Ja2/23elhIs4nCWs7wOX9FHrKgdrQbscPoq0uy+0aGzyWVQ==", - "requires": { - "@babel/runtime": "^7.3.1", - "@types/node": "^10.12.18", - "eventemitter3": "3.1.0", - "lodash": "^4.17.11", - "url-parse": "1.4.4", - "web3-core": "1.0.0-beta.55", - "web3-core-helpers": "1.0.0-beta.55", - "web3-core-method": "1.0.0-beta.55", - "web3-utils": "1.0.0-beta.55", - "websocket": "^1.0.28", - "xhr2-cookies": "1.1.0" - }, - "dependencies": { - "@types/node": { - "version": "10.14.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.8.tgz", - "integrity": "sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw==" - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } - } - }, - "web3-shh": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.0.0-beta.55.tgz", - "integrity": "sha512-lGP2HQ/1ThNnfoU8677aL48KsTx4Ht+2KQIn39dGpxVZqysQmovQIltbymVnAr4h8wofwcEz46iNHGa+PAyNzA==", - "requires": { - "@babel/runtime": "^7.3.1", - "web3-core": "1.0.0-beta.55", - "web3-core-helpers": "1.0.0-beta.55", - "web3-core-method": "1.0.0-beta.55", - "web3-core-subscriptions": "1.0.0-beta.55", - "web3-net": "1.0.0-beta.55", - "web3-providers": "1.0.0-beta.55", - "web3-utils": "1.0.0-beta.55" - } - }, - "web3-utils": { - "version": "1.0.0-beta.55", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.0.0-beta.55.tgz", - "integrity": "sha512-ASWqUi8gtWK02Tp8ZtcoAbHenMpQXNvHrakgzvqTNNZn26wgpv+Q4mdPi0KOR6ZgHFL8R/9b5BBoUTglS1WPpg==", - "requires": { - "@babel/runtime": "^7.3.1", - "@types/bn.js": "^4.11.4", - "@types/node": "^10.12.18", - "bn.js": "4.11.8", - "eth-lib": "0.2.8", - "ethjs-unit": "^0.1.6", - "lodash": "^4.17.11", - "number-to-bn": "1.7.0", - "randombytes": "^2.1.0", - "utf8": "2.1.1" - }, - "dependencies": { - "@types/node": { - "version": "10.14.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.8.tgz", - "integrity": "sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw==" - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } - } - }, - "websocket": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.28.tgz", - "integrity": "sha512-00y/20/80P7H4bCYkzuuvvfDvh+dgtXi5kzDf3UcZwN6boTYaKvsrtZ5lIYm1Gsg48siMErd9M4zjSYfYFHTrA==", - "requires": { - "debug": "^2.2.0", - "nan": "^2.11.0", - "typedarray-to-buffer": "^3.1.5", - "yaeti": "^0.0.6" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "xhr": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.5.0.tgz", - "integrity": "sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==", - "requires": { - "global": "~4.3.0", - "is-function": "^1.0.1", - "parse-headers": "^2.0.0", - "xtend": "^4.0.0" - } - }, - "xhr-request": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", - "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", - "requires": { - "buffer-to-arraybuffer": "^0.0.5", - "object-assign": "^4.1.1", - "query-string": "^5.0.1", - "simple-get": "^2.7.0", - "timed-out": "^4.0.1", - "url-set-query": "^1.0.0", - "xhr": "^2.0.4" - } - }, - "xhr-request-promise": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.2.tgz", - "integrity": "sha1-NDxE0e53JrhkgGloLQ+EDIO0Jh0=", - "requires": { - "xhr-request": "^1.0.1" - } - }, - "xhr2-cookies": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", - "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", - "requires": { - "cookiejar": "^2.1.1" - } - }, - "xmlhttprequest": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", - "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" - }, - "yaeti": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" - } - } -} diff --git a/package.json b/package.json index 9907166..27befe0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adamant-api", - "version": "0.5.3", + "version": "1.0.0-beta.1", "description": "\"REST API for ADAMANT Blockchain\"", "main": "index.js", "scripts": { From c94f53ab2bb67dbe9612de8ae337c5a32e6666a4 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Wed, 5 May 2021 12:39:17 +0300 Subject: [PATCH 02/57] Refector get module --- groups/get.js | 132 +++++++++++++++++++++++++++++-------------------- groups/get2.js | 76 ++++++++++++++++++++++++++++ index.js | 5 +- package.json | 1 + 4 files changed, 158 insertions(+), 56 deletions(-) create mode 100644 groups/get2.js diff --git a/groups/get.js b/groups/get.js index fa6c51f..7fd8212 100644 --- a/groups/get.js +++ b/groups/get.js @@ -1,60 +1,82 @@ -const request = require('sync-request'); +const axios = require('axios'); const logger = require('../helpers/logger'); -module.exports = (syncReq) => { - return async (type, params) => { - let endpoint; - let returned_field = false; - switch (type) { - case 'account': - endpoint = '/api/accounts?address=' + params; - break; - case 'delegate_forged': - endpoint = '/api/delegates/forging/getForgedByAccount?generatorPublicKey=' + params; - break; - case 'account_delegates': - endpoint = '/api/accounts/delegates?address=' + params; - returned_field = 'delegates'; - break; - case 'block': - endpoint = '/api/blocks/get?id=' + params; - break; - case 'states': - endpoint = '/api/states/get'; - if (params) { - endpoint = endpoint + '?' + params; - } - break; - case 'delegate': - endpoint = '/api/delegates/get?username=' + params; - returned_field = 'delegate'; - break; - case 'delegate_voters': - endpoint = '/api/delegates/voters?publicKey=' + params; - returned_field = 'accounts'; - break; - case 'blocks': - endpoint = '/api/blocks'; - if (params) { - endpoint = endpoint + '?' + params; - } - returned_field = 'blocks'; - break; - case 'transaction': - endpoint = '/api/transactions/get?id=' + params; - break; - case 'transactions': - endpoint = '/api/transactions?' + params.split(' ').join('').split(',').join('&'); - break; - case 'uri': - endpoint = '/api/' + params; - break; - default: - logger.error(`ADAMANT endpoint ${type} not implemented yet. Use 'uri' to use not implemented endpoints.`); - return false; - } +module.exports = (nodeManager) => { + return (endpoint, params) => { + + // let returned_field = false; + // switch (type) { + // case 'account': + // endpoint += '/api/accounts?address=' + params; + // break; + // case 'account_delegates': + // endpoint += '/api/accounts/delegates?address=' + params; + // returned_field = 'delegates'; + // break; + // case 'delegate': + // endpoint += '/api/delegates/get?username=' + params; + // returned_field = 'delegate'; + // break; + // case 'delegate_voters': + // endpoint += '/api/delegates/voters?publicKey=' + params; + // returned_field = 'accounts'; + // break; + // case 'delegate_forged': + // endpoint += '/api/delegates/forging/getForgedByAccount?generatorPublicKey=' + params; + // break; + // case 'block': + // endpoint += '/api/blocks/get?id=' + params; + // break; + // case 'states': + // endpoint += '/api/states/get'; + // if (params) { + // endpoint = endpoint + '?' + params; + // } + // break; + // case 'blocks': + // endpoint += '/api/blocks'; + // if (params) { + // endpoint = endpoint + '?' + params; + // } + // returned_field = 'blocks'; + // break; + // case 'transaction': + // endpoint += '/api/transactions/get?id=' + params; + // break; + // case 'transactions': + // endpoint += '/api/transactions?' + params.split(' ').join('').split(',').join('&'); + // break; + // case 'uri': + // endpoint += '/api/' + params; + // break; + // default: + // logger.error(`ADAMANT endpoint ${type} not implemented yet. Use 'uri' to use not implemented endpoints.`); + // return false; + // } + + const url = nodeManager.node() + endpoint; + return axios.get(url, { params }) + .then(function (response) { + log.log(response); + return { + success: true, + response + } + }) + .catch(function (error) { + log.error(error); + return { + success: false, + error + } + }) + .then(function () { + // always executed + }); + try { + const res = await syncReq(endpoint); if (res && res.success) { if (returned_field) { @@ -70,5 +92,7 @@ module.exports = (syncReq) => { logger.error(`Failed to process Get request of type ${type} to ADAMANT node. Error: ${e}.`); return false; } - }; + + } + }; diff --git a/groups/get2.js b/groups/get2.js new file mode 100644 index 0000000..f299c47 --- /dev/null +++ b/groups/get2.js @@ -0,0 +1,76 @@ +const request = require('sync-request'); +const logger = require('../helpers/logger'); + +module.exports = (syncReq) => { + return async (type, params) => { + let endpoint; + let returned_field = false; + switch (type) { + case 'account': + endpoint = '/api/accounts?address=' + params; + break; + case 'delegate_forged': + endpoint = '/api/delegates/forging/getForgedByAccount?generatorPublicKey=' + params; + break; + case 'account_delegates': + endpoint = '/api/accounts/delegates?address=' + params; + returned_field = 'delegates'; + break; + case 'block': + endpoint = '/api/blocks/get?id=' + params; + break; + case 'states': + endpoint = '/api/states/get'; + if (params) { + endpoint = endpoint + '?' + params; + } + break; + case 'delegate': + endpoint = '/api/delegates/get?username=' + params; + returned_field = 'delegate'; + break; + case 'delegate_voters': + endpoint = '/api/delegates/voters?publicKey=' + params; + returned_field = 'accounts'; + break; + case 'blocks': + endpoint = '/api/blocks'; + if (params) { + endpoint = endpoint + '?' + params; + } + returned_field = 'blocks'; + break; + case 'transaction': + endpoint = '/api/transactions/get?id=' + params; + break; + case 'transactions': + endpoint = '/api/transactions?' + params.split(' ').join('').split(',').join('&'); + break; + case 'uri': + endpoint = '/api/' + params; + break; + default: + logger.error(`ADAMANT endpoint ${type} not implemented yet. Use 'uri' to use not implemented endpoints.`); + return false; + } + + try { + + const res = await syncReq(endpoint); + if (res && res.success) { + if (returned_field) { + return res[returned_field]; + } + return res; + } + + logger.warn(`Get request to ADAMANT node was not successful. Type: ${type}, URL: ${endpoint}, Result: ${res && res.error}`); + return false; + + } catch (e) { + logger.error(`Failed to process Get request of type ${type} to ADAMANT node. Error: ${e}.`); + return false; + } + + }; +}; diff --git a/index.js b/index.js index 4fdea05..57a529d 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -const Get = require('./groups/get'); +const get = require('./groups/get'); const decodeMsg = require('./groups/decodeMsg'); const Send = require('./groups/send'); const healthCheck = require('./helpers/healthCheck'); @@ -14,10 +14,11 @@ module.exports = (params, log) => { log = log || console; logger.initLogger(params.logLevel, log); const {node, changeNodes} = healthCheck(params.node); + const nodeManager = healthCheck(params.node); const syncReq = syncGet(node, changeNodes); return { - get: Get(syncReq), + get: get(nodeManager), send: Send(node), decodeMsg, eth, diff --git a/package.json b/package.json index 27befe0..f122d29 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "author": "RomanS, Aleksei Lebedev (https://adamant.im)", "license": "GPL-3.0", "dependencies": { + "axios": "^0.21.1", "socket.io-client": "^2.2.0", "bignumber.js": "^8.0.1", "bitcore-mnemonic": "^1.5.0", From 864a9642136cff467a57bbcfdcfe18bd5678c1b9 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Fri, 7 May 2021 00:00:01 +0300 Subject: [PATCH 03/57] Get requests with retries --- groups/get.js | 115 +++++++++++++++----------------------------------- 1 file changed, 35 insertions(+), 80 deletions(-) diff --git a/groups/get.js b/groups/get.js index 7fd8212..d344618 100644 --- a/groups/get.js +++ b/groups/get.js @@ -1,98 +1,53 @@ const axios = require('axios'); +const _ = require('lodash'); const logger = require('../helpers/logger'); -module.exports = (nodeManager) => { - return (endpoint, params) => { - - // let returned_field = false; - // switch (type) { - // case 'account': - // endpoint += '/api/accounts?address=' + params; - // break; - // case 'account_delegates': - // endpoint += '/api/accounts/delegates?address=' + params; - // returned_field = 'delegates'; - // break; - // case 'delegate': - // endpoint += '/api/delegates/get?username=' + params; - // returned_field = 'delegate'; - // break; - // case 'delegate_voters': - // endpoint += '/api/delegates/voters?publicKey=' + params; - // returned_field = 'accounts'; - // break; - // case 'delegate_forged': - // endpoint += '/api/delegates/forging/getForgedByAccount?generatorPublicKey=' + params; - // break; - // case 'block': - // endpoint += '/api/blocks/get?id=' + params; - // break; - // case 'states': - // endpoint += '/api/states/get'; - // if (params) { - // endpoint = endpoint + '?' + params; - // } - // break; - // case 'blocks': - // endpoint += '/api/blocks'; - // if (params) { - // endpoint = endpoint + '?' + params; - // } - // returned_field = 'blocks'; - // break; - // case 'transaction': - // endpoint += '/api/transactions/get?id=' + params; - // break; - // case 'transactions': - // endpoint += '/api/transactions?' + params.split(' ').join('').split(',').join('&'); - // break; - // case 'uri': - // endpoint += '/api/' + params; - // break; - // default: - // logger.error(`ADAMANT endpoint ${type} not implemented yet. Use 'uri' to use not implemented endpoints.`); - // return false; - // } +const DEFAULT_GET_REQUEST_RETRIES = 2; // How much re-tries for get-requests by default - const url = nodeManager.node() + endpoint; +module.exports = (nodeManager) => { + return (endpoint, params, maxRetries = DEFAULT_GET_REQUEST_RETRIES, retryNo = 0) => { + + let url = _.trim(endpoint, "/ ") + if (!url || typeof(endpoint) !== 'string') + return new Promise((resolve, reject) => { + reject({ + success: false, + error: 'Bad parameters', + message: `Wrong endpoint parameter: ${endpoint}` + }) + }) + + url = nodeManager.node() + '/api//' + url; return axios.get(url, { params }) .then(function (response) { - log.log(response); + console.log('success'); return { success: true, - response + response: response, + status: response.status, + statusText: response.statusText, + result: response.data } }) .catch(function (error) { - log.error(error); + let logMessage = `[ADAMANT js-api] Get-request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}. Message: ${error.response ? _.trim(error.response.data, '\n') : undefined}. Try ${retryNo+1} of ${maxRetries+1}.`; + if (retryNo < maxRetries) { + logger.log(`${logMessage} Retrying…`); + return nodeManager.changeNodes() + .then(function () { + return module.exports(nodeManager)(endpoint, params, maxRetries, ++retryNo) + }) + } + logger.warn(`${logMessage} No more attempts, returning error.`); return { success: false, - error + response: error.response, + status: error.response ? error.response.status : undefined, + statusText: error.response ? error.response.statusText : undefined, + error: error.toString(), + message: error.response ? error.response.data : undefined } }) - .then(function () { - // always executed - }); - - - try { - - const res = await syncReq(endpoint); - if (res && res.success) { - if (returned_field) { - return res[returned_field]; - } - return res; - } - - logger.warn(`Get request to ADAMANT node was not successful. Type: ${type}, URL: ${endpoint}, Result: ${res && res.error}`); - return false; - - } catch (e) { - logger.error(`Failed to process Get request of type ${type} to ADAMANT node. Error: ${e}.`); - return false; - } } - }; From b65fe68768f0f5980234d2087611cb35890e7c26 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Fri, 7 May 2021 00:01:32 +0300 Subject: [PATCH 04/57] Health check with retries --- helpers/healthCheck.js | 151 +++++++++++++++++++++++++---------------- 1 file changed, 92 insertions(+), 59 deletions(-) diff --git a/helpers/healthCheck.js b/helpers/healthCheck.js index a111895..0a303a8 100644 --- a/helpers/healthCheck.js +++ b/helpers/healthCheck.js @@ -2,110 +2,143 @@ const request = require('request'); const _ = require('lodash'); const socket = require('./wsClient'); const logger = require('./logger'); + +const CHECK_NODES_INTERVAL = 60 * 5 * 1000; // Update active nodes every 5 minutes const HEIGHT_EPSILON = 10; // Used to group nodes by height and choose synced module.exports = (nodes) => { - if (typeof nodes === 'string') { - return () => nodes; + isCheckingNodes = false; + activeNode = nodes[0]; + liveNodes = []; + + /** + * Updates active nodes. If nodes are already updating, returns Promise of previous call + * @returns {Promise} Call changeNodes().then to do something when update complete + */ + function changeNodes (isPlannedUpdate = false) { + if (!this.isCheckingNodes) { + this.changeNodesPromise = new Promise(async (resolve) => { + if (!isPlannedUpdate) { + logger.warn('[ADAMANT js-api] Health check: Forcing to update active nodes…'); + } + await checkNodes(_.shuffle(nodes), this) + resolve(true) + }); + } + return this.changeNodesPromise } - this.hotNode = nodes[0]; - this.liveNodes = []; - checkNodes(nodes, this); - - setInterval(() => { - checkNodes(_.shuffle(nodes), this); - }, 60 * 1000); + + changeNodes(true) + setInterval(() => { changeNodes(true) }, CHECK_NODES_INTERVAL); return { - node: () => { // Current active node for REST requests - return this.hotNode; + + /** + * @returns {string} Current active node, f. e. http://88.198.156.44:36666 + */ + node: () => { + return activeNode; }, - changeNodes: _.throttle(() => { - logger.warn('[Health check]: Forcing to change node.'); - // To do: choose not the fastest node? May the fastest be defective? - checkNodes(_.shuffle(nodes), this); - }, 5000) + + changeNodes + }; + }; -// Request every node for its status and make a list of active ones +/** + * Requests every ADAMANT node for its status, makes a list of live nodes, and chooses one active + * @param nodes {Array} Array of nodes to request + * @param context {Object} Object, storing liveNodes and activeNode + * @returns {Promise} Call changeNodes().then to do something when update complete + */ async function checkNodes(nodes, context) { + context.isCheckingNodes = true; context.liveNodes = []; - nodes.forEach(async n => { - try { - const start = unix(); - const req = await checkNode(n + '/api/node/status'); - - if (req.status) { - context.liveNodes.push({ - node: n, - ifHttps: n.startsWith("https"), - url: n.replace(/^https?:\/\/(.*)$/, '$1').split(":")[0], - outOfSync: false, - ping: unix() - start, - height: req.status.network.height, - heightEpsilon: Math.round(req.status.network.height / HEIGHT_EPSILON), - ip: req.ip, - socketSupport: req.status.wsClient && req.status.wsClient.enabled, - wsPort: req.status.wsClient.port - }); - } else { - logger.log(`Node ${n} haven't returned its status.`); + + try { + + for (const n of nodes) { + try { + const start = unixTimestamp(); + const req = await checkNode(n + '/api/node/status'); + + if (req.status) { + context.liveNodes.push({ + node: n, + ifHttps: n.startsWith("https"), + url: n.replace(/^https?:\/\/(.*)$/, '$1').split(":")[0], + outOfSync: false, + ping: unixTimestamp() - start, + height: req.status.network.height, + heightEpsilon: Math.round(req.status.network.height / HEIGHT_EPSILON), + ip: req.ip, + socketSupport: req.status.wsClient && req.status.wsClient.enabled, + wsPort: req.status.wsClient.port + }); + + } else { + logger.log(`[ADAMANT js-api] Health check: Node ${n} haven't returned its status`); + } + + } catch (e) { + logger.log(`[ADAMANT js-api] Health check: Error while checking node ${n}:`, e); } - } catch (e) { - logger.log('Error while checking node', n); } - }); - - setTimeout(() => { // Allow 3 seconds to request nodes const count = context.liveNodes.length; if (!count) { - logger.error('[Health check]: All of ADAMANT nodes are unavailable. Check internet connection and nodes list in config.'); + logger.error('[ADAMANT js-api] Health check: All of nodes are unavailable. Check internet connection and nodes list in config.'); return; } - // Set hotNode to one that have maximum height and minimum ping + // Set activeNode to one that have maximum height and minimum ping if (count === 1) { - context.hotNode = context.liveNodes[0].node; + context.activeNode = context.liveNodes[0].node; } else if (count === 2) { const h0 = context.liveNodes[0]; const h1 = context.liveNodes[1]; - context.hotNode = h0.height > h1.height ? h0.node : h1.node; - + context.activeNode = h0.height > h1.height ? h0.node : h1.node; // Mark node outOfSync if needed if (h0.heightEpsilon > h1.heightEpsilon) { context.liveNodes[1].outOfSync = true } else if (h0.heightEpsilon < h1.heightEpsilon) { context.liveNodes[0].outOfSync = true } - } else { let biggestGroup = []; const groups = _.groupBy(context.liveNodes, n => n.heightEpsilon); Object.keys(groups).forEach(key => { - if (groups[key].length > biggestGroup.length){ + if (groups[key].length > biggestGroup.length) { biggestGroup = groups[key]; } }); - // All the nodes from the biggestGroup list are considered to be in sync, all the others are not - context.liveNodes.forEach(node => { + context.liveNodes.forEach(node => { node.outOfSync = !biggestGroup.includes(node) - }) - + }) biggestGroup.sort((a, b) => a.ping - b.ping); context.liveNodes.sort((a, b) => a.ping - b.ping); - context.hotNode = biggestGroup[0].node; // Use node with minimum ping among which are synced + context.activeNode = biggestGroup[0].node; // Use node with minimum ping among which are synced } socket.reviseConnection(context.liveNodes); - logger.log(`[Health check] Supported nodes: ${context.liveNodes.length}. hotNode is ${context.hotNode}.`); - // logger.logog('liveNodes', context.liveNodes, context.liveNodes.length); - }, 3000); + logger.log(`[ADAMANT js-api] Health check: Found ${context.liveNodes.length} supported nodes. Active node is ${context.activeNode}.`); + + } catch (e) { + logger.warn('[ADAMANT js-api] Health check: Error in checkNodes()', e); + } + + context.isCheckingNodes = false; + } +/** + * Requests status from a single ADAMANT node + * @param url {string} Node URL to request + * @returns {Promise} Node's status information + */ // Request status from a single node function checkNode(url) { return new Promise(resolve => { @@ -115,7 +148,7 @@ function checkNode(url) { } else { try { const status = JSON.parse(body); - const result = {status: status, ip: res.connection.remoteAddress}; + const result = { status: status, ip: res.connection.remoteAddress }; resolve(result); } catch (e) { resolve(false); @@ -125,6 +158,6 @@ function checkNode(url) { }); }; -function unix(){ +function unixTimestamp() { return new Date().getTime(); } From 69d80fc895387992a50b8e9fecca06fec7443bb1 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Fri, 7 May 2021 00:04:36 +0300 Subject: [PATCH 05/57] Remove syncGet --- index.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/index.js b/index.js index 57a529d..62426d9 100644 --- a/index.js +++ b/index.js @@ -3,7 +3,6 @@ const decodeMsg = require('./groups/decodeMsg'); const Send = require('./groups/send'); const healthCheck = require('./helpers/healthCheck'); const eth = require('./groups/eth'); -const syncGet = require('./groups/syncGet'); const transactionFormer = require('./helpers/transactionFormer'); const keys = require('./helpers/keys'); const encrypter = require('./helpers/encrypter'); @@ -13,16 +12,13 @@ const logger = require('adamant-api/helpers/logger'); module.exports = (params, log) => { log = log || console; logger.initLogger(params.logLevel, log); - const {node, changeNodes} = healthCheck(params.node); const nodeManager = healthCheck(params.node); - const syncReq = syncGet(node, changeNodes); return { get: get(nodeManager), - send: Send(node), + // send: Send(node), decodeMsg, eth, - syncGet: syncReq, transactionFormer, keys, encrypter, From 0d5486a882b342bbb5bdec8379fe9634e0604e66 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Fri, 7 May 2021 00:59:14 +0300 Subject: [PATCH 06/57] forceChangeActiveNode --- groups/get.js | 2 +- helpers/healthCheck.js | 54 ++++++++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/groups/get.js b/groups/get.js index d344618..dd67b7c 100644 --- a/groups/get.js +++ b/groups/get.js @@ -2,7 +2,7 @@ const axios = require('axios'); const _ = require('lodash'); const logger = require('../helpers/logger'); -const DEFAULT_GET_REQUEST_RETRIES = 2; // How much re-tries for get-requests by default +const DEFAULT_GET_REQUEST_RETRIES = 3; // How much re-tries for get-requests by default. Total 3+1 tries module.exports = (nodeManager) => { return (endpoint, params, maxRetries = DEFAULT_GET_REQUEST_RETRIES, retryNo = 0) => { diff --git a/helpers/healthCheck.js b/helpers/healthCheck.js index 0a303a8..dce497b 100644 --- a/helpers/healthCheck.js +++ b/helpers/healthCheck.js @@ -9,7 +9,8 @@ const HEIGHT_EPSILON = 10; // Used to group nodes by height and choose synced module.exports = (nodes) => { isCheckingNodes = false; - activeNode = nodes[0]; + nodesList = nodes; + activeNode = nodesList[0]; liveNodes = []; /** @@ -17,12 +18,12 @@ module.exports = (nodes) => { * @returns {Promise} Call changeNodes().then to do something when update complete */ function changeNodes (isPlannedUpdate = false) { - if (!this.isCheckingNodes) { + if (!isCheckingNodes) { this.changeNodesPromise = new Promise(async (resolve) => { if (!isPlannedUpdate) { logger.warn('[ADAMANT js-api] Health check: Forcing to update active nodes…'); } - await checkNodes(_.shuffle(nodes), this) + await checkNodes(isPlannedUpdate? false : true) resolve(true) }); } @@ -49,24 +50,21 @@ module.exports = (nodes) => { /** * Requests every ADAMANT node for its status, makes a list of live nodes, and chooses one active - * @param nodes {Array} Array of nodes to request - * @param context {Object} Object, storing liveNodes and activeNode - * @returns {Promise} Call changeNodes().then to do something when update complete */ -async function checkNodes(nodes, context) { +async function checkNodes(forceChangeActiveNode) { - context.isCheckingNodes = true; - context.liveNodes = []; + this.isCheckingNodes = true; + this.liveNodes = []; try { - for (const n of nodes) { + for (const n of this.nodesList) { try { const start = unixTimestamp(); const req = await checkNode(n + '/api/node/status'); if (req.status) { - context.liveNodes.push({ + this.liveNodes.push({ node: n, ifHttps: n.startsWith("https"), url: n.replace(/^https?:\/\/(.*)$/, '$1').split(":")[0], @@ -88,49 +86,53 @@ async function checkNodes(nodes, context) { } } - const count = context.liveNodes.length; + const count = this.liveNodes.length; if (!count) { - logger.error('[ADAMANT js-api] Health check: All of nodes are unavailable. Check internet connection and nodes list in config.'); + logger.error(`[ADAMANT js-api] Health check: All of ${this.nodesList.length} nodes are unavailable. Check internet connection and nodes list in config.`); return; } // Set activeNode to one that have maximum height and minimum ping if (count === 1) { - context.activeNode = context.liveNodes[0].node; + this.activeNode = this.liveNodes[0].node; } else if (count === 2) { - const h0 = context.liveNodes[0]; - const h1 = context.liveNodes[1]; - context.activeNode = h0.height > h1.height ? h0.node : h1.node; + const h0 = this.liveNodes[0]; + const h1 = this.liveNodes[1]; + this.activeNode = h0.height > h1.height ? h0.node : h1.node; // Mark node outOfSync if needed if (h0.heightEpsilon > h1.heightEpsilon) { - context.liveNodes[1].outOfSync = true + this.liveNodes[1].outOfSync = true } else if (h0.heightEpsilon < h1.heightEpsilon) { - context.liveNodes[0].outOfSync = true + this.liveNodes[0].outOfSync = true } } else { let biggestGroup = []; - const groups = _.groupBy(context.liveNodes, n => n.heightEpsilon); + const groups = _.groupBy(this.liveNodes, n => n.heightEpsilon); Object.keys(groups).forEach(key => { if (groups[key].length > biggestGroup.length) { biggestGroup = groups[key]; } }); // All the nodes from the biggestGroup list are considered to be in sync, all the others are not - context.liveNodes.forEach(node => { + this.liveNodes.forEach(node => { node.outOfSync = !biggestGroup.includes(node) }) biggestGroup.sort((a, b) => a.ping - b.ping); - context.liveNodes.sort((a, b) => a.ping - b.ping); - context.activeNode = biggestGroup[0].node; // Use node with minimum ping among which are synced + this.liveNodes.sort((a, b) => a.ping - b.ping); + + if (this.activeNode === biggestGroup[0].node && forceChangeActiveNode) + this.activeNode = biggestGroup[_.random(1, biggestGroup.length-1)].node // Use random node from which are synced + else + this.activeNode = biggestGroup[0].node; // Use node with minimum ping among which are synced } - socket.reviseConnection(context.liveNodes); - logger.log(`[ADAMANT js-api] Health check: Found ${context.liveNodes.length} supported nodes. Active node is ${context.activeNode}.`); + socket.reviseConnection(this.liveNodes); + logger.log(`[ADAMANT js-api] Health check: Found ${this.liveNodes.length} supported nodes. Active node is ${this.activeNode}.`); } catch (e) { logger.warn('[ADAMANT js-api] Health check: Error in checkNodes()', e); } - context.isCheckingNodes = false; + this.isCheckingNodes = false; } From a5c69541d53003bf264aa72c9a3dc27d44d278d1 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sun, 9 May 2021 11:41:44 +0300 Subject: [PATCH 07/57] Fixes for healthCheck and get --- groups/get.js | 5 ++--- helpers/healthCheck.js | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/groups/get.js b/groups/get.js index dd67b7c..d572113 100644 --- a/groups/get.js +++ b/groups/get.js @@ -17,10 +17,9 @@ module.exports = (nodeManager) => { }) }) - url = nodeManager.node() + '/api//' + url; + url = nodeManager.node() + '/api/' + url; return axios.get(url, { params }) .then(function (response) { - console.log('success'); return { success: true, response: response, @@ -45,7 +44,7 @@ module.exports = (nodeManager) => { status: error.response ? error.response.status : undefined, statusText: error.response ? error.response.statusText : undefined, error: error.toString(), - message: error.response ? error.response.data : undefined + message: error.response ? _.trim(error.response.data, '\n') : undefined } }) diff --git a/helpers/healthCheck.js b/helpers/healthCheck.js index dce497b..53b304d 100644 --- a/helpers/healthCheck.js +++ b/helpers/healthCheck.js @@ -19,7 +19,7 @@ module.exports = (nodes) => { */ function changeNodes (isPlannedUpdate = false) { if (!isCheckingNodes) { - this.changeNodesPromise = new Promise(async (resolve) => { + changeNodesPromise = new Promise(async (resolve) => { if (!isPlannedUpdate) { logger.warn('[ADAMANT js-api] Health check: Forcing to update active nodes…'); } @@ -27,7 +27,7 @@ module.exports = (nodes) => { resolve(true) }); } - return this.changeNodesPromise + return changeNodesPromise } changeNodes(true) From aca6434b16092850a8747d910a66bb09046498ee Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 15 May 2021 15:33:15 +0300 Subject: [PATCH 08/57] Refactor encryptor --- groups/send.js | 4 ++-- helpers/{encrypter.js => encryptor.js} | 10 ++++------ index.js | 4 ++-- 3 files changed, 8 insertions(+), 10 deletions(-) rename helpers/{encrypter.js => encryptor.js} (81%) diff --git a/groups/send.js b/groups/send.js index 0257c31..288eb92 100644 --- a/groups/send.js +++ b/groups/send.js @@ -1,6 +1,6 @@ const request = require('sync-request'); const keys = require('../helpers/keys'); -const encrypter = require('../helpers/encrypter'); +const encryptor = require('../helpers/encryptor'); const constants = require('../helpers/constants'); const logger = require('../helpers/logger'); const transactionFormer = require('../helpers/transactionFormer'); @@ -59,7 +59,7 @@ module.exports = (hotNode) => { const answer = JSON.parse(res.getBody().toString()); if (answer.success) { - const encrypt_data = encrypter.encodeMessage(payload, keyPair, answer.publicKey); + const encrypt_data = encryptor.encodeMessage(payload, keyPair, answer.publicKey); data.message = encrypt_data.message; data.own_message = encrypt_data.own_message; diff --git a/helpers/encrypter.js b/helpers/encryptor.js similarity index 81% rename from helpers/encrypter.js rename to helpers/encryptor.js index 66b06bd..fe5e4cf 100644 --- a/helpers/encrypter.js +++ b/helpers/encryptor.js @@ -1,14 +1,9 @@ var sodium = require('sodium-browserify-tweetnacl') -var crypto = require('crypto') -var Mnemonic = require('bitcore-mnemonic') -var bignum = require('./bignumber.js') -var keys = require('./keys.js') var nacl = require('tweetnacl/nacl-fast') var ed2curve = require('ed2curve') -var ByteBuffer = require('bytebuffer') -const constants = require('./constants.js') module.exports = { + bytesToHex: function (bytes) { for (var hex = [], i = 0; i < bytes.length; i++) { hex.push((bytes[i] >>> 4).toString(16)) @@ -16,12 +11,14 @@ module.exports = { } return hex.join('') }, + hexToBytes: function (hex) { for (var bytes = [], c = 0; c < hex.length; c += 2) { bytes.push(parseInt(hex.substr(c, 2), 16)) } return bytes }, + encodeMessage: function (msg, keypair, recipientPublicKey) { var nonce = Buffer.allocUnsafe(24) sodium.randombytes(nonce) @@ -34,4 +31,5 @@ module.exports = { own_message: this.bytesToHex(nonce) } } + } diff --git a/index.js b/index.js index 62426d9..5f9a755 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,7 @@ const healthCheck = require('./helpers/healthCheck'); const eth = require('./groups/eth'); const transactionFormer = require('./helpers/transactionFormer'); const keys = require('./helpers/keys'); -const encrypter = require('./helpers/encrypter'); +const encryptor = require('./helpers/encryptor'); const socket = require('./helpers/wsClient'); const logger = require('adamant-api/helpers/logger'); @@ -21,7 +21,7 @@ module.exports = (params, log) => { eth, transactionFormer, keys, - encrypter, + encryptor, socket }; }; From bc50907474591f22d5dee118dff0e6b48d3e2464 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 15 May 2021 15:56:33 +0300 Subject: [PATCH 09/57] Update deps --- groups/get2.js | 76 --------------------------------- groups/syncGet.js | 30 ------------- package.json | 105 +++++++++++++++++++++++++--------------------- 3 files changed, 58 insertions(+), 153 deletions(-) delete mode 100644 groups/get2.js delete mode 100644 groups/syncGet.js diff --git a/groups/get2.js b/groups/get2.js deleted file mode 100644 index f299c47..0000000 --- a/groups/get2.js +++ /dev/null @@ -1,76 +0,0 @@ -const request = require('sync-request'); -const logger = require('../helpers/logger'); - -module.exports = (syncReq) => { - return async (type, params) => { - let endpoint; - let returned_field = false; - switch (type) { - case 'account': - endpoint = '/api/accounts?address=' + params; - break; - case 'delegate_forged': - endpoint = '/api/delegates/forging/getForgedByAccount?generatorPublicKey=' + params; - break; - case 'account_delegates': - endpoint = '/api/accounts/delegates?address=' + params; - returned_field = 'delegates'; - break; - case 'block': - endpoint = '/api/blocks/get?id=' + params; - break; - case 'states': - endpoint = '/api/states/get'; - if (params) { - endpoint = endpoint + '?' + params; - } - break; - case 'delegate': - endpoint = '/api/delegates/get?username=' + params; - returned_field = 'delegate'; - break; - case 'delegate_voters': - endpoint = '/api/delegates/voters?publicKey=' + params; - returned_field = 'accounts'; - break; - case 'blocks': - endpoint = '/api/blocks'; - if (params) { - endpoint = endpoint + '?' + params; - } - returned_field = 'blocks'; - break; - case 'transaction': - endpoint = '/api/transactions/get?id=' + params; - break; - case 'transactions': - endpoint = '/api/transactions?' + params.split(' ').join('').split(',').join('&'); - break; - case 'uri': - endpoint = '/api/' + params; - break; - default: - logger.error(`ADAMANT endpoint ${type} not implemented yet. Use 'uri' to use not implemented endpoints.`); - return false; - } - - try { - - const res = await syncReq(endpoint); - if (res && res.success) { - if (returned_field) { - return res[returned_field]; - } - return res; - } - - logger.warn(`Get request to ADAMANT node was not successful. Type: ${type}, URL: ${endpoint}, Result: ${res && res.error}`); - return false; - - } catch (e) { - logger.error(`Failed to process Get request of type ${type} to ADAMANT node. Error: ${e}.`); - return false; - } - - }; -}; diff --git a/groups/syncGet.js b/groups/syncGet.js deleted file mode 100644 index 701409e..0000000 --- a/groups/syncGet.js +++ /dev/null @@ -1,30 +0,0 @@ -const request = require('request'); -const logger = require('../helpers/logger'); - -module.exports = (node, changeNodes) => { - return (uri, isUrl, isNoJson) => { - return new Promise(resolve => { - let url = isUrl && uri || node() + uri; - request(url, (a, b) => { - try { - const {body} = b; - if (isNoJson) { - resolve(body); - } else { - resolve(JSON.parse(body)); - } - } catch (e) { - let output = `Failed to process Syn-Get request ${url}. `; - if (isUrl) { // Request not to ADAMANT node - output += `Host may be unavailable. Error: ${e}` - } else { // Request to ADAMANT node - output += `Forcing to change active node now. Error: ${e}` - changeNodes(); - } - logger.warn(output); - resolve(null); - } - }); - }); - }; -}; diff --git a/package.json b/package.json index f122d29..d86adc9 100644 --- a/package.json +++ b/package.json @@ -1,48 +1,59 @@ { - "name": "adamant-api", - "version": "1.0.0-beta.1", - "description": "\"REST API for ADAMANT Blockchain\"", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [ - "adm", - "adm api", - "adamant", - "adamant api", - "blockchain", - "messenger", - "chat", - "bitcoin", - "ethereum" - ], - "author": "RomanS, Aleksei Lebedev (https://adamant.im)", - "license": "GPL-3.0", - "dependencies": { - "axios": "^0.21.1", - "socket.io-client": "^2.2.0", - "bignumber.js": "^8.0.1", - "bitcore-mnemonic": "^1.5.0", - "bytebuffer": "^5.0.1", - "crypto": "^1.0.1", - "ed2curve": "^0.2.1", - "ethereumjs-util": "^6.1.0", - "hdkey": "^1.1.1", - "request": "^2.88.0", - "sodium-browserify-tweetnacl": "^0.2.3", - "sync-request": "^6.0.0", - "web3": "^1.0.0-beta.55" - }, - "publishConfig": { - "access": "public" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/Adamant-im/adamant-api-jsclient.git" - }, - "bugs": { - "url": "https://github.com/Adamant-im/adamant-api-jsclient/issues" - }, - "homepage": "https://github.com/Adamant-im/adamant-api-jsclient#readme" -} + "name": "adamant-api", + "version": "1.0.0-beta.1", + "description": "REST API for ADAMANT Blockchain", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "RomanS, Aleksei Lebedev (https://adamant.im)", + "license": "GPL-3.0", + "dependencies": { + "axios": "^0.21.1", + "socket.io-client": "^2.4.0", + "bignumber.js": "^9.0.1", + "bitcore-mnemonic": "^8.25.10", + "bytebuffer": "^5.0.1", + "ed2curve": "^0.3.0", + "ethereumjs-util": "^6.1.0", + "hdkey": "^1.1.1", + "sodium-browserify-tweetnacl": "^0.2.6", + "web3": "^1.0.0-beta.55" + }, + "publishConfig": { + "access": "public" + }, + "keywords": [ + "adm", + "adamant", + "blockchain", + "messenger", + "chat", + "decentralized messenger", + "anonymous messenger", + "secure messenger", + "wallet", + "crypto wallet", + "private keys", + "communication", + "decentralized", + "decentralization", + "anonymous", + "anonymity", + "secure", + "encrypted", + "encryption", + "crypto", + "cryptocurrency", + "bitcoin", + "ethereum" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/Adamant-im/adamant-api-jsclient.git" + }, + "bugs": { + "url": "https://github.com/Adamant-im/adamant-api-jsclient/issues" + }, + "homepage": "https://github.com/Adamant-im/adamant-api-jsclient#readme" +} \ No newline at end of file From 864bf29aaddf3a46ffa983eb8017040720a94361 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 15 May 2021 15:57:32 +0300 Subject: [PATCH 10/57] Format keys --- helpers/keys.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/helpers/keys.js b/helpers/keys.js index 3a938ec..d554b16 100644 --- a/helpers/keys.js +++ b/helpers/keys.js @@ -4,9 +4,11 @@ var Mnemonic = require('bitcore-mnemonic'); var bignum = require('./bignumber.js'); module.exports = { + createNewPassPhrase: function () { return new Mnemonic(Mnemonic.Words.ENGLISH).toString(); }, + makeKeypairFromHash: function (hash) { var keypair = sodium.crypto_sign_seed_keypair(hash); return { @@ -14,22 +16,24 @@ module.exports = { privateKey: keypair.secretKey }; }, + createHashFromPassPhrase: function (passPhrase) { var secretMnemonic = new Mnemonic(passPhrase, Mnemonic.Words.ENGLISH); return crypto.createHash('sha256').update(secretMnemonic.toSeed().toString('hex'), 'hex').digest(); }, + createKeypairFromPassPhrase: function (passPhrase) { var hash = this.createHashFromPassPhrase(passPhrase); return this.makeKeypairFromHash(hash); }, + createAddressFromPublicKey: function (publicKey) { var publicKeyHash = crypto.createHash('sha256').update(publicKey, 'hex').digest(); - var temp = Buffer.alloc(8); - + var temp = Buffer.alloc(8); for (var i = 0; i < 8; i++) { temp[i] = publicKeyHash[7 - i]; } - return 'U' + bignum.fromBuffer(temp).toString(); } -}; \ No newline at end of file + +} From 1ae4856ef6b34488512a546184073bff51e3fc53 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 15 May 2021 15:58:42 +0300 Subject: [PATCH 11/57] Format logger --- helpers/keys.js | 4 ++-- helpers/logger.js | 41 ++++++++++++++++++++++++----------------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/helpers/keys.js b/helpers/keys.js index d554b16..0e2b317 100644 --- a/helpers/keys.js +++ b/helpers/keys.js @@ -5,7 +5,7 @@ var bignum = require('./bignumber.js'); module.exports = { - createNewPassPhrase: function () { + createNewPassPhrase: function () { return new Mnemonic(Mnemonic.Words.ENGLISH).toString(); }, @@ -29,7 +29,7 @@ module.exports = { createAddressFromPublicKey: function (publicKey) { var publicKeyHash = crypto.createHash('sha256').update(publicKey, 'hex').digest(); - var temp = Buffer.alloc(8); + var temp = Buffer.alloc(8); for (var i = 0; i < 8; i++) { temp[i] = publicKeyHash[7 - i]; } diff --git a/helpers/logger.js b/helpers/logger.js index bfd1a07..43ca552 100644 --- a/helpers/logger.js +++ b/helpers/logger.js @@ -1,28 +1,35 @@ let logger = { - errorLevel: 'log', - l: console, - initLogger(errorLevel, log) { - if (errorLevel) - this.errorLevel = errorLevel; - if (log) - this.l = log; - }, + + errorLevel: 'log', + l: console, + + initLogger(errorLevel, log) { + if (errorLevel) + this.errorLevel = errorLevel; + if (log) + this.l = log; + }, + error(str) { - if (['error', 'warn', 'info', 'log'].includes(this.errorLevel)) - this.l.error(str); + if (['error', 'warn', 'info', 'log'].includes(this.errorLevel)) + this.l.error(str); }, + warn(str) { - if (['warn', 'info', 'log'].includes(this.errorLevel)) - this.l.warn(str); + if (['warn', 'info', 'log'].includes(this.errorLevel)) + this.l.warn(str); }, + info(str) { - if (['info', 'log'].includes(this.errorLevel)) - this.l.info(str); + if (['info', 'log'].includes(this.errorLevel)) + this.l.info(str); }, + log(str) { - if (['log'].includes(this.errorLevel)) - this.l.log(str); + if (['log'].includes(this.errorLevel)) + this.l.log(str); } + }; -module.exports = logger; \ No newline at end of file +module.exports = logger; From 4839243520e23b7f5ed64a6343fcdf477d942090 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 15 May 2021 16:00:15 +0300 Subject: [PATCH 12/57] Format time --- helpers/time.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/helpers/time.js b/helpers/time.js index 11185ee..4e46bf4 100644 --- a/helpers/time.js +++ b/helpers/time.js @@ -1,16 +1,18 @@ const constants = require('./constants.js'); + module.exports = { + getEpochTime: function (time) { if (time === undefined) { time = Date.now(); } - var d = constants.epochTime; var t = d.getTime(); - return Math.floor((time - t) / 1000); }, + getTime: function (time) { return this.getEpochTime(time); } -} \ No newline at end of file + +} From 7ae0667422dc83f47635371aead7b1dad01782b9 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 15 May 2021 16:01:48 +0300 Subject: [PATCH 13/57] Format transactionFormer --- helpers/transactionFormer.js | 157 ++++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 69 deletions(-) diff --git a/helpers/transactionFormer.js b/helpers/transactionFormer.js index 7fa8ca5..52107cd 100644 --- a/helpers/transactionFormer.js +++ b/helpers/transactionFormer.js @@ -1,6 +1,5 @@ var sodium = require('sodium-browserify-tweetnacl'); var crypto = require('crypto'); -var Mnemonic = require('bitcore-mnemonic'); var bignum = require('./bignumber.js'); var keys = require('./keys.js'); var ByteBuffer = require('bytebuffer'); @@ -8,25 +7,28 @@ const constants = require('./constants.js'); const time = require('./time.js'); module.exports = { + createTransaction: function (type, data) { switch (type) { - case constants.transactionTypes.SEND: - return this.createSendTransaction(data); - case constants.transactionTypes.VOTE: - return this.createVoteTransaction(data); - case constants.transactionTypes.DELEGATE: - return this.createDelegateTransaction(data); - case constants.transactionTypes.CHAT_MESSAGE: - return this.createChatTransaction(data); - case constants.transactionTypes.STATE: - return this.createStateTransaction(data); + case constants.transactionTypes.SEND: + return this.createSendTransaction(data); + case constants.transactionTypes.VOTE: + return this.createVoteTransaction(data); + case constants.transactionTypes.DELEGATE: + return this.createDelegateTransaction(data); + case constants.transactionTypes.CHAT_MESSAGE: + return this.createChatTransaction(data); + case constants.transactionTypes.STATE: + return this.createStateTransaction(data); } return {}; }, + createBasicTransaction: function (data) { - var transaction = {type: data.transactionType, amount: 0, timestamp: time.getTime(), asset: {}, senderPublicKey: data.keyPair.publicKey.toString('hex'), senderId: keys.createAddressFromPublicKey(data.keyPair.publicKey)}; + var transaction = { type: data.transactionType, amount: 0, timestamp: time.getTime(), asset: {}, senderPublicKey: data.keyPair.publicKey.toString('hex'), senderId: keys.createAddressFromPublicKey(data.keyPair.publicKey) }; return transaction; }, + createSendTransaction: function (data) { data.transactionType = constants.transactionTypes.SEND; var transaction = this.createBasicTransaction(data); @@ -36,103 +38,113 @@ module.exports = { transaction.signature = this.transactionSign(transaction, data.keyPair); return transaction; }, + createStateTransaction: function (data) { data.transactionType = constants.transactionTypes.STATE; var transaction = this.createBasicTransaction(data); - transaction.asset = {"state": { - key: data.key, - value: data.value, - type: 0 - }}; + transaction.asset = { + "state": { + key: data.key, + value: data.value, + type: 0 + } + }; transaction.recipientId = null; transaction.amount = 0; transaction.signature = this.transactionSign(transaction, data.keyPair); return transaction; }, + createChatTransaction: function (data) { data.transactionType = constants.transactionTypes.CHAT_MESSAGE; var transaction = this.createBasicTransaction(data); - transaction.asset = {"chat": { - message: data.message, - own_message: data.own_message, - type: data.message_type - }}; + transaction.asset = { + "chat": { + message: data.message, + own_message: data.own_message, + type: data.message_type + } + }; transaction.recipientId = data.recipientId; transaction.amount = data.amount || 0; transaction.signature = this.transactionSign(transaction, data.keyPair); return transaction; }, + createDelegateTransaction: function (data) { data.transactionType = constants.transactionTypes.DELEGATE; var transaction = this.createBasicTransaction(data); - transaction.asset = {"delegate": { "username": data.username, publicKey: data.keyPair.publicKey.toString('hex')}}; + transaction.asset = { "delegate": { "username": data.username, publicKey: data.keyPair.publicKey.toString('hex') } }; transaction.recipientId = null; transaction.signature = this.transactionSign(transaction, data.keyPair); return transaction; }, + createVoteTransaction: function (data) { data.transactionType = constants.transactionTypes.VOTE; var transaction = this.createBasicTransaction(data); - transaction.asset = {"votes": data.votes}; + transaction.asset = { "votes": data.votes }; transaction.recipientId = transaction.senderId; transaction.signature = this.transactionSign(transaction, data.keyPair); return transaction; }, + getHash: function (trs) { return crypto.createHash('sha256').update(this.getBytes(trs)).digest(); }, + getBytes: function (transaction) { var skipSignature = false; var skipSecondSignature = true; var assetSize = 0; var assetBytes = null; - + switch (transaction.type) { - case constants.transactionTypes.SEND: - break; - case constants.transactionTypes.DELEGATE: - assetBytes = this.delegatesGetBytes(transaction); - assetSize = assetBytes.length; - break; - case constants.transactionTypes.STATE: - assetBytes = this.statesGetBytes(transaction); - assetSize = assetBytes.length; - break; - case constants.transactionTypes.VOTE: - assetBytes = this.voteGetBytes(transaction); - assetSize = assetBytes.length; - break; - case constants.transactionTypes.CHAT_MESSAGE: - assetBytes = this.chatGetBytes(transaction); - assetSize = assetBytes.length; - break; - default: - // 'Not supported yet' - return 0; + case constants.transactionTypes.SEND: + break; + case constants.transactionTypes.DELEGATE: + assetBytes = this.delegatesGetBytes(transaction); + assetSize = assetBytes.length; + break; + case constants.transactionTypes.STATE: + assetBytes = this.statesGetBytes(transaction); + assetSize = assetBytes.length; + break; + case constants.transactionTypes.VOTE: + assetBytes = this.voteGetBytes(transaction); + assetSize = assetBytes.length; + break; + case constants.transactionTypes.CHAT_MESSAGE: + assetBytes = this.chatGetBytes(transaction); + assetSize = assetBytes.length; + break; + default: + // 'Not supported yet' + return 0; } - + var bb = new ByteBuffer(1 + 4 + 32 + 8 + 8 + 64 + 64 + assetSize, true); - + bb.writeByte(transaction.type); bb.writeInt(transaction.timestamp); - + var senderPublicKeyBuffer = Buffer.from(transaction.senderPublicKey, 'hex'); for (var i = 0; i < senderPublicKeyBuffer.length; i++) { bb.writeByte(senderPublicKeyBuffer[i]); } - + if (transaction.requesterPublicKey) { var requesterPublicKey = Buffer.from(transaction.requesterPublicKey, 'hex'); - + for (var i = 0; i < requesterPublicKey.length; i++) { bb.writeByte(requesterPublicKey[i]); } } - + if (transaction.recipientId) { var recipient = transaction.recipientId.slice(1); - recipient = new bignum(recipient).toBuffer({size: 8}); - + recipient = new bignum(recipient).toBuffer({ size: 8 }); + for (i = 0; i < 8; i++) { bb.writeByte(recipient[i] || 0); } @@ -141,43 +153,45 @@ module.exports = { bb.writeByte(0); } } - + bb.writeLong(transaction.amount); - + if (assetSize > 0) { for (var i = 0; i < assetSize; i++) { bb.writeByte(assetBytes[i]); } } - + if (!skipSignature && transaction.signature) { var signatureBuffer = Buffer.from(transaction.signature, 'hex'); for (var i = 0; i < signatureBuffer.length; i++) { bb.writeByte(signatureBuffer[i]); } } - + if (!skipSecondSignature && transaction.signSignature) { var signSignatureBuffer = Buffer.from(transaction.signSignature, 'hex'); for (var i = 0; i < signSignatureBuffer.length; i++) { bb.writeByte(signSignatureBuffer[i]); } } - + bb.flip(); var arrayBuffer = new Uint8Array(bb.toArrayBuffer()); var buffer = []; - + for (var i = 0; i < arrayBuffer.length; i++) { buffer[i] = arrayBuffer[i]; } - + return Buffer.from(buffer); }, + transactionSign: function (trs, keypair) { var hash = this.getHash(trs); return this.sign(hash, keypair).toString('hex'); }, + voteGetBytes: function (trs) { var buf; try { @@ -187,12 +201,13 @@ module.exports = { } return buf; }, + delegatesGetBytes: function (trs) { if (!trs.asset.delegate.username) { return null; } var buf; - + try { buf = Buffer.from(trs.asset.delegate.username, 'utf8'); } catch (e) { @@ -200,12 +215,13 @@ module.exports = { } return buf; }, + statesGetBytes: function (trs) { if (!trs.asset.state.value) { return null; } var buf; - + try { buf = Buffer.from([]); var stateBuf = Buffer.from(trs.asset.state.value); @@ -214,26 +230,27 @@ module.exports = { var keyBuf = Buffer.from(trs.asset.state.key); buf = Buffer.concat([buf, keyBuf]); } - + var bb = new ByteBuffer(4 + 4, true); bb.writeInt(trs.asset.state.type); bb.flip(); - + buf = Buffer.concat([buf, bb.toBuffer()]); } catch (e) { throw e; } - + return buf; }, + chatGetBytes: function (trs) { var buf; - + try { buf = Buffer.from([]); var messageBuf = Buffer.from(trs.asset.chat.message, 'hex'); buf = Buffer.concat([buf, messageBuf]); - + if (trs.asset.chat.own_message) { var ownMessageBuf = Buffer.from(trs.asset.chat.own_message, 'hex'); buf = Buffer.concat([buf, ownMessageBuf]); @@ -245,10 +262,12 @@ module.exports = { } catch (e) { throw e; } - + return buf; }, + sign: function (hash, keypair) { return sodium.crypto_sign_detached(hash, Buffer.from(keypair.privateKey, 'hex')); } + }; From fe3ed41e5b63a52b7804b83835a2d2814f98f57e Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 15 May 2021 16:02:37 +0300 Subject: [PATCH 14/57] Format wsClient --- helpers/wsClient.js | 173 ++++++++++++++++++++++---------------------- 1 file changed, 87 insertions(+), 86 deletions(-) diff --git a/helpers/wsClient.js b/helpers/wsClient.js index ff2faa3..a1e9979 100644 --- a/helpers/wsClient.js +++ b/helpers/wsClient.js @@ -3,97 +3,98 @@ const _ = require('lodash'); const logger = require('./logger'); module.exports = { - isSocketEnabled: false, // If we need socket connection - wsType: "ws", // Socket connection type, "ws" (default) or "wss" - admAddress: '', // ADM address to subscribe to notifications - connection: null, // Socket connection - onNewMessage: null, // Method to process new messages or transactions - activeNodes: [], // List of nodes that are active. Not all of them synced and support socket. - activeSocketNodes: [], // List of nodes that are active, synced and support socket - useFastest: false, // If to connect to node with minimum ping. Not recommended. + + isSocketEnabled: false, // If we need socket connection + wsType: "ws", // Socket connection type, "ws" (default) or "wss" + admAddress: '', // ADM address to subscribe to notifications + connection: null, // Socket connection + onNewMessage: null, // Method to process new messages or transactions + activeNodes: [], // List of nodes that are active. Not all of them synced and support socket. + activeSocketNodes: [], // List of nodes that are active, synced and support socket + useFastest: false, // If to connect to node with minimum ping. Not recommended. - // Constructor - initSocket(params) { - this.onNewMessage = params.onNewMessage; - this.isSocketEnabled = params.socket; - this.wsType = params.wsType; - this.admAddress = params.admAddress; - }, + // Constructor + initSocket(params) { + this.onNewMessage = params.onNewMessage; + this.isSocketEnabled = params.socket; + this.wsType = params.wsType; + this.admAddress = params.admAddress; + }, - // Runs after every healthCheck() to re-connect socket if needed - reviseConnection(nodes) { - if (!this.isSocketEnabled) { - return; - } - if (!this.connection || !this.connection.connected) { - this.activeNodes = nodes.slice(); - this.setNodes(); - this.setConnection(); - } - }, + // Runs after every healthCheck() to re-connect socket if needed + reviseConnection(nodes) { + if (!this.isSocketEnabled) { + return; + } + if (!this.connection || !this.connection.connected) { + this.activeNodes = nodes.slice(); + this.setNodes(); + this.setConnection(); + } + }, - // Make socket connection and subscribe to new transactions - setConnection() { - if (this.activeSocketNodes.length === 0) { - logger.warn(`[Socket] No supported socket nodes at the moment.`); - return; - } + // Make socket connection and subscribe to new transactions + setConnection() { + if (this.activeSocketNodes.length === 0) { + logger.warn(`[Socket] No supported socket nodes at the moment.`); + return; + } - const node = this.socketAddress(); - logger.log(`[Socket] Supported nodes: ${this.activeSocketNodes.length}. Connecting to ${node}...`); - this.connection = ioClient.connect(node, { reconnection: false, timeout: 5000 }); + const node = this.socketAddress(); + logger.log(`[Socket] Supported nodes: ${this.activeSocketNodes.length}. Connecting to ${node}...`); + this.connection = ioClient.connect(node, { reconnection: false, timeout: 5000 }); - this.connection.on('connect', () => { - this.connection.emit('address', this.admAddress); - logger.info('[Socket] Connected to ' + node + ' and subscribed to incoming transactions for ' + this.admAddress + '.'); - }); - - this.connection.on('disconnect', reason => { - logger.warn('[Socket] Disconnected. Reason: ' + reason) - }); - - this.connection.on('connect_error', (err) => { - logger.warn('[Socket] Connection error: ' + err) - }); - - this.connection.on('newTrans', transaction => { - if ((transaction.recipientId === this.admAddress) && (transaction.type === 0 || transaction.type === 8)) { - // console.info(`[Socket] New incoming socket transaction received: ${transaction.id}`); - this.onNewMessage(transaction); - } - }); - }, + this.connection.on('connect', () => { + this.connection.emit('address', this.admAddress); + logger.info('[Socket] Connected to ' + node + ' and subscribed to incoming transactions for ' + this.admAddress + '.'); + }); - // Save the list of nodes activeSocketNodes that are active, synced and support socket - setNodes() { - this.activeSocketNodes = this.activeNodes.filter(n => n.socketSupport & !n.outOfSync); - // Remove nodes without IP if "ws" connection type - if (this.wsType === "ws") { - this.activeSocketNodes = this.activeSocketNodes.filter(n => !n.ifHttps || n.ip); - } - }, + this.connection.on('disconnect', reason => { + logger.warn('[Socket] Disconnected. Reason: ' + reason) + }); + + this.connection.on('connect_error', (err) => { + logger.warn('[Socket] Connection error: ' + err) + }); + + this.connection.on('newTrans', transaction => { + if ((transaction.recipientId === this.admAddress) && (transaction.type === 0 || transaction.type === 8)) { + // console.info(`[Socket] New incoming socket transaction received: ${transaction.id}`); + this.onNewMessage(transaction); + } + }); + }, + + // Save the list of nodes activeSocketNodes that are active, synced and support socket + setNodes() { + this.activeSocketNodes = this.activeNodes.filter(n => n.socketSupport & !n.outOfSync); + // Remove nodes without IP if "ws" connection type + if (this.wsType === "ws") { + this.activeSocketNodes = this.activeSocketNodes.filter(n => !n.ifHttps || n.ip); + } + }, + + // Returns socket url for connection + socketAddress() { + const node = this.useFastest ? this.fastestNode() : this.randomNode(); + let socketUrl = this.wsType + "://"; + if (this.wsType === "ws") { + let host = node.ip; + if (!host || host === undefined) + host = node.url; + socketUrl = socketUrl + host + ":" + node.wsPort + } else { + socketUrl = socketUrl + node.url; // no port if wss + } + return socketUrl; + }, + + fastestNode() { + return this.activeSocketNodes[0]; // They are sorted by ping + }, + + randomNode() { + return this.activeSocketNodes[_.random(this.activeSocketNodes.length - 1)] + } - // Returns socket url for connection - socketAddress() { - const node = this.useFastest ? this.fastestNode() : this.randomNode(); - let socketUrl = this.wsType + "://"; - if (this.wsType === "ws") { - let host = node.ip; - if (!host || host === undefined) - host = node.url; - socketUrl = socketUrl + host + ":" + node.wsPort - } else { - socketUrl = socketUrl + node.url; // no port if wss - } - return socketUrl; - }, - - fastestNode() { - return this.activeSocketNodes[0]; // They are sorted by ping - }, - - randomNode() { - return this.activeSocketNodes[_.random(this.activeSocketNodes.length - 1)] - } - } From b14a706c219f1f01d53430db2175fffd55cc7782 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 15 May 2021 16:04:52 +0300 Subject: [PATCH 15/57] Format constants --- helpers/constants.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/helpers/constants.js b/helpers/constants.js index aa45399..821fc52 100644 --- a/helpers/constants.js +++ b/helpers/constants.js @@ -1,4 +1,5 @@ module.exports = { + epochTime: new Date(Date.UTC(2017, 8, 2, 17, 0, 0, 0)), fees: { send: 50000000, @@ -25,5 +26,7 @@ module.exports = { CHAT_MESSAGE: 8, STATE: 9 }, - maxVotesPerTransaction: 33 -} \ No newline at end of file + maxVotesPerTransaction: 33, + sat: 100000000 + +} From 700b3e2555555582b5b7728e4d441d9429f27b8f Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 15 May 2021 17:27:37 +0300 Subject: [PATCH 16/57] sendTokens --- groups/sendTokens.js | 89 ++++++++++++++++++++++++++++++++++++++++++++ helpers/constants.js | 8 +++- helpers/validator.js | 38 +++++++++++++++++++ index.js | 2 + 4 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 groups/sendTokens.js create mode 100644 helpers/validator.js diff --git a/groups/sendTokens.js b/groups/sendTokens.js new file mode 100644 index 0000000..301e184 --- /dev/null +++ b/groups/sendTokens.js @@ -0,0 +1,89 @@ +const axios = require('axios'); +const _ = require('lodash'); +const logger = require('../helpers/logger'); +const keys = require('../helpers/keys'); +const constants = require('../helpers/constants'); +const transactionFormer = require('../helpers/transactionFormer'); +const validator = require('../helpers/validator'); + +const DEFAULT_SEND_TOKENS_RETRIES = 4; // How much re-tries for send tokens requests by default. Total 4+1 tries + +module.exports = (nodeManager) => { + return (passPhrase, address, amount, isAmountInADM = true, maxRetries = DEFAULT_SEND_TOKENS_RETRIES, retryNo = 0) => { + + let transaction; + + try { + + if (!validator.validatePassPhrase(passPhrase)) + return validator.badParameter('passPhrase') + + const keyPair = keys.createKeypairFromPassPhrase(passPhrase); + + if (!validator.validateAdmAddress(address)) + return badParameter('address') + + if (isAmountInADM) { + amount = parseInt(parseFloat(String(amount)) * constants.SAT) + } + + if (!validator.validateIntegerAmount(amount)) + return badParameter('amount') + + const data = { + keyPair, + recipientId: address, + amount + }; + + transaction = transactionFormer.createTransaction(constants.transactionTypes.SEND, data); + + } catch (e) { + + return validator.badParameter('#exception_catched#', e) + + } + + console.log(transaction, transaction) + + const params = { + json: { + transaction + } + }; + + let url = nodeManager.node() + '/api/transactions/process'; + return axios.post(url, { params }) + .then(function (response) { + console.log('done', response) + return { + success: true, + response: response, + status: response.status, + statusText: response.statusText, + result: response.data + } + }) + .catch(function (error) { + console.log('error', error) + let logMessage = `[ADAMANT js-api] Send tokens request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}. Message: ${error.response ? _.trim(error.response.data, '\n') : undefined}. Try ${retryNo+1} of ${maxRetries+1}.`; + if (retryNo < maxRetries) { + logger.log(`${logMessage} Retrying…`); + return nodeManager.changeNodes() + .then(function () { + return module.exports(nodeManager)(passPhrase, address, amount, isAmountInADM, maxRetries, ++retryNo) + }) + } + logger.warn(`${logMessage} No more attempts, returning error.`); + return { + success: false, + response: error.response, + status: error.response ? error.response.status : undefined, + statusText: error.response ? error.response.statusText : undefined, + error: error.toString(), + message: error.response ? _.trim(error.response.data, '\n') : undefined + } + }) + + } +}; diff --git a/helpers/constants.js b/helpers/constants.js index 821fc52..5a1cc8c 100644 --- a/helpers/constants.js +++ b/helpers/constants.js @@ -27,6 +27,12 @@ module.exports = { STATE: 9 }, maxVotesPerTransaction: 33, - sat: 100000000 + SAT: 100000000, + RE_BASE64 = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$/, + RE_ADM_ADDRESS = /^U([0-9]{6,})$/i, + RE_BTC_ADDRESS = /^(bc1|[13])[a-km-zA-HJ-NP-Z02-9]{25,39}$/, + RE_DASH_ADDRESS = /^[7X][1-9A-HJ-NP-Za-km-z]{33,}$/, + RE_DOGE_ADDRESS = /^[A|D|9][A-Z0-9]([0-9a-zA-Z]{9,})$/, + RE_LSK_ADDRESS = /^[0-9]{2,21}L$/ , } diff --git a/helpers/validator.js b/helpers/validator.js new file mode 100644 index 0000000..20e561c --- /dev/null +++ b/helpers/validator.js @@ -0,0 +1,38 @@ +const constants = require('./constants'); + +module.exports = { + + validatePassPhrase(passPhrase) { + if (!passPhrase || typeof(passPhrase) !== 'string' || passPhrase.length < 30) + return false + else + return true + }, + + validateAdmAddress(address) { + if (!address || typeof(address) !== 'string' || !constants.RE_ADM_ADDRESS.test(address)) + return false + else + return true + }, + + validateIntegerAmount(amount) { + console.log(amount, typeof(amount)) + if (!amount || typeof(amount) !== 'number' || isNaN(amount) || !isSafeInteger(amount)) + return false + else + return true + }, + + badParameter(name, value) { + return new Promise((resolve, reject) => { + reject({ + success: false, + error: 'Bad parameters', + message: `Wrong ${name} parameter${value ? ': ' + value : ''}` + }) + }) + } + + +}; diff --git a/index.js b/index.js index 5f9a755..77005b2 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ const get = require('./groups/get'); const decodeMsg = require('./groups/decodeMsg'); const Send = require('./groups/send'); +const sendTokens = require('./groups/sendTokens'); const healthCheck = require('./helpers/healthCheck'); const eth = require('./groups/eth'); const transactionFormer = require('./helpers/transactionFormer'); @@ -17,6 +18,7 @@ module.exports = (params, log) => { return { get: get(nodeManager), // send: Send(node), + sendTokens: sendTokens(nodeManager), decodeMsg, eth, transactionFormer, From de59dbd2921f2b574cac9c1ef523e292bdd9f5bd Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 15 May 2021 18:06:34 +0300 Subject: [PATCH 17/57] Fixes --- groups/sendTokens.js | 4 ++-- helpers/constants.js | 13 ++++++------- helpers/validator.js | 7 +++++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/groups/sendTokens.js b/groups/sendTokens.js index 301e184..ca12c1e 100644 --- a/groups/sendTokens.js +++ b/groups/sendTokens.js @@ -21,14 +21,14 @@ module.exports = (nodeManager) => { const keyPair = keys.createKeypairFromPassPhrase(passPhrase); if (!validator.validateAdmAddress(address)) - return badParameter('address') + return validator.badParameter('address', address) if (isAmountInADM) { amount = parseInt(parseFloat(String(amount)) * constants.SAT) } if (!validator.validateIntegerAmount(amount)) - return badParameter('amount') + return validator.badParameter('amount', amount) const data = { keyPair, diff --git a/helpers/constants.js b/helpers/constants.js index 5a1cc8c..1f3b34b 100644 --- a/helpers/constants.js +++ b/helpers/constants.js @@ -28,11 +28,10 @@ module.exports = { }, maxVotesPerTransaction: 33, SAT: 100000000, - RE_BASE64 = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$/, - RE_ADM_ADDRESS = /^U([0-9]{6,})$/i, - RE_BTC_ADDRESS = /^(bc1|[13])[a-km-zA-HJ-NP-Z02-9]{25,39}$/, - RE_DASH_ADDRESS = /^[7X][1-9A-HJ-NP-Za-km-z]{33,}$/, - RE_DOGE_ADDRESS = /^[A|D|9][A-Z0-9]([0-9a-zA-Z]{9,})$/, - RE_LSK_ADDRESS = /^[0-9]{2,21}L$/ , - + RE_BASE64: /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$/, + RE_ADM_ADDRESS: /^U([0-9]{6,})$/, + RE_BTC_ADDRESS: /^(bc1|[13])[a-km-zA-HJ-NP-Z02-9]{25,39}$/, + RE_DASH_ADDRESS: /^[7X][1-9A-HJ-NP-Za-km-z]{33,}$/, + RE_DOGE_ADDRESS: /^[A|D|9][A-Z0-9]([0-9a-zA-Z]{9,})$/, + RE_LSK_ADDRESS: /^[0-9]{2,21}L$/ } diff --git a/helpers/validator.js b/helpers/validator.js index 20e561c..f1da2c6 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -3,6 +3,7 @@ const constants = require('./constants'); module.exports = { validatePassPhrase(passPhrase) { + console.log(passPhrase) if (!passPhrase || typeof(passPhrase) !== 'string' || passPhrase.length < 30) return false else @@ -10,6 +11,7 @@ module.exports = { }, validateAdmAddress(address) { + console.log(address) if (!address || typeof(address) !== 'string' || !constants.RE_ADM_ADDRESS.test(address)) return false else @@ -17,7 +19,7 @@ module.exports = { }, validateIntegerAmount(amount) { - console.log(amount, typeof(amount)) + console.log(amount, typeof(amount)) if (!amount || typeof(amount) !== 'number' || isNaN(amount) || !isSafeInteger(amount)) return false else @@ -25,8 +27,9 @@ module.exports = { }, badParameter(name, value) { + console.log('bad param', name, value) return new Promise((resolve, reject) => { - reject({ + resolve({ success: false, error: 'Bad parameters', message: `Wrong ${name} parameter${value ? ': ' + value : ''}` From f336176f06d4e6ae1b4c0d58b3a200943f8125f9 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 15 May 2021 18:40:22 +0300 Subject: [PATCH 18/57] Fix validator --- groups/sendTokens.js | 12 +++++++++--- helpers/validator.js | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/groups/sendTokens.js b/groups/sendTokens.js index ca12c1e..042952f 100644 --- a/groups/sendTokens.js +++ b/groups/sendTokens.js @@ -5,6 +5,7 @@ const keys = require('../helpers/keys'); const constants = require('../helpers/constants'); const transactionFormer = require('../helpers/transactionFormer'); const validator = require('../helpers/validator'); +const BigNumber = require('bignumber.js') const DEFAULT_SEND_TOKENS_RETRIES = 4; // How much re-tries for send tokens requests by default. Total 4+1 tries @@ -24,16 +25,21 @@ module.exports = (nodeManager) => { return validator.badParameter('address', address) if (isAmountInADM) { - amount = parseInt(parseFloat(String(amount)) * constants.SAT) + // amount = parseInt(parseFloat(String(amount)) * constants.SAT) + amountInSat = BigNumber(String(amount)).multipliedBy(constants.SAT).toNumber() + console.log('BigNumber(String(amount)).multipliedBy(constants.SAT)', BigNumber(String(amount)).multipliedBy(constants.SAT)) + console.log('BigNumber(String(amount)).multipliedBy(constants.SAT)', BigNumber(String(amount)).multipliedBy(constants.SAT).toNumber()) + } else { + amountInSat = amount } - if (!validator.validateIntegerAmount(amount)) + if (!validator.validateIntegerAmount(amountInSat)) return validator.badParameter('amount', amount) const data = { keyPair, recipientId: address, - amount + amount: amountInSat }; transaction = transactionFormer.createTransaction(constants.transactionTypes.SEND, data); diff --git a/helpers/validator.js b/helpers/validator.js index f1da2c6..c7610e1 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -20,7 +20,7 @@ module.exports = { validateIntegerAmount(amount) { console.log(amount, typeof(amount)) - if (!amount || typeof(amount) !== 'number' || isNaN(amount) || !isSafeInteger(amount)) + if (!amount || typeof(amount) !== 'number' || isNaN(amount) || !Number.isSafeInteger(amount)) return false else return true From 9df457b639f8e30eda63166197c10110c4e1620e Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 22 May 2021 22:56:20 +0300 Subject: [PATCH 19/57] Fix healthCheck when no available nodes --- helpers/healthCheck.js | 73 +++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/helpers/healthCheck.js b/helpers/healthCheck.js index 53b304d..cba0c1e 100644 --- a/helpers/healthCheck.js +++ b/helpers/healthCheck.js @@ -89,45 +89,46 @@ async function checkNodes(forceChangeActiveNode) { const count = this.liveNodes.length; if (!count) { logger.error(`[ADAMANT js-api] Health check: All of ${this.nodesList.length} nodes are unavailable. Check internet connection and nodes list in config.`); - return; - } - - // Set activeNode to one that have maximum height and minimum ping - if (count === 1) { - this.activeNode = this.liveNodes[0].node; - } else if (count === 2) { - const h0 = this.liveNodes[0]; - const h1 = this.liveNodes[1]; - this.activeNode = h0.height > h1.height ? h0.node : h1.node; - // Mark node outOfSync if needed - if (h0.heightEpsilon > h1.heightEpsilon) { - this.liveNodes[1].outOfSync = true - } else if (h0.heightEpsilon < h1.heightEpsilon) { - this.liveNodes[0].outOfSync = true - } } else { - let biggestGroup = []; - const groups = _.groupBy(this.liveNodes, n => n.heightEpsilon); - Object.keys(groups).forEach(key => { - if (groups[key].length > biggestGroup.length) { - biggestGroup = groups[key]; + + // Set activeNode to one that have maximum height and minimum ping + if (count === 1) { + this.activeNode = this.liveNodes[0].node; + } else if (count === 2) { + const h0 = this.liveNodes[0]; + const h1 = this.liveNodes[1]; + this.activeNode = h0.height > h1.height ? h0.node : h1.node; + // Mark node outOfSync if needed + if (h0.heightEpsilon > h1.heightEpsilon) { + this.liveNodes[1].outOfSync = true + } else if (h0.heightEpsilon < h1.heightEpsilon) { + this.liveNodes[0].outOfSync = true } - }); - // All the nodes from the biggestGroup list are considered to be in sync, all the others are not - this.liveNodes.forEach(node => { - node.outOfSync = !biggestGroup.includes(node) - }) - biggestGroup.sort((a, b) => a.ping - b.ping); - this.liveNodes.sort((a, b) => a.ping - b.ping); - - if (this.activeNode === biggestGroup[0].node && forceChangeActiveNode) - this.activeNode = biggestGroup[_.random(1, biggestGroup.length-1)].node // Use random node from which are synced - else - this.activeNode = biggestGroup[0].node; // Use node with minimum ping among which are synced + } else { + let biggestGroup = []; + const groups = _.groupBy(this.liveNodes, n => n.heightEpsilon); + Object.keys(groups).forEach(key => { + if (groups[key].length > biggestGroup.length) { + biggestGroup = groups[key]; + } + }); + // All the nodes from the biggestGroup list are considered to be in sync, all the others are not + this.liveNodes.forEach(node => { + node.outOfSync = !biggestGroup.includes(node) + }) + biggestGroup.sort((a, b) => a.ping - b.ping); + this.liveNodes.sort((a, b) => a.ping - b.ping); + + if (this.activeNode === biggestGroup[0].node && forceChangeActiveNode) + this.activeNode = biggestGroup[_.random(1, biggestGroup.length-1)].node // Use random node from which are synced + else + this.activeNode = biggestGroup[0].node; // Use node with minimum ping among which are synced + } + socket.reviseConnection(this.liveNodes); + logger.log(`[ADAMANT js-api] Health check: Found ${this.liveNodes.length} supported nodes. Active node is ${this.activeNode}.`); + } - socket.reviseConnection(this.liveNodes); - logger.log(`[ADAMANT js-api] Health check: Found ${this.liveNodes.length} supported nodes. Active node is ${this.activeNode}.`); - + } catch (e) { logger.warn('[ADAMANT js-api] Health check: Error in checkNodes()', e); } From 2e04c54118cab3e3338f983cedaf3272712fffd7 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 22 May 2021 23:03:45 +0300 Subject: [PATCH 20/57] Clean up --- helpers/validator.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/helpers/validator.js b/helpers/validator.js index c7610e1..68d2428 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -3,7 +3,6 @@ const constants = require('./constants'); module.exports = { validatePassPhrase(passPhrase) { - console.log(passPhrase) if (!passPhrase || typeof(passPhrase) !== 'string' || passPhrase.length < 30) return false else @@ -11,7 +10,6 @@ module.exports = { }, validateAdmAddress(address) { - console.log(address) if (!address || typeof(address) !== 'string' || !constants.RE_ADM_ADDRESS.test(address)) return false else @@ -19,7 +17,6 @@ module.exports = { }, validateIntegerAmount(amount) { - console.log(amount, typeof(amount)) if (!amount || typeof(amount) !== 'number' || isNaN(amount) || !Number.isSafeInteger(amount)) return false else @@ -27,7 +24,6 @@ module.exports = { }, badParameter(name, value) { - console.log('bad param', name, value) return new Promise((resolve, reject) => { resolve({ success: false, From 24ffc4116df179e737fbe681d34943ab01bdbc8f Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 22 May 2021 23:04:57 +0300 Subject: [PATCH 21/57] Clean up --- groups/sendTokens.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/groups/sendTokens.js b/groups/sendTokens.js index 042952f..e06b47b 100644 --- a/groups/sendTokens.js +++ b/groups/sendTokens.js @@ -27,8 +27,6 @@ module.exports = (nodeManager) => { if (isAmountInADM) { // amount = parseInt(parseFloat(String(amount)) * constants.SAT) amountInSat = BigNumber(String(amount)).multipliedBy(constants.SAT).toNumber() - console.log('BigNumber(String(amount)).multipliedBy(constants.SAT)', BigNumber(String(amount)).multipliedBy(constants.SAT)) - console.log('BigNumber(String(amount)).multipliedBy(constants.SAT)', BigNumber(String(amount)).multipliedBy(constants.SAT).toNumber()) } else { amountInSat = amount } @@ -50,18 +48,9 @@ module.exports = (nodeManager) => { } - console.log(transaction, transaction) - - const params = { - json: { - transaction - } - }; - let url = nodeManager.node() + '/api/transactions/process'; - return axios.post(url, { params }) + return axios.post(url, { transaction }) .then(function (response) { - console.log('done', response) return { success: true, response: response, @@ -71,7 +60,6 @@ module.exports = (nodeManager) => { } }) .catch(function (error) { - console.log('error', error) let logMessage = `[ADAMANT js-api] Send tokens request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}. Message: ${error.response ? _.trim(error.response.data, '\n') : undefined}. Try ${retryNo+1} of ${maxRetries+1}.`; if (retryNo < maxRetries) { logger.log(`${logMessage} Retrying…`); From 29597b0977edec79a5506d966198656a32a56728 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sun, 23 May 2021 12:40:04 +0300 Subject: [PATCH 22/57] Fix non-integer amount --- groups/sendTokens.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/groups/sendTokens.js b/groups/sendTokens.js index e06b47b..87cffb5 100644 --- a/groups/sendTokens.js +++ b/groups/sendTokens.js @@ -26,7 +26,7 @@ module.exports = (nodeManager) => { if (isAmountInADM) { // amount = parseInt(parseFloat(String(amount)) * constants.SAT) - amountInSat = BigNumber(String(amount)).multipliedBy(constants.SAT).toNumber() + amountInSat = BigNumber(String(amount)).multipliedBy(constants.SAT).integerValue().toNumber() } else { amountInSat = amount } From a81c7f7751d113a34a76a03e1e7d3106131ab1fe Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sun, 23 May 2021 14:46:37 +0300 Subject: [PATCH 23/57] Add getPublicKey() --- groups/getPublicKey.js | 28 +++++++++++++ groups/sendMessage.js | 94 ++++++++++++++++++++++++++++++++++++++++++ helpers/validator.js | 19 +++++++++ index.js | 2 + 4 files changed, 143 insertions(+) create mode 100644 groups/getPublicKey.js create mode 100644 groups/sendMessage.js diff --git a/groups/getPublicKey.js b/groups/getPublicKey.js new file mode 100644 index 0000000..8cdeea2 --- /dev/null +++ b/groups/getPublicKey.js @@ -0,0 +1,28 @@ +const get = require('./get'); +const logger = require('../helpers/logger'); + +module.exports = (nodeManager) => { + + return (address) => { + + try { + + const publicKey = await get(nodeManager)('/accounts/getPublicKey', { address }); + if (publicKey.success) { + if (publicKey.result.success) { + console.log('publicKey.result', publicKey.result) + // return votesCount + } else { + logger.warn(`Unable to get public key for ${address}. Node's reply: ${publicKey.result.error}.`); + } + } else { + logger.warn(`Failed to get public key for ${address}, ${publicKey.error}. Message: ${publicKey.message}.`); + } + + } catch (e) { + logger.error(`Error while fetching public key for ${address}:`, e); + } + + } + +}; diff --git a/groups/sendMessage.js b/groups/sendMessage.js new file mode 100644 index 0000000..b4afa4a --- /dev/null +++ b/groups/sendMessage.js @@ -0,0 +1,94 @@ +const axios = require('axios'); +const _ = require('lodash'); +const logger = require('../helpers/logger'); +const keys = require('../helpers/keys'); +const constants = require('../helpers/constants'); +const transactionFormer = require('../helpers/transactionFormer'); +const validator = require('../helpers/validator'); +const getPublicKey = require('./getPublicKey'); + +const DEFAULT_SEND_MESSAGE_RETRIES = 4; // How much re-tries for send message requests by default. Total 4+1 tries + +module.exports = (nodeManager) => { + return (passPhrase, address, message, message_type = 1, tokensAmount, maxRetries = DEFAULT_SEND_MESSAGE_RETRIES, retryNo = 0) => { + + let transaction; + + try { + + if (!validator.validatePassPhrase(passPhrase)) + return validator.badParameter('passPhrase') + + const keyPair = keys.createKeypairFromPassPhrase(passPhrase); + + if (!validator.validateAdmAddress(address)) + return validator.badParameter('address', address) + + if (message_type === 'rich') + message_type = 2; + if (message_type === 'signal') + message_type = 3; + + if (!validator.validateMessageType(message_type)) + return validator.badParameter('message_type', message_type) + + const data = { + keyPair, + recipientId: address, + message_type + }; + + if (tokensAmount) { + tokensAmount = tokensAmount.toString(); + if (!validator.validateStringAmount(tokensAmount)) + return validator.badParameter('tokensAmount', tokensAmount) + data.amount = tokensAmount; + } + + + + // transaction = transactionFormer.createTransaction(constants.transactionTypes.SEND, data); + + } catch (e) { + + return validator.badParameter('#exception_catched#', e) + + } + + let publicKey = getPublicKey(nodeManager)(address); + console.log('publicKey', publicKey) + return; + + let url = nodeManager.node() + '/api/transactions/process'; + return axios.post(url, { transaction }) + .then(function (response) { + return { + success: true, + response: response, + status: response.status, + statusText: response.statusText, + result: response.data + } + }) + .catch(function (error) { + let logMessage = `[ADAMANT js-api] Send tokens request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}. Message: ${error.response ? _.trim(error.response.data, '\n') : undefined}. Try ${retryNo+1} of ${maxRetries+1}.`; + if (retryNo < maxRetries) { + logger.log(`${logMessage} Retrying…`); + return nodeManager.changeNodes() + .then(function () { + return module.exports(nodeManager)(passPhrase, address, amount, isAmountInADM, maxRetries, ++retryNo) + }) + } + logger.warn(`${logMessage} No more attempts, returning error.`); + return { + success: false, + response: error.response, + status: error.response ? error.response.status : undefined, + statusText: error.response ? error.response.statusText : undefined, + error: error.toString(), + message: error.response ? _.trim(error.response.data, '\n') : undefined + } + }) + + } +}; diff --git a/helpers/validator.js b/helpers/validator.js index 68d2428..d3f13e1 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -2,6 +2,11 @@ const constants = require('./constants'); module.exports = { + isNumeric(str) { + if (typeof str !== "string") return false + return !isNaN(str) && !isNaN(parseFloat(str)) + }, + validatePassPhrase(passPhrase) { if (!passPhrase || typeof(passPhrase) !== 'string' || passPhrase.length < 30) return false @@ -23,6 +28,20 @@ module.exports = { return true }, + validateStringAmount(amount) { + if (!amount || !this.isNumeric(amount)) + return false + else + return true + }, + + validateMessageType(message_type) { + if (!message_type || typeof(message_type) !== 'number' || ![1,2,3].includes(message_type)) + return false + else + return true + }, + badParameter(name, value) { return new Promise((resolve, reject) => { resolve({ diff --git a/index.js b/index.js index 77005b2..bdca875 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ const get = require('./groups/get'); +const getPublicKey = require('./groups/getPublicKey'); const decodeMsg = require('./groups/decodeMsg'); const Send = require('./groups/send'); const sendTokens = require('./groups/sendTokens'); @@ -17,6 +18,7 @@ module.exports = (params, log) => { return { get: get(nodeManager), + getPublicKey: getPublicKey(nodeManager), // send: Send(node), sendTokens: sendTokens(nodeManager), decodeMsg, From bd2c6657994d90d79881b89198805f0d724a3db3 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sun, 23 May 2021 15:08:20 +0300 Subject: [PATCH 24/57] Async getPublicKey() --- groups/getPublicKey.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/groups/getPublicKey.js b/groups/getPublicKey.js index 8cdeea2..c179696 100644 --- a/groups/getPublicKey.js +++ b/groups/getPublicKey.js @@ -3,24 +3,26 @@ const logger = require('../helpers/logger'); module.exports = (nodeManager) => { - return (address) => { + return async (address) => { try { const publicKey = await get(nodeManager)('/accounts/getPublicKey', { address }); if (publicKey.success) { if (publicKey.result.success) { - console.log('publicKey.result', publicKey.result) - // return votesCount + return publicKey.result.publicKey } else { logger.warn(`Unable to get public key for ${address}. Node's reply: ${publicKey.result.error}.`); + return false } } else { logger.warn(`Failed to get public key for ${address}, ${publicKey.error}. Message: ${publicKey.message}.`); + return false } } catch (e) { logger.error(`Error while fetching public key for ${address}:`, e); + return false } } From d991703061e1f87cad5a0eb08bfd04750893fefe Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sun, 23 May 2021 15:11:30 +0300 Subject: [PATCH 25/57] Make getPublicKey() public --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index bdca875..01506f6 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,8 @@ const get = require('./groups/get'); const getPublicKey = require('./groups/getPublicKey'); const decodeMsg = require('./groups/decodeMsg'); -const Send = require('./groups/send'); const sendTokens = require('./groups/sendTokens'); +const sendMessage = require('./groups/sendMessage'); const healthCheck = require('./helpers/healthCheck'); const eth = require('./groups/eth'); const transactionFormer = require('./helpers/transactionFormer'); @@ -19,8 +19,8 @@ module.exports = (params, log) => { return { get: get(nodeManager), getPublicKey: getPublicKey(nodeManager), - // send: Send(node), sendTokens: sendTokens(nodeManager), + sendMessage: sendMessage(nodeManager), decodeMsg, eth, transactionFormer, From 3f592d5b6203262e019a072f3d09d34966260e30 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sun, 23 May 2021 15:29:07 +0300 Subject: [PATCH 26/57] Add validateMessage() --- helpers/validator.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/helpers/validator.js b/helpers/validator.js index d3f13e1..2035690 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -42,6 +42,13 @@ module.exports = { return true }, + validateMessage(message) { + if (typeof(message) !== 'string') + return false + else + return true + }, + badParameter(name, value) { return new Promise((resolve, reject) => { resolve({ @@ -52,5 +59,4 @@ module.exports = { }) } - }; From 9e4e34c6790f2882d27e709128d19d8e95ff1343 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sun, 23 May 2021 15:55:40 +0300 Subject: [PATCH 27/57] Add sendMessage() --- groups/sendMessage.js | 120 +++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 42 deletions(-) diff --git a/groups/sendMessage.js b/groups/sendMessage.js index b4afa4a..39a2783 100644 --- a/groups/sendMessage.js +++ b/groups/sendMessage.js @@ -3,6 +3,7 @@ const _ = require('lodash'); const logger = require('../helpers/logger'); const keys = require('../helpers/keys'); const constants = require('../helpers/constants'); +const encryptor = require('../helpers/encryptor'); const transactionFormer = require('../helpers/transactionFormer'); const validator = require('../helpers/validator'); const getPublicKey = require('./getPublicKey'); @@ -12,14 +13,14 @@ const DEFAULT_SEND_MESSAGE_RETRIES = 4; // How much re-tries for send message re module.exports = (nodeManager) => { return (passPhrase, address, message, message_type = 1, tokensAmount, maxRetries = DEFAULT_SEND_MESSAGE_RETRIES, retryNo = 0) => { - let transaction; + let keyPair, data; try { if (!validator.validatePassPhrase(passPhrase)) return validator.badParameter('passPhrase') - const keyPair = keys.createKeypairFromPassPhrase(passPhrase); + keyPair = keys.createKeypairFromPassPhrase(passPhrase); if (!validator.validateAdmAddress(address)) return validator.badParameter('address', address) @@ -32,7 +33,10 @@ module.exports = (nodeManager) => { if (!validator.validateMessageType(message_type)) return validator.badParameter('message_type', message_type) - const data = { + if (!validator.validateMessage(message)) + return validator.badParameter('message', message) + + data = { keyPair, recipientId: address, message_type @@ -45,50 +49,82 @@ module.exports = (nodeManager) => { data.amount = tokensAmount; } - - - // transaction = transactionFormer.createTransaction(constants.transactionTypes.SEND, data); - } catch (e) { return validator.badParameter('#exception_catched#', e) } - let publicKey = getPublicKey(nodeManager)(address); - console.log('publicKey', publicKey) - return; - - let url = nodeManager.node() + '/api/transactions/process'; - return axios.post(url, { transaction }) - .then(function (response) { - return { - success: true, - response: response, - status: response.status, - statusText: response.statusText, - result: response.data - } - }) - .catch(function (error) { - let logMessage = `[ADAMANT js-api] Send tokens request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}. Message: ${error.response ? _.trim(error.response.data, '\n') : undefined}. Try ${retryNo+1} of ${maxRetries+1}.`; - if (retryNo < maxRetries) { - logger.log(`${logMessage} Retrying…`); - return nodeManager.changeNodes() - .then(function () { - return module.exports(nodeManager)(passPhrase, address, amount, isAmountInADM, maxRetries, ++retryNo) - }) - } - logger.warn(`${logMessage} No more attempts, returning error.`); - return { - success: false, - response: error.response, - status: error.response ? error.response.status : undefined, - statusText: error.response ? error.response.statusText : undefined, - error: error.toString(), - message: error.response ? _.trim(error.response.data, '\n') : undefined - } - }) - + return getPublicKey(nodeManager)(address) + .then((publicKey) => { + + if (publicKey) { + + try { + + const encryptedMessage = encryptor.encodeMessage(message, keyPair, publicKey); + console.log(encryptedMessage) + data.message = encryptedMessage.message; + data.own_message = encryptedMessage.own_message; + + let transaction = transactionFormer.createTransaction(constants.transactionTypes.CHAT_MESSAGE, data); + + let url = nodeManager.node() + '/api/transactions/process'; + return axios.post(url, { transaction }) + .then(function (response) { + return { + success: true, + response: response, + status: response.status, + statusText: response.statusText, + result: response.data + } + }) + .catch(function (error) { + let logMessage = `[ADAMANT js-api] Send message request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}. Message: ${error.response ? _.trim(error.response.data, '\n') : undefined}. Try ${retryNo+1} of ${maxRetries+1}.`; + if (retryNo < maxRetries) { + logger.log(`${logMessage} Retrying…`); + return nodeManager.changeNodes() + .then(function () { + return module.exports(nodeManager)(passPhrase, address, message, message_type, tokensAmount, maxRetries, ++retryNo) + }) + } + logger.warn(`${logMessage} No more attempts, returning error.`); + return { + success: false, + response: error.response, + status: error.response ? error.response.status : undefined, + statusText: error.response ? error.response.statusText : undefined, + error: error.toString(), + message: error.response ? _.trim(error.response.data, '\n') : undefined + } + }) + + } catch (e) { + + return new Promise((resolve, reject) => { + resolve({ + success: false, + error: 'Failed to process a message', + message: `Unable to encode message '${message}' with public key ${publicKey}, or unable to build a transaction. Exception: ` + e + }) + }) + + } + + } else { + + return new Promise((resolve, reject) => { + resolve({ + success: false, + error: 'No public key', + message: `Unable to get public key for ${address}. It is necessary for sending an encrypted message. Account may be uninitialized (https://medium.com/adamant-im/chats-and-uninitialized-accounts-in-adamant-5035438e2fcd), or network error` + }) + }) + + } // if (publicKey) + + }) // getPublicKey.then } + }; From 6f4b4c3344545bebf5d97da590f26898a3ff3c08 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sun, 23 May 2021 19:40:25 +0300 Subject: [PATCH 28/57] Add AdmToSats() --- helpers/validator.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/helpers/validator.js b/helpers/validator.js index 2035690..1aeb037 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -1,4 +1,5 @@ const constants = require('./constants'); +const BigNumber = require('bignumber.js') module.exports = { @@ -49,6 +50,10 @@ module.exports = { return true }, + AdmToSats(amount) { + return BigNumber(String(amount)).multipliedBy(constants.SAT).integerValue().toNumber() + }, + badParameter(name, value) { return new Promise((resolve, reject) => { resolve({ From 0f9d13900e1715758befe67b34ae597dc374420e Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sun, 23 May 2021 19:41:33 +0300 Subject: [PATCH 29/57] Update sendTokens --- groups/sendTokens.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/groups/sendTokens.js b/groups/sendTokens.js index 87cffb5..f2b06d9 100644 --- a/groups/sendTokens.js +++ b/groups/sendTokens.js @@ -5,7 +5,6 @@ const keys = require('../helpers/keys'); const constants = require('../helpers/constants'); const transactionFormer = require('../helpers/transactionFormer'); const validator = require('../helpers/validator'); -const BigNumber = require('bignumber.js') const DEFAULT_SEND_TOKENS_RETRIES = 4; // How much re-tries for send tokens requests by default. Total 4+1 tries @@ -25,8 +24,7 @@ module.exports = (nodeManager) => { return validator.badParameter('address', address) if (isAmountInADM) { - // amount = parseInt(parseFloat(String(amount)) * constants.SAT) - amountInSat = BigNumber(String(amount)).multipliedBy(constants.SAT).integerValue().toNumber() + amountInSat = validator.AdmToSats(amount) } else { amountInSat = amount } From e66d090d0e6548cf0eccbe6cdcef652e8a7838c1 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 12:31:38 +0300 Subject: [PATCH 30/57] validateMessage() with JSON --- helpers/validator.js | 52 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/helpers/validator.js b/helpers/validator.js index 1aeb037..36ed432 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -8,6 +8,16 @@ module.exports = { return !isNaN(str) && !isNaN(parseFloat(str)) }, + tryParseJSON(jsonString) { + try { + let o = JSON.parse(jsonString); + if (o && typeof o === "object") { + return o; + } + } catch (e) { } + return false + }, + validatePassPhrase(passPhrase) { if (!passPhrase || typeof(passPhrase) !== 'string' || passPhrase.length < 30) return false @@ -43,23 +53,53 @@ module.exports = { return true }, - validateMessage(message) { + validateMessage(message, message_type) { if (typeof(message) !== 'string') - return false - else - return true + return { + result: false, + error: `Message must be a string` + } + else { + if (message_type === 2 || message_type === 3) { + + let json = this.tryParseJSON(message) + + if (!json) + return { + result: false, + error: `For rich and signal messages, 'message' must be a JSON string` + } + + if (json.type && json.type.toLowerCase().includes('_transaction')) + if (json.type.toLowerCase() !== json.type) + return { + result: false, + error: `Value '_transaction' must be in lower case` + } + + if (typeof json.amount !== 'string' || !this.validateStringAmount(json.amount)) + return { + result: false, + error: `Field 'amount' must be a string, representing a number` + } + + } + } + return { + result: true + } }, AdmToSats(amount) { return BigNumber(String(amount)).multipliedBy(constants.SAT).integerValue().toNumber() }, - badParameter(name, value) { + badParameter(name, value, customMessage) { return new Promise((resolve, reject) => { resolve({ success: false, error: 'Bad parameters', - message: `Wrong ${name} parameter${value ? ': ' + value : ''}` + message: `Wrong '${name}' parameter${value ? ': ' + value : ''}${customMessage ? '. Error: ' + customMessage : ''}` }) }) } From ec5c4bd92e9d786ea41178a95874c02ed04e8ace Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 12:32:46 +0300 Subject: [PATCH 31/57] Allow sendMessage to send ADM tokens --- groups/sendMessage.js | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/groups/sendMessage.js b/groups/sendMessage.js index 39a2783..a13adf2 100644 --- a/groups/sendMessage.js +++ b/groups/sendMessage.js @@ -11,7 +11,20 @@ const getPublicKey = require('./getPublicKey'); const DEFAULT_SEND_MESSAGE_RETRIES = 4; // How much re-tries for send message requests by default. Total 4+1 tries module.exports = (nodeManager) => { - return (passPhrase, address, message, message_type = 1, tokensAmount, maxRetries = DEFAULT_SEND_MESSAGE_RETRIES, retryNo = 0) => { + /** + * Sends encrypted basic, rich, or signal message + * See https://github.com/Adamant-im/adamant/wiki/Message-Types + * @param {string} passPhrase Senders's passPhrase. Sender's address will be derived from it. + * @param {string} address Recipient's ADAMANT address + * @param {string} message Message plain text in case of basic message. Stringified JSON in case of rich or signal messages. + * Example of rich message for token transfer: `{"type":"eth_transaction","amount":"0.002","hash":"0xfa46d2b3c99878f1f9863fcbdb0bc27d220d7065c6528543cbb83ced84487deb","comments":"I like to send it, send it"}` + * @param {string, number} message_type Type of message: basic, rich, or signal + * @param {string, number} amount Amount to send with a message + * @param {boolean} isAmountInADM If amount specified in ADM, or in sats (10^-8 ADM) + * @param {number} maxRetries How much times to retry request + * @returns {Promise} Request results + */ + return (passPhrase, address, message, message_type = 'basic', amount, isAmountInADM = true, maxRetries = DEFAULT_SEND_MESSAGE_RETRIES, retryNo = 0) => { let keyPair, data; @@ -25,6 +38,8 @@ module.exports = (nodeManager) => { if (!validator.validateAdmAddress(address)) return validator.badParameter('address', address) + if (message_type === 'basic') + message_type = 1; if (message_type === 'rich') message_type = 2; if (message_type === 'signal') @@ -33,8 +48,9 @@ module.exports = (nodeManager) => { if (!validator.validateMessageType(message_type)) return validator.badParameter('message_type', message_type) - if (!validator.validateMessage(message)) - return validator.badParameter('message', message) + let messageValidation = validator.validateMessage(message, message_type); + if (!messageValidation.result) + return validator.badParameter('message', message, messageValidation.error) data = { keyPair, @@ -42,11 +58,15 @@ module.exports = (nodeManager) => { message_type }; - if (tokensAmount) { - tokensAmount = tokensAmount.toString(); - if (!validator.validateStringAmount(tokensAmount)) - return validator.badParameter('tokensAmount', tokensAmount) - data.amount = tokensAmount; + if (amount) { + if (isAmountInADM) { + amountInSat = validator.AdmToSats(amount) + } else { + amountInSat = amount + } + if (!validator.validateIntegerAmount(amountInSat)) + return validator.badParameter('amount', amount) + data.amount = amountInSat; } } catch (e) { From 07040b5aa3be93779157945abec2008037978612 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 13:51:20 +0300 Subject: [PATCH 32/57] Add formatRequestResults() --- groups/get.js | 18 +++--------------- groups/sendMessage.js | 17 ++--------------- groups/sendTokens.js | 17 ++--------------- helpers/validator.js | 27 +++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 45 deletions(-) diff --git a/groups/get.js b/groups/get.js index d572113..3e8f317 100644 --- a/groups/get.js +++ b/groups/get.js @@ -1,6 +1,7 @@ const axios = require('axios'); const _ = require('lodash'); const logger = require('../helpers/logger'); +const validator = require('../helpers/validator'); const DEFAULT_GET_REQUEST_RETRIES = 3; // How much re-tries for get-requests by default. Total 3+1 tries @@ -20,13 +21,7 @@ module.exports = (nodeManager) => { url = nodeManager.node() + '/api/' + url; return axios.get(url, { params }) .then(function (response) { - return { - success: true, - response: response, - status: response.status, - statusText: response.statusText, - result: response.data - } + return validator.formatRequestResults(response, true) }) .catch(function (error) { let logMessage = `[ADAMANT js-api] Get-request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}. Message: ${error.response ? _.trim(error.response.data, '\n') : undefined}. Try ${retryNo+1} of ${maxRetries+1}.`; @@ -38,14 +33,7 @@ module.exports = (nodeManager) => { }) } logger.warn(`${logMessage} No more attempts, returning error.`); - return { - success: false, - response: error.response, - status: error.response ? error.response.status : undefined, - statusText: error.response ? error.response.statusText : undefined, - error: error.toString(), - message: error.response ? _.trim(error.response.data, '\n') : undefined - } + return validator.formatRequestResults(error, false) }) } diff --git a/groups/sendMessage.js b/groups/sendMessage.js index a13adf2..f15bf24 100644 --- a/groups/sendMessage.js +++ b/groups/sendMessage.js @@ -92,13 +92,7 @@ module.exports = (nodeManager) => { let url = nodeManager.node() + '/api/transactions/process'; return axios.post(url, { transaction }) .then(function (response) { - return { - success: true, - response: response, - status: response.status, - statusText: response.statusText, - result: response.data - } + return validator.formatRequestResults(response, true) }) .catch(function (error) { let logMessage = `[ADAMANT js-api] Send message request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}. Message: ${error.response ? _.trim(error.response.data, '\n') : undefined}. Try ${retryNo+1} of ${maxRetries+1}.`; @@ -110,14 +104,7 @@ module.exports = (nodeManager) => { }) } logger.warn(`${logMessage} No more attempts, returning error.`); - return { - success: false, - response: error.response, - status: error.response ? error.response.status : undefined, - statusText: error.response ? error.response.statusText : undefined, - error: error.toString(), - message: error.response ? _.trim(error.response.data, '\n') : undefined - } + return validator.formatRequestResults(error, false) }) } catch (e) { diff --git a/groups/sendTokens.js b/groups/sendTokens.js index f2b06d9..98c90f0 100644 --- a/groups/sendTokens.js +++ b/groups/sendTokens.js @@ -49,13 +49,7 @@ module.exports = (nodeManager) => { let url = nodeManager.node() + '/api/transactions/process'; return axios.post(url, { transaction }) .then(function (response) { - return { - success: true, - response: response, - status: response.status, - statusText: response.statusText, - result: response.data - } + return validator.formatRequestResults(response, true) }) .catch(function (error) { let logMessage = `[ADAMANT js-api] Send tokens request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}. Message: ${error.response ? _.trim(error.response.data, '\n') : undefined}. Try ${retryNo+1} of ${maxRetries+1}.`; @@ -67,14 +61,7 @@ module.exports = (nodeManager) => { }) } logger.warn(`${logMessage} No more attempts, returning error.`); - return { - success: false, - response: error.response, - status: error.response ? error.response.status : undefined, - statusText: error.response ? error.response.statusText : undefined, - error: error.toString(), - message: error.response ? _.trim(error.response.data, '\n') : undefined - } + return validator.formatRequestResults(error, false) }) } diff --git a/helpers/validator.js b/helpers/validator.js index 36ed432..5be82f7 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -102,6 +102,33 @@ module.exports = { message: `Wrong '${name}' parameter${value ? ': ' + value : ''}${customMessage ? '. Error: ' + customMessage : ''}` }) }) + }, + + formatRequestResults(response, isRequestSuccess) { + let results = {}; + results.details = {}; + + if (isRequestSuccess) { + results.success = response.success && response.data && response.data.success; + results.data = response.data; + results.details.status = response.status; + results.details.statusText = response.statusText; + results.details.response = response; + if (!results.success && results.data) + results.errorMessage = `Node's reply: ${results.data.error}.` + } else { + results.success = false; + results.data = undefined; + results.details.status = response.response ? response.response.status : undefined; + results.details.statusText = response.response ? response.response.statusText : undefined; + results.details.error = response.toString(); + results.details.message = response.response ? _.trim(response.response.data, '\n') : undefined; + results.details.response = response.response; + results.errorMessage = `${results.details.error}. Message: ${results.details.message}.`; + } + + return results; + } }; From be222c93005f3798cbed8b841c58901de7e8f972 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 14:04:34 +0300 Subject: [PATCH 33/57] Fix formatRequestResults() --- helpers/validator.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/helpers/validator.js b/helpers/validator.js index 5be82f7..f9948f3 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -109,13 +109,13 @@ module.exports = { results.details = {}; if (isRequestSuccess) { - results.success = response.success && response.data && response.data.success; + results.success = response.data && response.data.success; results.data = response.data; results.details.status = response.status; results.details.statusText = response.statusText; results.details.response = response; if (!results.success && results.data) - results.errorMessage = `Node's reply: ${results.data.error}.` + results.errorMessage = `Node's reply: ${results.data.error}` } else { results.success = false; results.data = undefined; @@ -124,7 +124,7 @@ module.exports = { results.details.error = response.toString(); results.details.message = response.response ? _.trim(response.response.data, '\n') : undefined; results.details.response = response.response; - results.errorMessage = `${results.details.error}. Message: ${results.details.message}.`; + results.errorMessage = `${results.details.error}. Message: ${results.details.message}`; } return results; From f58c7a00ace5b1909a432e28e27df33a9920fb29 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 14:15:12 +0300 Subject: [PATCH 34/57] Update errorMessage --- helpers/validator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/validator.js b/helpers/validator.js index f9948f3..0c54397 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -124,7 +124,7 @@ module.exports = { results.details.error = response.toString(); results.details.message = response.response ? _.trim(response.response.data, '\n') : undefined; results.details.response = response.response; - results.errorMessage = `${results.details.error}. Message: ${results.details.message}`; + results.errorMessage = `${results.details.error}${results.details.message ? '. Message: ' + results.details.message : ''}`; } return results; From cf01c0ac85b7a0bf1adecf5f2e847cec557f62a7 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 14:20:59 +0300 Subject: [PATCH 35/57] Update getPublicKey --- groups/getPublicKey.js | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/groups/getPublicKey.js b/groups/getPublicKey.js index c179696..10a602d 100644 --- a/groups/getPublicKey.js +++ b/groups/getPublicKey.js @@ -5,26 +5,14 @@ module.exports = (nodeManager) => { return async (address) => { - try { - - const publicKey = await get(nodeManager)('/accounts/getPublicKey', { address }); + const publicKey = await get(nodeManager)('/accounts/getPublicKey', { address }); if (publicKey.success) { - if (publicKey.result.success) { - return publicKey.result.publicKey - } else { - logger.warn(`Unable to get public key for ${address}. Node's reply: ${publicKey.result.error}.`); - return false - } + return publicKey.data.publicKey } else { - logger.warn(`Failed to get public key for ${address}, ${publicKey.error}. Message: ${publicKey.message}.`); + logger.warn(`[ADAMANT js-api] Failed to get public key for ${address}. ${publicKey.errorMessage}.`); return false } - } catch (e) { - logger.error(`Error while fetching public key for ${address}:`, e); - return false - } - } }; From 9567e3c5bd9b1d60197e94cfc30efd8630a20f2c Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 14:22:36 +0300 Subject: [PATCH 36/57] Update sendMessage --- groups/sendMessage.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/groups/sendMessage.js b/groups/sendMessage.js index f15bf24..9702161 100644 --- a/groups/sendMessage.js +++ b/groups/sendMessage.js @@ -83,7 +83,6 @@ module.exports = (nodeManager) => { try { const encryptedMessage = encryptor.encodeMessage(message, keyPair, publicKey); - console.log(encryptedMessage) data.message = encryptedMessage.message; data.own_message = encryptedMessage.own_message; @@ -112,8 +111,7 @@ module.exports = (nodeManager) => { return new Promise((resolve, reject) => { resolve({ success: false, - error: 'Failed to process a message', - message: `Unable to encode message '${message}' with public key ${publicKey}, or unable to build a transaction. Exception: ` + e + errorMessage: `Unable to encode message '${message}' with public key ${publicKey}, or unable to build a transaction. Exception: ` + e }) }) @@ -124,8 +122,7 @@ module.exports = (nodeManager) => { return new Promise((resolve, reject) => { resolve({ success: false, - error: 'No public key', - message: `Unable to get public key for ${address}. It is necessary for sending an encrypted message. Account may be uninitialized (https://medium.com/adamant-im/chats-and-uninitialized-accounts-in-adamant-5035438e2fcd), or network error` + errorMessage: `Unable to get public key for ${address}. It is necessary for sending an encrypted message. Account may be uninitialized (https://medium.com/adamant-im/chats-and-uninitialized-accounts-in-adamant-5035438e2fcd), or network error` }) }) From 3361846a9c708e7168b6ce80bbc89499bb2bf86c Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 14:23:18 +0300 Subject: [PATCH 37/57] Update validator --- helpers/validator.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/helpers/validator.js b/helpers/validator.js index 0c54397..4cb1450 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -98,8 +98,7 @@ module.exports = { return new Promise((resolve, reject) => { resolve({ success: false, - error: 'Bad parameters', - message: `Wrong '${name}' parameter${value ? ': ' + value : ''}${customMessage ? '. Error: ' + customMessage : ''}` + errorMessage: `Wrong '${name}' parameter${value ? ': ' + value : ''}${customMessage ? '. Error: ' + customMessage : ''}` }) }) }, From 3b22b51f0f5aae787d6a3b4ee4387522a7b82c4c Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 14:28:40 +0300 Subject: [PATCH 38/57] Add validateEndpoint() --- groups/get.js | 10 ++-------- helpers/validator.js | 7 +++++++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/groups/get.js b/groups/get.js index 3e8f317..3906fa6 100644 --- a/groups/get.js +++ b/groups/get.js @@ -9,14 +9,8 @@ module.exports = (nodeManager) => { return (endpoint, params, maxRetries = DEFAULT_GET_REQUEST_RETRIES, retryNo = 0) => { let url = _.trim(endpoint, "/ ") - if (!url || typeof(endpoint) !== 'string') - return new Promise((resolve, reject) => { - reject({ - success: false, - error: 'Bad parameters', - message: `Wrong endpoint parameter: ${endpoint}` - }) - }) + if (!url || !validator.validateEndpoint(endpoint)) + return validator.badParameter('endpoint') url = nodeManager.node() + '/api/' + url; return axios.get(url, { params }) diff --git a/helpers/validator.js b/helpers/validator.js index 4cb1450..a059c5e 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -25,6 +25,13 @@ module.exports = { return true }, + validateEndpoint(endpoint) { + if (!endpoint || typeof(endpoint) !== 'string') + return false + else + return true + }, + validateAdmAddress(address) { if (!address || typeof(address) !== 'string' || !constants.RE_ADM_ADDRESS.test(address)) return false From 40b74493a75d63bc01c95f8cf2216cc2e383d686 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 20:13:50 +0300 Subject: [PATCH 39/57] Replace request with axios --- groups/send.js | 88 ------------------------------------------ helpers/healthCheck.js | 45 +++++++++++---------- 2 files changed, 24 insertions(+), 109 deletions(-) delete mode 100644 groups/send.js diff --git a/groups/send.js b/groups/send.js deleted file mode 100644 index 288eb92..0000000 --- a/groups/send.js +++ /dev/null @@ -1,88 +0,0 @@ -const request = require('sync-request'); -const keys = require('../helpers/keys'); -const encryptor = require('../helpers/encryptor'); -const constants = require('../helpers/constants'); -const logger = require('../helpers/logger'); -const transactionFormer = require('../helpers/transactionFormer'); -const SAT = 100000000; - -module.exports = (hotNode) => { - - return (passPhrase, address, payload, type = 'tokens', isEncode, amount_comment) => { - - const recipientId = address; - const keyPair = keys.createKeypairFromPassPhrase(passPhrase); - - if (type === 'tokens') { - try { - const amount = parseInt(parseFloat(String(payload)) * SAT); - const data = { - keyPair, - recipientId, - amount - }; - const transaction = transactionFormer.createTransaction(constants.transactionTypes.SEND, data); - const res = JSON.parse(request('POST', hotNode() + '/api/transactions/process', { - json: { - transaction - } - }).getBody().toString()); - - return res; - - } catch (e) { - logger.error('Error while sending tokens: ' + e); - return false; - } - - } else if (['message', 'rich', 'signal'].includes(type)) { - - try { - let message_type = 1; - - if (type === 'rich') - message_type = 2; - if (type === 'signal') - message_type = 3; - - const data = { - keyPair, - recipientId, - message_type - }; - - if (amount_comment) { - data.amount = parseInt(parseFloat(String(amount_comment)) * SAT); - } - - const res = request('GET', hotNode() + '/api/accounts/getPublicKey?address=' + recipientId); - const answer = JSON.parse(res.getBody().toString()); - - if (answer.success) { - const encrypt_data = encryptor.encodeMessage(payload, keyPair, answer.publicKey); - - data.message = encrypt_data.message; - data.own_message = encrypt_data.own_message; - const transaction = transactionFormer.createTransaction(constants.transactionTypes.CHAT_MESSAGE, data); - - if (isEncode) { - return transaction; - } - - const res = JSON.parse(request('POST', hotNode() + '/api/transactions/process', { - json: { - transaction - } - }).getBody().toString()); - - return res; - - } - - } catch (e) { - logger.error(`Error while sending message of type ${type}: ${e}`); - return false; - } - } - }; -}; diff --git a/helpers/healthCheck.js b/helpers/healthCheck.js index cba0c1e..1e47d0e 100644 --- a/helpers/healthCheck.js +++ b/helpers/healthCheck.js @@ -1,7 +1,8 @@ -const request = require('request'); +const axios = require('axios'); const _ = require('lodash'); const socket = require('./wsClient'); const logger = require('./logger'); +const dnsPromises = require('dns').promises; const CHECK_NODES_INTERVAL = 60 * 5 * 1000; // Update active nodes every 5 minutes const HEIGHT_EPSILON = 10; // Used to group nodes by height and choose synced @@ -60,19 +61,22 @@ async function checkNodes(forceChangeActiveNode) { for (const n of this.nodesList) { try { - const start = unixTimestamp(); - const req = await checkNode(n + '/api/node/status'); + let start = unixTimestamp(); + let req = await checkNode(n + '/api/node/status'); + let url = n.replace(/^https?:\/\/(.*)$/, '$1').split(":")[0]; + let ifIP = /(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}/.test(url) if (req.status) { this.liveNodes.push({ node: n, ifHttps: n.startsWith("https"), - url: n.replace(/^https?:\/\/(.*)$/, '$1').split(":")[0], + ifIP, + url, outOfSync: false, ping: unixTimestamp() - start, height: req.status.network.height, heightEpsilon: Math.round(req.status.network.height / HEIGHT_EPSILON), - ip: req.ip, + ip: ifIP ? url : await getIP(url), socketSupport: req.status.wsClient && req.status.wsClient.enabled, wsPort: req.status.wsClient.port }); @@ -137,28 +141,27 @@ async function checkNodes(forceChangeActiveNode) { } +async function getIP(url) { + try { + let addresses = await dnsPromises.resolve4(url); + if (addresses && addresses[0] !== '0.0.0.0') + return addresses[0] + } catch (e) { } +}; + /** * Requests status from a single ADAMANT node * @param url {string} Node URL to request * @returns {Promise} Node's status information */ -// Request status from a single node function checkNode(url) { - return new Promise(resolve => { - request(url, (err, res, body) => { - if (err) { - resolve(false); - } else { - try { - const status = JSON.parse(body); - const result = { status: status, ip: res.connection.remoteAddress }; - resolve(result); - } catch (e) { - resolve(false); - } - } - }); - }); + return axios.get(url) + .then(function (response) { + return { status: response.data } + }) + .catch(function (error) { + return false + }) }; function unixTimestamp() { From fe1f449e28d5acd435658c67c1a74299c328cd07 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 20:43:16 +0300 Subject: [PATCH 40/57] Update eth dependencies --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d86adc9..3321dea 100644 --- a/package.json +++ b/package.json @@ -10,15 +10,15 @@ "license": "GPL-3.0", "dependencies": { "axios": "^0.21.1", - "socket.io-client": "^2.4.0", "bignumber.js": "^9.0.1", "bitcore-mnemonic": "^8.25.10", "bytebuffer": "^5.0.1", "ed2curve": "^0.3.0", - "ethereumjs-util": "^6.1.0", - "hdkey": "^1.1.1", + "ethereumjs-util": "^7.0.10", + "hdkey": "^2.0.1", + "socket.io-client": "^2.4.0", "sodium-browserify-tweetnacl": "^0.2.6", - "web3": "^1.0.0-beta.55" + "web3": "^1.3.6" }, "publishConfig": { "access": "public" @@ -56,4 +56,4 @@ "url": "https://github.com/Adamant-im/adamant-api-jsclient/issues" }, "homepage": "https://github.com/Adamant-im/adamant-api-jsclient#readme" -} \ No newline at end of file +} From ac29fbf8b4890e79b489ecd5ab0a4aa14ede36f4 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 20:56:01 +0300 Subject: [PATCH 41/57] Clean up --- groups/decodeMsg.js | 7 ++++++- groups/eth.js | 1 - groups/getPublicKey.js | 16 +++++++--------- helpers/constants.js | 1 + 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/groups/decodeMsg.js b/groups/decodeMsg.js index 460dcf3..31829bb 100644 --- a/groups/decodeMsg.js +++ b/groups/decodeMsg.js @@ -3,6 +3,7 @@ const nacl = require('tweetnacl/nacl-fast'); const keys = require('../helpers/keys'); module.exports = (msg, senderPublicKey, passPhrase, nonce) => { + const keypair = keys.createKeypairFromPassPhrase(passPhrase); let privateKey = keypair.privateKey; if (typeof msg === 'string') { @@ -23,10 +24,11 @@ module.exports = (msg, senderPublicKey, passPhrase, nonce) => { const DHSecretKey = ed2curve.convertSecretKey(privateKey); const decrypted = nacl.box.open(msg, nonce, DHPublicKey, DHSecretKey); return decrypted ? Utf8ArrayToStr(decrypted) : '' -} +} function hexToBytes(hexString = '') { + const bytes = [] for (let c = 0; c < hexString.length; c += 2) { @@ -34,9 +36,11 @@ function hexToBytes(hexString = '') { } return Uint8Array.from(bytes); + } function Utf8ArrayToStr(array) { + var out, i, len, c; var char2, char3; @@ -75,4 +79,5 @@ function Utf8ArrayToStr(array) { } return out; + } \ No newline at end of file diff --git a/groups/eth.js b/groups/eth.js index 737f31a..1a09698 100644 --- a/groups/eth.js +++ b/groups/eth.js @@ -1,4 +1,3 @@ -// https://web3js.readthedocs.io/en/1.0/web3-eth.html#eth-getbalance const Web3 = require('web3'); var Mnemonic = require('bitcore-mnemonic'); const hdkey = require('hdkey'); diff --git a/groups/getPublicKey.js b/groups/getPublicKey.js index 10a602d..43f6894 100644 --- a/groups/getPublicKey.js +++ b/groups/getPublicKey.js @@ -4,15 +4,13 @@ const logger = require('../helpers/logger'); module.exports = (nodeManager) => { return async (address) => { - - const publicKey = await get(nodeManager)('/accounts/getPublicKey', { address }); - if (publicKey.success) { - return publicKey.data.publicKey - } else { - logger.warn(`[ADAMANT js-api] Failed to get public key for ${address}. ${publicKey.errorMessage}.`); - return false - } - + const publicKey = await get(nodeManager)('/accounts/getPublicKey', { address }); + if (publicKey.success) { + return publicKey.data.publicKey + } else { + logger.warn(`[ADAMANT js-api] Failed to get public key for ${address}. ${publicKey.errorMessage}.`); + return false + } } }; diff --git a/helpers/constants.js b/helpers/constants.js index 1f3b34b..b2eb6bf 100644 --- a/helpers/constants.js +++ b/helpers/constants.js @@ -34,4 +34,5 @@ module.exports = { RE_DASH_ADDRESS: /^[7X][1-9A-HJ-NP-Za-km-z]{33,}$/, RE_DOGE_ADDRESS: /^[A|D|9][A-Z0-9]([0-9a-zA-Z]{9,})$/, RE_LSK_ADDRESS: /^[0-9]{2,21}L$/ + } From c7d73fba09d112ce29c9447ca2041c01ee8c5ac2 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 21:13:54 +0300 Subject: [PATCH 42/57] Remove lodash from get --- groups/get.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/groups/get.js b/groups/get.js index 3906fa6..0c40dff 100644 --- a/groups/get.js +++ b/groups/get.js @@ -1,5 +1,4 @@ const axios = require('axios'); -const _ = require('lodash'); const logger = require('../helpers/logger'); const validator = require('../helpers/validator'); @@ -8,7 +7,7 @@ const DEFAULT_GET_REQUEST_RETRIES = 3; // How much re-tries for get-requests by module.exports = (nodeManager) => { return (endpoint, params, maxRetries = DEFAULT_GET_REQUEST_RETRIES, retryNo = 0) => { - let url = _.trim(endpoint, "/ ") + let url = trimAny(endpoint, "/ "); if (!url || !validator.validateEndpoint(endpoint)) return validator.badParameter('endpoint') @@ -32,3 +31,16 @@ module.exports = (nodeManager) => { } }; + +function trimAny(str, chars) { + if (!str || typeof str !== 'string') + return '' + let start = 0, + end = str.length; + while(start < end && chars.indexOf(str[start]) >= 0) + ++start; + while(end > start && chars.indexOf(str[end - 1]) >= 0) + --end; + return (start > 0 || end < str.length) ? str.substring(start, end) : str; +} + From befa90fa80d8a78e842d2a9c435a93644bb90fda Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 21:20:01 +0300 Subject: [PATCH 43/57] Remove lodash --- groups/get.js | 2 +- groups/sendMessage.js | 3 +-- groups/sendTokens.js | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/groups/get.js b/groups/get.js index 0c40dff..233085c 100644 --- a/groups/get.js +++ b/groups/get.js @@ -17,7 +17,7 @@ module.exports = (nodeManager) => { return validator.formatRequestResults(response, true) }) .catch(function (error) { - let logMessage = `[ADAMANT js-api] Get-request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}. Message: ${error.response ? _.trim(error.response.data, '\n') : undefined}. Try ${retryNo+1} of ${maxRetries+1}.`; + let logMessage = `[ADAMANT js-api] Get-request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}${error.response && error.response.data ? '. Message: ' + error.response.data.toString().trim() : ''}. Try ${retryNo+1} of ${maxRetries+1}.`; if (retryNo < maxRetries) { logger.log(`${logMessage} Retrying…`); return nodeManager.changeNodes() diff --git a/groups/sendMessage.js b/groups/sendMessage.js index 9702161..53294b0 100644 --- a/groups/sendMessage.js +++ b/groups/sendMessage.js @@ -1,5 +1,4 @@ const axios = require('axios'); -const _ = require('lodash'); const logger = require('../helpers/logger'); const keys = require('../helpers/keys'); const constants = require('../helpers/constants'); @@ -94,7 +93,7 @@ module.exports = (nodeManager) => { return validator.formatRequestResults(response, true) }) .catch(function (error) { - let logMessage = `[ADAMANT js-api] Send message request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}. Message: ${error.response ? _.trim(error.response.data, '\n') : undefined}. Try ${retryNo+1} of ${maxRetries+1}.`; + let logMessage = `[ADAMANT js-api] Send message request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}${error.response && error.response.data ? '. Message: ' + error.response.data.toString().trim() : ''}. Try ${retryNo+1} of ${maxRetries+1}.`; if (retryNo < maxRetries) { logger.log(`${logMessage} Retrying…`); return nodeManager.changeNodes() diff --git a/groups/sendTokens.js b/groups/sendTokens.js index 98c90f0..79b1394 100644 --- a/groups/sendTokens.js +++ b/groups/sendTokens.js @@ -1,5 +1,4 @@ const axios = require('axios'); -const _ = require('lodash'); const logger = require('../helpers/logger'); const keys = require('../helpers/keys'); const constants = require('../helpers/constants'); @@ -52,7 +51,7 @@ module.exports = (nodeManager) => { return validator.formatRequestResults(response, true) }) .catch(function (error) { - let logMessage = `[ADAMANT js-api] Send tokens request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}. Message: ${error.response ? _.trim(error.response.data, '\n') : undefined}. Try ${retryNo+1} of ${maxRetries+1}.`; + let logMessage = `[ADAMANT js-api] Send tokens request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}${error.response && error.response.data ? '. Message: ' + error.response.data.toString().trim() : ''}. Try ${retryNo+1} of ${maxRetries+1}.`; if (retryNo < maxRetries) { logger.log(`${logMessage} Retrying…`); return nodeManager.changeNodes() From a5e97428c4c1ee28351b6edb55dbd552078b596d Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 21:57:29 +0300 Subject: [PATCH 44/57] Remove lodash --- helpers/healthCheck.js | 4 ++-- helpers/validator.js | 8 +++++++- helpers/wsClient.js | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/helpers/healthCheck.js b/helpers/healthCheck.js index 1e47d0e..da9124f 100644 --- a/helpers/healthCheck.js +++ b/helpers/healthCheck.js @@ -1,7 +1,7 @@ const axios = require('axios'); -const _ = require('lodash'); const socket = require('./wsClient'); const logger = require('./logger'); +const validator = require('./validator'); const dnsPromises = require('dns').promises; const CHECK_NODES_INTERVAL = 60 * 5 * 1000; // Update active nodes every 5 minutes @@ -124,7 +124,7 @@ async function checkNodes(forceChangeActiveNode) { this.liveNodes.sort((a, b) => a.ping - b.ping); if (this.activeNode === biggestGroup[0].node && forceChangeActiveNode) - this.activeNode = biggestGroup[_.random(1, biggestGroup.length-1)].node // Use random node from which are synced + this.activeNode = biggestGroup[validator.getRandomIntInclusive(1, biggestGroup.length-1)].node // Use random node from which are synced else this.activeNode = biggestGroup[0].node; // Use node with minimum ping among which are synced } diff --git a/helpers/validator.js b/helpers/validator.js index a059c5e..1a77448 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -3,6 +3,12 @@ const BigNumber = require('bignumber.js') module.exports = { + getRandomIntInclusive(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1) + min); //The maximum is inclusive and the minimum is inclusive + }, + isNumeric(str) { if (typeof str !== "string") return false return !isNaN(str) && !isNaN(parseFloat(str)) @@ -128,7 +134,7 @@ module.exports = { results.details.status = response.response ? response.response.status : undefined; results.details.statusText = response.response ? response.response.statusText : undefined; results.details.error = response.toString(); - results.details.message = response.response ? _.trim(response.response.data, '\n') : undefined; + results.details.message = response.response && response.response.data ? response.response.data.toString().trim() : undefined; results.details.response = response.response; results.errorMessage = `${results.details.error}${results.details.message ? '. Message: ' + results.details.message : ''}`; } diff --git a/helpers/wsClient.js b/helpers/wsClient.js index a1e9979..05853b7 100644 --- a/helpers/wsClient.js +++ b/helpers/wsClient.js @@ -1,6 +1,6 @@ const ioClient = require("socket.io-client"); -const _ = require('lodash'); const logger = require('./logger'); +const validator = require('./validator'); module.exports = { @@ -94,7 +94,7 @@ module.exports = { }, randomNode() { - return this.activeSocketNodes[_.random(this.activeSocketNodes.length - 1)] + return this.activeSocketNodes[validator.getRandomIntInclusive(0, this.activeSocketNodes.length - 1)] } } From b37f8f8bd8dd796728c3de6dca8b37c43d77f571 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 May 2021 22:23:28 +0300 Subject: [PATCH 45/57] Remove lodash --- helpers/healthCheck.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/helpers/healthCheck.js b/helpers/healthCheck.js index da9124f..822cb28 100644 --- a/helpers/healthCheck.js +++ b/helpers/healthCheck.js @@ -109,17 +109,29 @@ async function checkNodes(forceChangeActiveNode) { this.liveNodes[0].outOfSync = true } } else { + let biggestGroup = []; - const groups = _.groupBy(this.liveNodes, n => n.heightEpsilon); + // const groups = _.groupBy(this.liveNodes, n => n.heightEpsilon); + const groups = this.liveNodes.reduce(function (grouped, node) { + var int = Math.floor(node.heightEpsilon); + if (!grouped.hasOwnProperty(int)) { + grouped[int] = []; + } + grouped[int].push(node); + return grouped; + }, {}); + Object.keys(groups).forEach(key => { if (groups[key].length > biggestGroup.length) { biggestGroup = groups[key]; } }); + // All the nodes from the biggestGroup list are considered to be in sync, all the others are not this.liveNodes.forEach(node => { node.outOfSync = !biggestGroup.includes(node) }) + biggestGroup.sort((a, b) => a.ping - b.ping); this.liveNodes.sort((a, b) => a.ping - b.ping); @@ -127,6 +139,7 @@ async function checkNodes(forceChangeActiveNode) { this.activeNode = biggestGroup[validator.getRandomIntInclusive(1, biggestGroup.length-1)].node // Use random node from which are synced else this.activeNode = biggestGroup[0].node; // Use node with minimum ping among which are synced + } socket.reviseConnection(this.liveNodes); logger.log(`[ADAMANT js-api] Health check: Found ${this.liveNodes.length} supported nodes. Active node is ${this.activeNode}.`); From 4fc3955f3bb6fd5c8987468035dd969f1c24761a Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 25 May 2021 11:57:49 +0300 Subject: [PATCH 46/57] Update healthCheck --- helpers/healthCheck.js | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/helpers/healthCheck.js b/helpers/healthCheck.js index 822cb28..239e541 100644 --- a/helpers/healthCheck.js +++ b/helpers/healthCheck.js @@ -5,7 +5,7 @@ const validator = require('./validator'); const dnsPromises = require('dns').promises; const CHECK_NODES_INTERVAL = 60 * 5 * 1000; // Update active nodes every 5 minutes -const HEIGHT_EPSILON = 10; // Used to group nodes by height and choose synced +const HEIGHT_EPSILON = 5; // Used to group nodes by height and choose synced module.exports = (nodes) => { @@ -86,34 +86,42 @@ async function checkNodes(forceChangeActiveNode) { } } catch (e) { - logger.log(`[ADAMANT js-api] Health check: Error while checking node ${n}:`, e); + logger.log(`[ADAMANT js-api] Health check: Error while checking node ${n}, ` + e); } } const count = this.liveNodes.length; + let outOfSyncCount = 0; + if (!count) { logger.error(`[ADAMANT js-api] Health check: All of ${this.nodesList.length} nodes are unavailable. Check internet connection and nodes list in config.`); } else { // Set activeNode to one that have maximum height and minimum ping if (count === 1) { + this.activeNode = this.liveNodes[0].node; + } else if (count === 2) { + const h0 = this.liveNodes[0]; const h1 = this.liveNodes[1]; this.activeNode = h0.height > h1.height ? h0.node : h1.node; // Mark node outOfSync if needed if (h0.heightEpsilon > h1.heightEpsilon) { this.liveNodes[1].outOfSync = true + outOfSyncCount += 1; } else if (h0.heightEpsilon < h1.heightEpsilon) { this.liveNodes[0].outOfSync = true + outOfSyncCount += 1; } + } else { let biggestGroup = []; - // const groups = _.groupBy(this.liveNodes, n => n.heightEpsilon); + // Removing lodash: const groups = _.groupBy(this.liveNodes, n => n.heightEpsilon); const groups = this.liveNodes.reduce(function (grouped, node) { - var int = Math.floor(node.heightEpsilon); + var int = Math.floor(node.heightEpsilon); // Excessive, it is already rounded if (!grouped.hasOwnProperty(int)) { grouped[int] = []; } @@ -131,23 +139,31 @@ async function checkNodes(forceChangeActiveNode) { this.liveNodes.forEach(node => { node.outOfSync = !biggestGroup.includes(node) }) + outOfSyncCount = this.liveNodes.length - biggestGroup.length; biggestGroup.sort((a, b) => a.ping - b.ping); this.liveNodes.sort((a, b) => a.ping - b.ping); - if (this.activeNode === biggestGroup[0].node && forceChangeActiveNode) + if (forceChangeActiveNode && biggestGroup.length > 1 && this.activeNode === biggestGroup[0].node) this.activeNode = biggestGroup[validator.getRandomIntInclusive(1, biggestGroup.length-1)].node // Use random node from which are synced else this.activeNode = biggestGroup[0].node; // Use node with minimum ping among which are synced } socket.reviseConnection(this.liveNodes); - logger.log(`[ADAMANT js-api] Health check: Found ${this.liveNodes.length} supported nodes. Active node is ${this.activeNode}.`); + let unavailableCount = this.nodesList.length - this.liveNodes.length; + let supportedCount = this.liveNodes.length - outOfSyncCount; + let nodesInfoString = ''; + if (unavailableCount) + nodesInfoString += `, ${unavailableCount} nodes didn't respond` + if (outOfSyncCount) + nodesInfoString += `, ${outOfSyncCount} nodes are not synced` + logger.log(`[ADAMANT js-api] Health check: Found ${supportedCount} supported and synced nodes${nodesInfoString}. Active node is ${this.activeNode}.`); } } catch (e) { - logger.warn('[ADAMANT js-api] Health check: Error in checkNodes()', e); + logger.warn('[ADAMANT js-api] Health check: Error in checkNodes(), ' + e); } this.isCheckingNodes = false; From 32c54697448993ce578e71a09c1cacee5797e92a Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 25 May 2021 23:34:34 +0300 Subject: [PATCH 47/57] Remove web3 lib --- groups/eth.js | 5 ++--- package.json | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/groups/eth.js b/groups/eth.js index 1a09698..efd3548 100644 --- a/groups/eth.js +++ b/groups/eth.js @@ -1,9 +1,8 @@ -const Web3 = require('web3'); var Mnemonic = require('bitcore-mnemonic'); const hdkey = require('hdkey'); const HD_KEY_PATH = "m/44'/60'/3'/1/0"; -const {bufferToHex, privateToAddress } = require('ethereumjs-util'); -const {eth} = new Web3('https://ethnode1.adamant.im'); +const { bufferToHex, privateToAddress } = require('ethereumjs-util'); +const eth = { } /** * Generates a ETH account from the passphrase specified. diff --git a/package.json b/package.json index 3321dea..d88b291 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,7 @@ "ethereumjs-util": "^7.0.10", "hdkey": "^2.0.1", "socket.io-client": "^2.4.0", - "sodium-browserify-tweetnacl": "^0.2.6", - "web3": "^1.3.6" + "sodium-browserify-tweetnacl": "^0.2.6" }, "publishConfig": { "access": "public" From ca6f42f5a72cf4d77852e73b59fe32e4a336dddf Mon Sep 17 00:00:00 2001 From: adamant-al Date: Thu, 27 May 2021 17:27:32 +0300 Subject: [PATCH 48/57] Descriptions --- README.md | 46 +++++++++++++++++++++++++++++++++++-------- groups/get.js | 2 +- groups/sendMessage.js | 4 ++-- groups/sendTokens.js | 10 ++++++++++ package.json | 2 +- 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 1d48832..c479182 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ # ADAMANT JavaScript API library -ADAMANT JavaScript API is a library intended to interact with ADAMANT blockchain for Node.js developers. Also [ADAMANT Console](https://github.com/Adamant-im/adamant-console/wiki) and [ADAMANT node Direct API](https://github.com/Adamant-im/adamant/wiki/) are available. +ADAMANT JavaScript API is a library intended to interact with ADAMANT blockchain for JavaScript developers. Also [ADAMANT Console](https://github.com/Adamant-im/adamant-console/wiki) and [ADAMANT node Direct API](https://github.com/Adamant-im/adamant/wiki/) are available. -Abilities: +Features: -* Internal Health Check for ADAMANT nodes. Health Check system pings all nodes in the list using [`/status`](https://github.com/Adamant-im/adamant/wiki/API-Specification#get-blockchain-and-network-status) endpoint, and connect to a node with actual height. +* High reliability +* GET-requests to the blockchain +* Sending tokens +* Sending messages * Encrypting and decrypting of messages * Forming and signing transactions * Working with ADM key pairs @@ -13,14 +16,19 @@ Abilities: * Support for WebSocket connections * Logging warnings, errors, info -# Usage +## Reliability -Add current version of ADAMANT JavaScript API library in project's `package.json` in `dependencies` section like this: +JS API shows decentralization in action—if a network node cannot fulfill your request, the library will redirect it to another node, and so on several times. You will get the result and you do not need to think about processing the request. + +Health Check system pings all nodes in the list using [`/status`](https://github.com/Adamant-im/adamant/wiki/API-Specification#get-blockchain-and-network-status) endpoint, and connects to a node with actual height. When the library unable to process request with current node, it forces to re-initialize Health Check. + +## Usage + +Add current version of ADAMANT JavaScript API library in project's `package.json` in `dependencies` section: ``` json "dependencies": { - "adamant-api": "^0.5.3", - ... + "adamant-api": "^1.0.0-beta.2", ``` Or install library from npm: @@ -29,6 +37,28 @@ Or install library from npm: npm i adamant-api ``` -# Documentation +Initialize the library: + +``` JS +const nodesList = [ + "http://localhost:36666", + "https://endless.adamant.im", + "https://clown.adamant.im", + "http://23.226.231.225:36666", + "http://88.198.156.44:36666", + "https://lake.adamant.im" +]; +const api = require('adamant-api')({ node: nodesList, logLevel: 'info' }); +``` + +Request example: + +``` JS +api.get('blocks').then(response => { + console.log(response.data) +}) +``` + +## Documentation See [Wiki](https://github.com/Adamant-im/adamant-api-jsclient/wiki) for documentation and usage. diff --git a/groups/get.js b/groups/get.js index 233085c..507c522 100644 --- a/groups/get.js +++ b/groups/get.js @@ -7,7 +7,7 @@ const DEFAULT_GET_REQUEST_RETRIES = 3; // How much re-tries for get-requests by module.exports = (nodeManager) => { return (endpoint, params, maxRetries = DEFAULT_GET_REQUEST_RETRIES, retryNo = 0) => { - let url = trimAny(endpoint, "/ "); + let url = trimAny(endpoint, "/ ").replace(/^api\//, ''); if (!url || !validator.validateEndpoint(endpoint)) return validator.badParameter('endpoint') diff --git a/groups/sendMessage.js b/groups/sendMessage.js index 53294b0..657daa1 100644 --- a/groups/sendMessage.js +++ b/groups/sendMessage.js @@ -11,12 +11,12 @@ const DEFAULT_SEND_MESSAGE_RETRIES = 4; // How much re-tries for send message re module.exports = (nodeManager) => { /** - * Sends encrypted basic, rich, or signal message + * Creates Message transaction, signs it, and broadcasts to ADAMANT network. Supports Basic, Rich and Signal Message Types. * See https://github.com/Adamant-im/adamant/wiki/Message-Types * @param {string} passPhrase Senders's passPhrase. Sender's address will be derived from it. * @param {string} address Recipient's ADAMANT address * @param {string} message Message plain text in case of basic message. Stringified JSON in case of rich or signal messages. - * Example of rich message for token transfer: `{"type":"eth_transaction","amount":"0.002","hash":"0xfa46d2b3c99878f1f9863fcbdb0bc27d220d7065c6528543cbb83ced84487deb","comments":"I like to send it, send it"}` + * Example of rich message for Ether in-chat transfer: `{"type":"eth_transaction","amount":"0.002","hash":"0xfa46d2b3c99878f1f9863fcbdb0bc27d220d7065c6528543cbb83ced84487deb","comments":"I like to send it, send it"}` * @param {string, number} message_type Type of message: basic, rich, or signal * @param {string, number} amount Amount to send with a message * @param {boolean} isAmountInADM If amount specified in ADM, or in sats (10^-8 ADM) diff --git a/groups/sendTokens.js b/groups/sendTokens.js index 79b1394..fd867b7 100644 --- a/groups/sendTokens.js +++ b/groups/sendTokens.js @@ -8,6 +8,16 @@ const validator = require('../helpers/validator'); const DEFAULT_SEND_TOKENS_RETRIES = 4; // How much re-tries for send tokens requests by default. Total 4+1 tries module.exports = (nodeManager) => { + /** + * Creates Token Transfer transaction, signs it, and broadcasts to ADAMANT network + * See https://github.com/Adamant-im/adamant/wiki/Transaction-Types#type-0-token-transfer-transaction + * @param {string} passPhrase Senders's passPhrase. Sender's address will be derived from it. + * @param {string} address Recipient's ADAMANT address + * @param {string, number} amount Amount to send + * @param {boolean} isAmountInADM If amount specified in ADM, or in sats (10^-8 ADM) + * @param {number} maxRetries How much times to retry request + * @returns {Promise} Request results + */ return (passPhrase, address, amount, isAmountInADM = true, maxRetries = DEFAULT_SEND_TOKENS_RETRIES, retryNo = 0) => { let transaction; diff --git a/package.json b/package.json index d88b291..4ace36a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adamant-api", - "version": "1.0.0-beta.1", + "version": "1.0.0-beta.2", "description": "REST API for ADAMANT Blockchain", "main": "index.js", "scripts": { From ff6e760067b868bf6e67f2ce4ac34c3cebf6a557 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Thu, 27 May 2021 17:52:18 +0300 Subject: [PATCH 49/57] Add validateAdmPublicKey() --- groups/sendMessage.js | 26 ++++++++++++++++++-------- helpers/constants.js | 1 + helpers/validator.js | 7 +++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/groups/sendMessage.js b/groups/sendMessage.js index 657daa1..ba83f07 100644 --- a/groups/sendMessage.js +++ b/groups/sendMessage.js @@ -14,7 +14,7 @@ module.exports = (nodeManager) => { * Creates Message transaction, signs it, and broadcasts to ADAMANT network. Supports Basic, Rich and Signal Message Types. * See https://github.com/Adamant-im/adamant/wiki/Message-Types * @param {string} passPhrase Senders's passPhrase. Sender's address will be derived from it. - * @param {string} address Recipient's ADAMANT address + * @param {string} addressOrPublicKey Recipient's ADAMANT address or public key. Using public key is faster, as the library wouldn't request it from the network * @param {string} message Message plain text in case of basic message. Stringified JSON in case of rich or signal messages. * Example of rich message for Ether in-chat transfer: `{"type":"eth_transaction","amount":"0.002","hash":"0xfa46d2b3c99878f1f9863fcbdb0bc27d220d7065c6528543cbb83ced84487deb","comments":"I like to send it, send it"}` * @param {string, number} message_type Type of message: basic, rich, or signal @@ -23,9 +23,10 @@ module.exports = (nodeManager) => { * @param {number} maxRetries How much times to retry request * @returns {Promise} Request results */ - return (passPhrase, address, message, message_type = 'basic', amount, isAmountInADM = true, maxRetries = DEFAULT_SEND_MESSAGE_RETRIES, retryNo = 0) => { + return (passPhrase, addressOrPublicKey, message, message_type = 'basic', amount, isAmountInADM = true, maxRetries = DEFAULT_SEND_MESSAGE_RETRIES, retryNo = 0) => { let keyPair, data; + let address, publicKey; try { @@ -34,8 +35,17 @@ module.exports = (nodeManager) => { keyPair = keys.createKeypairFromPassPhrase(passPhrase); - if (!validator.validateAdmAddress(address)) - return validator.badParameter('address', address) + if (!validator.validateAdmAddress(addressOrPublicKey)) { + if (!validator.validateAdmPublicKey(addressOrPublicKey)) { + return validator.badParameter('addressOrPublicKey', addressOrPublicKey) + } else { + publicKey = addressOrPublicKey; + address = keys.createAddressFromPublicKey(publicKey) + } + } else { + publicKey = ''; + address = addressOrPublicKey + } if (message_type === 'basic') message_type = 1; @@ -53,7 +63,7 @@ module.exports = (nodeManager) => { data = { keyPair, - recipientId: address, + recipientId: addressOrPublicKey, message_type }; @@ -74,7 +84,7 @@ module.exports = (nodeManager) => { } - return getPublicKey(nodeManager)(address) + return getPublicKey(nodeManager)(addressOrPublicKey) .then((publicKey) => { if (publicKey) { @@ -98,7 +108,7 @@ module.exports = (nodeManager) => { logger.log(`${logMessage} Retrying…`); return nodeManager.changeNodes() .then(function () { - return module.exports(nodeManager)(passPhrase, address, message, message_type, tokensAmount, maxRetries, ++retryNo) + return module.exports(nodeManager)(passPhrase, addressOrPublicKey, message, message_type, tokensAmount, maxRetries, ++retryNo) }) } logger.warn(`${logMessage} No more attempts, returning error.`); @@ -121,7 +131,7 @@ module.exports = (nodeManager) => { return new Promise((resolve, reject) => { resolve({ success: false, - errorMessage: `Unable to get public key for ${address}. It is necessary for sending an encrypted message. Account may be uninitialized (https://medium.com/adamant-im/chats-and-uninitialized-accounts-in-adamant-5035438e2fcd), or network error` + errorMessage: `Unable to get public key for ${addressOrPublicKey}. It is necessary for sending an encrypted message. Account may be uninitialized (https://medium.com/adamant-im/chats-and-uninitialized-accounts-in-adamant-5035438e2fcd), or network error` }) }) diff --git a/helpers/constants.js b/helpers/constants.js index b2eb6bf..55ed58e 100644 --- a/helpers/constants.js +++ b/helpers/constants.js @@ -28,6 +28,7 @@ module.exports = { }, maxVotesPerTransaction: 33, SAT: 100000000, + RE_HEX: /^[a-fA-F0-9]+$/, RE_BASE64: /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$/, RE_ADM_ADDRESS: /^U([0-9]{6,})$/, RE_BTC_ADDRESS: /^(bc1|[13])[a-km-zA-HJ-NP-Z02-9]{25,39}$/, diff --git a/helpers/validator.js b/helpers/validator.js index 1a77448..4483aaf 100644 --- a/helpers/validator.js +++ b/helpers/validator.js @@ -45,6 +45,13 @@ module.exports = { return true }, + validateAdmPublicKey(publicKey) { + if (!publicKey || typeof(publicKey) !== 'string' || publicKey.length !== 64 || !constants.RE_HEX.test(publicKey)) + return false + else + return true + }, + validateIntegerAmount(amount) { if (!amount || typeof(amount) !== 'number' || isNaN(amount) || !Number.isSafeInteger(amount)) return false From 5bac72e01abbdad2ae9688c058fa6f821037e1bd Mon Sep 17 00:00:00 2001 From: adamant-al Date: Fri, 28 May 2021 09:51:09 +0300 Subject: [PATCH 50/57] Cache public keys --- groups/getPublicKey.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/groups/getPublicKey.js b/groups/getPublicKey.js index 43f6894..dc40b21 100644 --- a/groups/getPublicKey.js +++ b/groups/getPublicKey.js @@ -1,11 +1,16 @@ const get = require('./get'); const logger = require('../helpers/logger'); +const publicKeysCache = { }; module.exports = (nodeManager) => { return async (address) => { + if (publicKeysCache[address]) + return publicKeysCache[address] + const publicKey = await get(nodeManager)('/accounts/getPublicKey', { address }); if (publicKey.success) { + publicKeysCache[address] = publicKey.data.publicKey; return publicKey.data.publicKey } else { logger.warn(`[ADAMANT js-api] Failed to get public key for ${address}. ${publicKey.errorMessage}.`); From 766fa339a1f119e97e5253b065ed3914ca2fe4bb Mon Sep 17 00:00:00 2001 From: adamant-al Date: Fri, 28 May 2021 09:53:54 +0300 Subject: [PATCH 51/57] We can use public key instead of address to send message --- groups/sendMessage.js | 102 +++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/groups/sendMessage.js b/groups/sendMessage.js index ba83f07..94fa187 100644 --- a/groups/sendMessage.js +++ b/groups/sendMessage.js @@ -14,7 +14,9 @@ module.exports = (nodeManager) => { * Creates Message transaction, signs it, and broadcasts to ADAMANT network. Supports Basic, Rich and Signal Message Types. * See https://github.com/Adamant-im/adamant/wiki/Message-Types * @param {string} passPhrase Senders's passPhrase. Sender's address will be derived from it. - * @param {string} addressOrPublicKey Recipient's ADAMANT address or public key. Using public key is faster, as the library wouldn't request it from the network + * @param {string} addressOrPublicKey Recipient's ADAMANT address or public key. + * Using public key is faster, as the library wouldn't request it from the network. + * Though we cache public keys, and next request with address will be processed as fast as with public key. * @param {string} message Message plain text in case of basic message. Stringified JSON in case of rich or signal messages. * Example of rich message for Ether in-chat transfer: `{"type":"eth_transaction","amount":"0.002","hash":"0xfa46d2b3c99878f1f9863fcbdb0bc27d220d7065c6528543cbb83ced84487deb","comments":"I like to send it, send it"}` * @param {string, number} message_type Type of message: basic, rich, or signal @@ -23,7 +25,7 @@ module.exports = (nodeManager) => { * @param {number} maxRetries How much times to retry request * @returns {Promise} Request results */ - return (passPhrase, addressOrPublicKey, message, message_type = 'basic', amount, isAmountInADM = true, maxRetries = DEFAULT_SEND_MESSAGE_RETRIES, retryNo = 0) => { + return async (passPhrase, addressOrPublicKey, message, message_type = 'basic', amount, isAmountInADM = true, maxRetries = DEFAULT_SEND_MESSAGE_RETRIES, retryNo = 0) => { let keyPair, data; let address, publicKey; @@ -40,7 +42,11 @@ module.exports = (nodeManager) => { return validator.badParameter('addressOrPublicKey', addressOrPublicKey) } else { publicKey = addressOrPublicKey; - address = keys.createAddressFromPublicKey(publicKey) + try { + address = keys.createAddressFromPublicKey('publicKey') + } catch (e) { + return validator.badParameter('addressOrPublicKey', addressOrPublicKey) + } } } else { publicKey = ''; @@ -63,7 +69,7 @@ module.exports = (nodeManager) => { data = { keyPair, - recipientId: addressOrPublicKey, + recipientId: address, message_type }; @@ -84,60 +90,54 @@ module.exports = (nodeManager) => { } - return getPublicKey(nodeManager)(addressOrPublicKey) - .then((publicKey) => { + if (!publicKey) + publicKey = await getPublicKey(nodeManager)(address); - if (publicKey) { - - try { + if (!publicKey) + return new Promise((resolve, reject) => { + resolve({ + success: false, + errorMessage: `Unable to get public key for ${addressOrPublicKey}. It is necessary for sending an encrypted message. Account may be uninitialized (https://medium.com/adamant-im/chats-and-uninitialized-accounts-in-adamant-5035438e2fcd), or network error` + }) + }) - const encryptedMessage = encryptor.encodeMessage(message, keyPair, publicKey); - data.message = encryptedMessage.message; - data.own_message = encryptedMessage.own_message; - - let transaction = transactionFormer.createTransaction(constants.transactionTypes.CHAT_MESSAGE, data); - - let url = nodeManager.node() + '/api/transactions/process'; - return axios.post(url, { transaction }) - .then(function (response) { - return validator.formatRequestResults(response, true) - }) - .catch(function (error) { - let logMessage = `[ADAMANT js-api] Send message request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}${error.response && error.response.data ? '. Message: ' + error.response.data.toString().trim() : ''}. Try ${retryNo+1} of ${maxRetries+1}.`; - if (retryNo < maxRetries) { - logger.log(`${logMessage} Retrying…`); - return nodeManager.changeNodes() - .then(function () { - return module.exports(nodeManager)(passPhrase, addressOrPublicKey, message, message_type, tokensAmount, maxRetries, ++retryNo) - }) - } - logger.warn(`${logMessage} No more attempts, returning error.`); - return validator.formatRequestResults(error, false) - }) - - } catch (e) { + try { - return new Promise((resolve, reject) => { - resolve({ - success: false, - errorMessage: `Unable to encode message '${message}' with public key ${publicKey}, or unable to build a transaction. Exception: ` + e + const encryptedMessage = encryptor.encodeMessage(message, keyPair, publicKey); + data.message = encryptedMessage.message; + data.own_message = encryptedMessage.own_message; + + let transaction = transactionFormer.createTransaction(constants.transactionTypes.CHAT_MESSAGE, data); + + let url = nodeManager.node() + '/api/transactions/process'; + return axios.post(url, { transaction }) + .then(function (response) { + return validator.formatRequestResults(response, true) + }) + .catch(function (error) { + let logMessage = `[ADAMANT js-api] Send message request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}${error.response && error.response.data ? '. Message: ' + error.response.data.toString().trim() : ''}. Try ${retryNo+1} of ${maxRetries+1}.`; + if (retryNo < maxRetries) { + logger.log(`${logMessage} Retrying…`); + return nodeManager.changeNodes() + .then(function () { + return module.exports(nodeManager)(passPhrase, addressOrPublicKey, message, message_type, tokensAmount, maxRetries, ++retryNo) }) - }) - } + logger.warn(`${logMessage} No more attempts, returning error.`); + return validator.formatRequestResults(error, false) + }) + + } catch (e) { - } else { - - return new Promise((resolve, reject) => { - resolve({ - success: false, - errorMessage: `Unable to get public key for ${addressOrPublicKey}. It is necessary for sending an encrypted message. Account may be uninitialized (https://medium.com/adamant-im/chats-and-uninitialized-accounts-in-adamant-5035438e2fcd), or network error` - }) - }) + return new Promise((resolve, reject) => { + resolve({ + success: false, + errorMessage: `Unable to encode message '${message}' with public key ${publicKey}, or unable to build a transaction. Exception: ` + e + }) + }) - } // if (publicKey) + } - }) // getPublicKey.then - } + } // sendMessage() }; From b8b0360d965d38f463fc4ad47e813b14938cd497 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Fri, 28 May 2021 09:56:31 +0300 Subject: [PATCH 52/57] We can use public key instead of address to send tokens --- groups/sendTokens.js | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/groups/sendTokens.js b/groups/sendTokens.js index fd867b7..220aa3b 100644 --- a/groups/sendTokens.js +++ b/groups/sendTokens.js @@ -12,15 +12,17 @@ module.exports = (nodeManager) => { * Creates Token Transfer transaction, signs it, and broadcasts to ADAMANT network * See https://github.com/Adamant-im/adamant/wiki/Transaction-Types#type-0-token-transfer-transaction * @param {string} passPhrase Senders's passPhrase. Sender's address will be derived from it. - * @param {string} address Recipient's ADAMANT address + * @param {string} addressOrPublicKey Recipient's ADAMANT address or public key. + * Address is preferred, as if we get public key, we should derive address from it. * @param {string, number} amount Amount to send * @param {boolean} isAmountInADM If amount specified in ADM, or in sats (10^-8 ADM) * @param {number} maxRetries How much times to retry request * @returns {Promise} Request results */ - return (passPhrase, address, amount, isAmountInADM = true, maxRetries = DEFAULT_SEND_TOKENS_RETRIES, retryNo = 0) => { + return (passPhrase, addressOrPublicKey, amount, isAmountInADM = true, maxRetries = DEFAULT_SEND_TOKENS_RETRIES, retryNo = 0) => { let transaction; + let address, publicKey; try { @@ -29,9 +31,22 @@ module.exports = (nodeManager) => { const keyPair = keys.createKeypairFromPassPhrase(passPhrase); - if (!validator.validateAdmAddress(address)) - return validator.badParameter('address', address) - + if (!validator.validateAdmAddress(addressOrPublicKey)) { + if (!validator.validateAdmPublicKey(addressOrPublicKey)) { + return validator.badParameter('addressOrPublicKey', addressOrPublicKey) + } else { + publicKey = addressOrPublicKey; + try { + address = keys.createAddressFromPublicKey('publicKey') + } catch (e) { + return validator.badParameter('addressOrPublicKey', addressOrPublicKey) + } + } + } else { + publicKey = ''; + address = addressOrPublicKey + } + if (isAmountInADM) { amountInSat = validator.AdmToSats(amount) } else { @@ -66,7 +81,7 @@ module.exports = (nodeManager) => { logger.log(`${logMessage} Retrying…`); return nodeManager.changeNodes() .then(function () { - return module.exports(nodeManager)(passPhrase, address, amount, isAmountInADM, maxRetries, ++retryNo) + return module.exports(nodeManager)(passPhrase, addressOrPublicKey, amount, isAmountInADM, maxRetries, ++retryNo) }) } logger.warn(`${logMessage} No more attempts, returning error.`); From e6fa53df7ea15994ec2e7836dc72ef5dd593d543 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Fri, 28 May 2021 11:22:39 +0300 Subject: [PATCH 53/57] Clean up --- groups/sendMessage.js | 2 +- groups/sendTokens.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/groups/sendMessage.js b/groups/sendMessage.js index 94fa187..c93af24 100644 --- a/groups/sendMessage.js +++ b/groups/sendMessage.js @@ -43,7 +43,7 @@ module.exports = (nodeManager) => { } else { publicKey = addressOrPublicKey; try { - address = keys.createAddressFromPublicKey('publicKey') + address = keys.createAddressFromPublicKey(publicKey) } catch (e) { return validator.badParameter('addressOrPublicKey', addressOrPublicKey) } diff --git a/groups/sendTokens.js b/groups/sendTokens.js index 220aa3b..6e5da0d 100644 --- a/groups/sendTokens.js +++ b/groups/sendTokens.js @@ -37,7 +37,7 @@ module.exports = (nodeManager) => { } else { publicKey = addressOrPublicKey; try { - address = keys.createAddressFromPublicKey('publicKey') + address = keys.createAddressFromPublicKey(publicKey) } catch (e) { return validator.badParameter('addressOrPublicKey', addressOrPublicKey) } From a81615c4967497980133a5ea2e29a5df80b8dddb Mon Sep 17 00:00:00 2001 From: adamant-al Date: Fri, 28 May 2021 22:37:49 +0300 Subject: [PATCH 54/57] Comments --- groups/sendMessage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/groups/sendMessage.js b/groups/sendMessage.js index c93af24..991628c 100644 --- a/groups/sendMessage.js +++ b/groups/sendMessage.js @@ -11,13 +11,13 @@ const DEFAULT_SEND_MESSAGE_RETRIES = 4; // How much re-tries for send message re module.exports = (nodeManager) => { /** - * Creates Message transaction, signs it, and broadcasts to ADAMANT network. Supports Basic, Rich and Signal Message Types. + * Encrypts a message, creates Message transaction, signs it, and broadcasts to ADAMANT network. Supports Basic, Rich and Signal Message Types. * See https://github.com/Adamant-im/adamant/wiki/Message-Types * @param {string} passPhrase Senders's passPhrase. Sender's address will be derived from it. * @param {string} addressOrPublicKey Recipient's ADAMANT address or public key. * Using public key is faster, as the library wouldn't request it from the network. * Though we cache public keys, and next request with address will be processed as fast as with public key. - * @param {string} message Message plain text in case of basic message. Stringified JSON in case of rich or signal messages. + * @param {string} message Message plain text in case of basic message. Stringified JSON in case of rich or signal messages. The library will encrypt a message. * Example of rich message for Ether in-chat transfer: `{"type":"eth_transaction","amount":"0.002","hash":"0xfa46d2b3c99878f1f9863fcbdb0bc27d220d7065c6528543cbb83ced84487deb","comments":"I like to send it, send it"}` * @param {string, number} message_type Type of message: basic, rich, or signal * @param {string, number} amount Amount to send with a message From eb3a6f7a43c2bb607ff6c13b0626da37e4163144 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Fri, 28 May 2021 22:39:51 +0300 Subject: [PATCH 55/57] Export constants --- index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 01506f6..8a063f0 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,4 @@ +const constants = require('./helpers/constants.js'); const get = require('./groups/get'); const getPublicKey = require('./groups/getPublicKey'); const decodeMsg = require('./groups/decodeMsg'); @@ -9,7 +10,7 @@ const transactionFormer = require('./helpers/transactionFormer'); const keys = require('./helpers/keys'); const encryptor = require('./helpers/encryptor'); const socket = require('./helpers/wsClient'); -const logger = require('adamant-api/helpers/logger'); +const logger = require('./helpers/logger'); module.exports = (params, log) => { log = log || console; @@ -26,6 +27,7 @@ module.exports = (params, log) => { transactionFormer, keys, encryptor, - socket + socket, + constants }; }; From 36628f15d2f5adb36bacfd58db59e4c1b2504707 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Fri, 28 May 2021 22:43:11 +0300 Subject: [PATCH 56/57] Bupm version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4ace36a..b242447 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adamant-api", - "version": "1.0.0-beta.2", + "version": "1.0.0", "description": "REST API for ADAMANT Blockchain", "main": "index.js", "scripts": { From 930c90edb3a7ab26791f6173313a0428e4b3411d Mon Sep 17 00:00:00 2001 From: adamant-al Date: Fri, 28 May 2021 22:45:59 +0300 Subject: [PATCH 57/57] Upd readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c479182..f6c6169 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Features: * GET-requests to the blockchain * Sending tokens * Sending messages +* Caching public keys * Encrypting and decrypting of messages * Forming and signing transactions * Working with ADM key pairs