From d6df53af062823d16f1bdf70de32658e1d32f8e8 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev Date: Sun, 15 Nov 2020 12:45:11 +0300 Subject: [PATCH 01/36] Update .gitignore --- .gitignore | 5 +- README.md | 21 +- package-lock.json | 3094 --------------------------------------------- 3 files changed, 19 insertions(+), 3101 deletions(-) delete mode 100644 package-lock.json diff --git a/.gitignore b/.gitignore index 4a7c7e3..fd1de43 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ node_modules/ logs/ -config.test \ No newline at end of file +.vscode/ +config.test +package-lock.json +tests.js diff --git a/README.md b/README.md index 73b28de..41e880f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ ADAMANT InfoServices is a crypto and fiat currency rates service provider. It collects rates from MOEX, Coinmarketcap, CryptoCompare and Coingecko and calculates cross-rates, and provides information via API. Features: + - Collects rates from MOEX for fiat tickers - Collects rates from Coinmarketcap for crypto tickers - Collects rates from CryptoCompare for crypto tickers @@ -15,12 +16,15 @@ Features: - Free use for any purposes # Installation + ## Requirements -- Ubuntu 16 / Ubuntu 18 (other OS had not been tested) -- NodeJS v 8+ (already installed if you have a node on your machine) + +- Ubuntu 16 / Ubuntu 18 (we didn't test with others) +- NodeJS v 8+ - MongoDB ([installation instructions](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/)) ## Setup + ``` su - adamant git clone https://github.com/Adamant-im/adamant-currencyinfo-services @@ -29,12 +33,14 @@ npm i ``` ## Pre-launch tuning + ``` nano config.json ``` Parameters: -- `crypto_cmc` List of coins to fetch rates from Coincarketcap + +- `crypto_cmc` List of coins to fetch rates from Coinmarketcap - `crypto_cc` List of coins to fetch rates from Cryptocompare - `crypto_cg` List of coins to fetch rates from Coingecko. Better use `crypto_cg_coinids`. - `crypto_cg_coinids` List of Coingecko coin Ids to fetch rates from Coingecko. Used when one coin symbol is used for different coins. Coin ids can be seen on https://api.coingecko.com/api/v3/coins/list. @@ -49,20 +55,23 @@ Parameters: - `adamant_notify` ADM address to receive alerts for InfoService administrator. Recommended. - `passPhrase` The secret phrase for account you want to send alerts from. Obligatory in case of you set `adamant_notify` - `node_ADM` List of nodes for API work, obligatorily in case of you set `adamant_notify` - ## Launching + You can start ADAMANT InfoServices with `node app` command, but it is recommended to use process manager: + ``` -pm2 start --name info-service app.js +pm2 start --name info-service app.js ``` -## Add info-service to cron: +## Add info-service to cron + ``` crontab -e ``` Add string: + ``` @reboot cd /home/adamant/adamant-currencyinfo-services && pm2 start --name info-service app.js ``` diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index dccfa4d..0000000 --- a/package-lock.json +++ /dev/null @@ -1,3094 +0,0 @@ -{ - "name": "adamant-currencyinfo-services", - "version": "1.1.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "requires": { - "defer-to-connect": "^1.0.1" - } - }, - "@types/bignumber.js": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/bignumber.js/-/bignumber.js-5.0.0.tgz", - "integrity": "sha512-0DH7aPGCClywOFaxxjE6UwpN2kQYe9LwuDQMv+zYA97j5GkOMo8e66LYT+a8JYU7jfmUFRZLa9KycxHDsKXJCA==", - "requires": { - "bignumber.js": "*" - } - }, - "@types/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", - "requires": { - "@types/node": "*" - } - }, - "@types/concat-stream": { - "version": "1.6.0", - "resolved": "https://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": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", - "integrity": "sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=", - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "13.1.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.6.tgz", - "integrity": "sha512-Jg1F+bmxcpENHP23sVKkNuU3uaxPnsBMW0cLjleiikFKomJQbsn0Cqk2yDvQArqzZN6ABfBkZ0To7pQ8sLdWDg==" - }, - "@types/qs": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.0.tgz", - "integrity": "sha512-c4zji5CjWv1tJxIZkz1oUtGcdOlsH3aza28Nqmm+uNDWBRHoMsjooBEN4czZp1V3iXPihE/VRUOBqg+4Xq0W4g==" - }, - "@web3-js/scrypt-shim": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@web3-js/scrypt-shim/-/scrypt-shim-0.1.0.tgz", - "integrity": "sha512-ZtZeWCc/s0nMcdx/+rZwY1EcuRdemOK9ag21ty9UsHkFxsNb/AaoucUz0iPuyGe0Ku+PFuRmWZG7Z7462p9xPw==", - "requires": { - "scryptsy": "^2.1.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "@web3-js/websocket": { - "version": "1.0.30", - "resolved": "https://registry.npmjs.org/@web3-js/websocket/-/websocket-1.0.30.tgz", - "integrity": "sha512-fDwrD47MiDrzcJdSeTLF75aCcxVVt8B1N74rA+vh2XCAvFy4tEWJjtnUtj2QG7/zlQ6g9cQ88bZFBxwd9/FmtA==", - "requires": { - "debug": "^2.2.0", - "es5-ext": "^0.10.50", - "nan": "^2.14.0", - "typedarray-to-buffer": "^3.1.5", - "yaeti": "^0.0.6" - } - }, - "accepts": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", - "requires": { - "mime-types": "~2.1.18", - "negotiator": "0.6.1" - } - }, - "adamant-api": { - "version": "0.1.22", - "resolved": "https://registry.npmjs.org/adamant-api/-/adamant-api-0.1.22.tgz", - "integrity": "sha512-BuUkqtFP4x9999MLnPkn5NPs8+L3EM4OOqgo8TiJCOfNYGWZme+dtorSk58fyK1Zw4GwICADWdWkwAl5q/vEkQ==", - "requires": { - "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" - } - }, - "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.9.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz", - "integrity": "sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==", - "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" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "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" - } - }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "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.7", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.7.tgz", - "integrity": "sha512-zAKJGuQPihXW22fkrfOclUUZXM2g92z5GzlSMHxhO6r6Qj+Nm0ccaGNBzDZojzwOMkpjAv4J0fOv1U4go+a4iw==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" - }, - "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.1.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-8.1.1.tgz", - "integrity": "sha512-QD46ppGintwPGuL1KqmwhR0O+N2cZUg8JG/VzwI2e28sM9TqHjQB10lI4QAaMHVbLzwVLLAwEglpKPViWX+5NQ==" - }, - "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.16.0", - "resolved": "https://registry.npmjs.org/bitcore-lib/-/bitcore-lib-0.16.0.tgz", - "integrity": "sha512-CEtcrPAH2gwgaMN+OPMJc18TBEak1+TtzMyafrqrIbK9PIa3kat195qBJhC0liJSHRiRr6IE2eLcXeIFFs+U8w==", - "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.11" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" - } - } - }, - "bitcore-mnemonic": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/bitcore-mnemonic/-/bitcore-mnemonic-1.7.0.tgz", - "integrity": "sha512-1JV1okgz9Vv+Y4fG2m3ToR+BGdKA6tSoqjepIxA95BZjW6YaeopVW4iOe/dY9dnkZH4+LA2AJ4YbDE6H3ih3Yw==", - "requires": { - "bitcore-lib": "^0.16.0", - "unorm": "^1.4.1" - } - }, - "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", - "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" - }, - "body-parser": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", - "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", - "requires": { - "bytes": "3.0.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "~1.6.3", - "iconv-lite": "0.4.23", - "on-finished": "~2.3.0", - "qs": "6.5.2", - "raw-body": "2.3.3", - "type-is": "~1.6.16" - } - }, - "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" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" - } - }, - "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" - } - }, - "bson": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.0.tgz", - "integrity": "sha512-9Aeai9TacfNtWXOYarkFJRW2CWo+dRon+fuLZYJmvLV3+MiUp0bEI6IAZfXEIg7/Pl/7IWlLaDnhzTsD81etQA==" - }, - "buffer": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", - "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" - }, - "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-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" - }, - "buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" - }, - "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" - } - }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" - } - } - }, - "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.4", - "resolved": "https://registry.npmjs.org/chloride-test/-/chloride-test-1.2.4.tgz", - "integrity": "sha512-9vhoi1qXSBPn6//ZxIgSe3M2QhKHzIPZQzmrZgmPADsqW0Jxpe3db1e7aGSRUMXbxAQ04SfypdT8dGaSvIvKDw==", - "requires": { - "json-buffer": "^2.0.11" - } - }, - "chownr": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", - "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==" - }, - "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" - } - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "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" - } - }, - "commander": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", - "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", - "requires": { - "graceful-readlink": ">= 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" - } - }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "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=" - }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, - "create-ecdh": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", - "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - } - }, - "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==" - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "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": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", - "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", - "requires": { - "decompress-tar": "^4.0.0", - "decompress-tarbz2": "^4.0.0", - "decompress-targz": "^4.0.0", - "decompress-unzip": "^4.0.1", - "graceful-fs": "^4.1.10", - "make-dir": "^1.0.0", - "pify": "^2.3.0", - "strip-dirs": "^2.0.0" - } - }, - "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" - } - }, - "decompress-tar": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", - "requires": { - "file-type": "^5.2.0", - "is-stream": "^1.1.0", - "tar-stream": "^1.5.2" - } - }, - "decompress-tarbz2": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", - "requires": { - "decompress-tar": "^4.1.0", - "file-type": "^6.1.0", - "is-stream": "^1.1.0", - "seek-bzip": "^1.0.5", - "unbzip2-stream": "^1.0.9" - }, - "dependencies": { - "file-type": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==" - } - } - }, - "decompress-targz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", - "requires": { - "decompress-tar": "^4.1.1", - "file-type": "^5.2.0", - "is-stream": "^1.1.0" - } - }, - "decompress-unzip": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", - "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", - "requires": { - "file-type": "^3.8.0", - "get-stream": "^2.2.0", - "pify": "^2.3.0", - "yauzl": "^2.4.2" - }, - "dependencies": { - "file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" - }, - "get-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", - "requires": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" - } - } - } - }, - "defer-to-connect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.1.tgz", - "integrity": "sha512-J7thop4u3mRTkYRQ+Vpfwy2G5Ehoy82I14+14W4YMDLKdWloI9gSzRbV30s/NckQGVJtPkWNcW4oMAUigTdqiQ==" - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.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" - } - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, - "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" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "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" - } - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "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" - }, - "dependencies": { - "js-sha3": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" - } - } - }, - "eth-lib": { - "version": "0.1.29", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", - "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "nano-json-stream-parser": "^0.1.2", - "servify": "^0.1.12", - "ws": "^3.0.0", - "xhr-request-promise": "^0.1.2" - } - }, - "ethereum-bloom-filters": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.6.tgz", - "integrity": "sha512-dE9CGNzgOOsdh7msZirvv8qjHtnHpvBlKe2647kM8v+yeF71IRso55jpojemvHV+jMjr48irPWxMRaHuOWzAFA==", - "requires": { - "js-sha3": "^0.8.0" - } - }, - "ethereumjs-common": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.0.tgz", - "integrity": "sha512-SZOjgK1356hIY7MRj3/ma5qtfr/4B5BL+G4rP/XSMYr2z1H5el4RX5GReYCKmQmYI/nSBmRnwrZ17IfHuG0viQ==" - }, - "ethereumjs-tx": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz", - "integrity": "sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw==", - "requires": { - "ethereumjs-common": "^1.5.0", - "ethereumjs-util": "^6.0.0" - } - }, - "ethereumjs-util": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.0.tgz", - "integrity": "sha512-vb0XN9J2QGdZGIEKG2vXM+kUdEivUfU6Wmi5y0cg+LRhDYKnXIZ/Lz7XjFbHRR9VIKq2lVGLzGBkA++y2nOdOQ==", - "requires": { - "@types/bn.js": "^4.11.3", - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "0.1.6", - "keccak": "^2.0.0", - "rlp": "^2.2.3", - "secp256k1": "^3.0.1" - } - }, - "ethers": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", - "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", - "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.3", - "setimmediate": "1.0.4", - "uuid": "2.0.1", - "xmlhttprequest": "1.8.0" - }, - "dependencies": { - "@types/node": { - "version": "10.17.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz", - "integrity": "sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==" - }, - "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" - } - }, - "js-sha3": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" - }, - "setimmediate": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", - "integrity": "sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48=" - }, - "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.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" - }, - "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" - } - }, - "express": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", - "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", - "requires": { - "accepts": "~1.3.5", - "array-flatten": "1.1.1", - "body-parser": "1.18.3", - "content-disposition": "0.5.2", - "content-type": "~1.0.4", - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.1.1", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.4", - "qs": "6.5.2", - "range-parser": "~1.2.0", - "safe-buffer": "5.1.2", - "send": "0.16.2", - "serve-static": "1.13.2", - "setprototypeof": "1.1.0", - "statuses": "~1.4.0", - "type-is": "~1.6.16", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - } - }, - "ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "requires": { - "type": "^2.0.0" - }, - "dependencies": { - "type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", - "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==" - } - } - }, - "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=" - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "requires": { - "pend": "~1.2.0" - } - }, - "file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" - }, - "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==" - }, - "finalhandler": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", - "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.4.0", - "unpipe": "~1.0.0" - } - }, - "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" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "fs-extra": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "requires": { - "minipass": "^2.6.0" - } - }, - "get-port": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", - "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=" - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } - }, - "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" - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" - }, - "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-symbol-support-x": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", - "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" - }, - "has-to-string-tag-x": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", - "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", - "requires": { - "has-symbol-support-x": "^1.4.1" - } - }, - "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.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "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": "8.1.3", - "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", - "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", - "requires": { - "caseless": "^0.12.0", - "concat-stream": "^1.6.2", - "http-response-object": "^3.0.1", - "parse-cache-control": "^1.0.1" - } - }, - "http-cache-semantics": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", - "integrity": "sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==" - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "http-https": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", - "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" - }, - "http-response-object": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", - "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", - "requires": { - "@types/node": "^10.0.3" - }, - "dependencies": { - "@types/node": { - "version": "10.17.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz", - "integrity": "sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==" - } - } - }, - "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" - } - }, - "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "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=" - } - } - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ipaddr.js": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", - "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" - }, - "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-natural-number": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", - "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=" - }, - "is-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", - "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" - }, - "is-retry-allowed": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "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=" - }, - "isurl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", - "requires": { - "has-to-string-tag-x": "^1.2.0", - "is-object": "^1.0.1" - } - }, - "js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - }, - "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": "https://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=" - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsonminify": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/jsonminify/-/jsonminify-0.4.1.tgz", - "integrity": "sha1-gF2vuzk5UYjO6atYLIHvlZ1+cQw=" - }, - "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": "2.1.0", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-2.1.0.tgz", - "integrity": "sha512-m1wbJRTo+gWbctZWay9i26v5fFnYkOn7D5PCxJ3fZUGUEb49dE1Pm4BREUYCt/aoO6di7jeoGmhvqN9Nzylm3Q==", - "requires": { - "bindings": "^1.5.0", - "inherits": "^2.0.4", - "nan": "^2.14.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" - } - } - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "requires": { - "json-buffer": "3.0.0" - }, - "dependencies": { - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" - } - } - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - }, - "long": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", - "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" - }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - } - } - }, - "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" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "micex.api": { - "version": "github:zyuhel/micex.api#2e489883322a662e5575712c14efda42ed2dabab", - "from": "github:zyuhel/micex.api#2e48988", - "requires": { - "debug": "^2.2.0", - "lodash": ">=4.17.5", - "request": "^2.60.0" - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - } - }, - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" - }, - "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=" - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", - "requires": { - "minipass": "^2.9.0" - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "mkdirp-promise": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", - "integrity": "sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE=", - "requires": { - "mkdirp": "*" - } - }, - "mock-fs": { - "version": "4.10.4", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.10.4.tgz", - "integrity": "sha512-gDfZDLaPIvtOusbusLinfx6YSe2YpQsDT8qdP41P47dQ/NQggtkHukz7hwqgt8QvMBmAv+Z6DGmXPyb5BWX2nQ==" - }, - "mongodb": { - "version": "3.1.13", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.13.tgz", - "integrity": "sha512-sz2dhvBZQWf3LRNDhbd30KHVzdjZx9IKC0L+kSZ/gzYquCF5zPOgGqRz6sSCqYZtKP2ekB4nfLxhGtzGHnIKxA==", - "requires": { - "mongodb-core": "3.1.11", - "safe-buffer": "^5.1.2" - } - }, - "mongodb-core": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.1.11.tgz", - "integrity": "sha512-rD2US2s5qk/ckbiiGFHeu+yKYDXdJ1G87F6CG3YdaZpzdOm5zpoAZd/EKbPmFO6cQZ+XVXBXBJ660sSI0gc6qg==", - "requires": { - "bson": "^1.1.0", - "require_optional": "^1.0.1", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" - } - }, - "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==" - }, - "nano-json-stream-parser": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", - "integrity": "sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=" - }, - "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" - }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "normalize-url": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", - "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" - }, - "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=" - }, - "oboe": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", - "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", - "requires": { - "http-https": "^1.0.0" - } - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-timeout": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", - "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", - "requires": { - "p-finally": "^1.0.0" - } - }, - "parse-asn1": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", - "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", - "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.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.3", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.3.tgz", - "integrity": "sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==" - }, - "parseurl": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "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" - } - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "^2.0.0" - } - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" - }, - "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.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "promise": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.3.tgz", - "integrity": "sha512-HeRDUL1RJiLhyA0/grn+PTShlBAcLuh/1BJGtrvjwbvRDCTLLMEz9rOGCV+R3vHY4MixIuoMEd9Yq/XvsTPcjw==", - "requires": { - "asap": "~2.0.6" - } - }, - "proxy-addr": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", - "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.8.0" - } - }, - "psl": { - "version": "1.1.31", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", - "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" - }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "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" - } - }, - "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" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" - }, - "raw-body": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", - "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", - "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.3", - "iconv-lite": "0.4.23", - "unpipe": "1.0.0" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "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" - } - }, - "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" - } - }, - "require_optional": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", - "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", - "requires": { - "resolve-from": "^2.0.0", - "semver": "^5.1.0" - } - }, - "resolve-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" - }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "requires": { - "lowercase-keys": "^1.0.0" - } - }, - "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.4", - "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.4.tgz", - "integrity": "sha512-fdq2yYCWpAQBhwkZv+Z8o/Z4sPmYm1CUq6P7n6lVTOdb949CnqA0sndXal5C1NleSVSZm6q5F3iEbauyVln/iw==", - "requires": { - "bn.js": "^4.11.1" - } - }, - "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==" - }, - "saslprep": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.2.tgz", - "integrity": "sha512-4cDsYuAjXssUSjxHKRe4DTZC0agDwsCqcMqtJAQPzC74nJ7LfAJflAtC1Zed5hMzEQKj82d3tuzqdGNRsLJ4Gw==", - "optional": true, - "requires": { - "sparse-bitfield": "^3.0.3" - } - }, - "scrypt-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", - "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=" - }, - "scryptsy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-2.1.0.tgz", - "integrity": "sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w==" - }, - "secp256k1": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.8.0.tgz", - "integrity": "sha512-k5ke5avRZbtl9Tqx/SA7CbY3NF6Ro+Sj9cZxezFzuBlLDmyqPiL8hJJ+EmzD8Ig4LUDByHJ3/iPOVoRixs/hmw==", - "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.5.2", - "nan": "^2.14.0", - "safe-buffer": "^5.1.2" - }, - "dependencies": { - "elliptic": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", - "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", - "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" - } - } - } - }, - "seek-bzip": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", - "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", - "requires": { - "commander": "~2.8.1" - } - }, - "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" - }, - "send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" - } - }, - "serve-static": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", - "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.16.2" - } - }, - "servify": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", - "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", - "requires": { - "body-parser": "^1.16.0", - "cors": "^2.8.1", - "express": "^4.14.0", - "request": "^2.79.0", - "xhr": "^2.3.3" - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://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.6", - "resolved": "https://registry.npmjs.org/sodium-browserify-tweetnacl/-/sodium-browserify-tweetnacl-0.2.6.tgz", - "integrity": "sha512-ZnEI26hdluilpYY28Xc4rc1ALfmEp2TWihkJX6Mdtw0z9RfHfpZJU7P8DoKbN1HcBdU9aJmguFZs7igE8nLJPg==", - "requires": { - "chloride-test": "^1.1.0", - "ed2curve": "^0.1.4", - "sha.js": "^2.4.8", - "tweetnacl": "^1.0.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" - }, - "dependencies": { - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - } - } - }, - "tweetnacl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.1.tgz", - "integrity": "sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A==" - } - } - }, - "sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", - "optional": true, - "requires": { - "memory-pager": "^1.0.2" - } - }, - "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" - } - }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" - }, - "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_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-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", - "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", - "requires": { - "is-natural-number": "^4.0.1" - } - }, - "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" - } - }, - "swarm-js": { - "version": "0.1.39", - "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.39.tgz", - "integrity": "sha512-QLMqL2rzF6n5s50BptyD6Oi0R1aWlJC5Y17SRIVXRj6OR1DRIPM7nepvrxxkjA1zNzFz6mUOMjfeqeDaWB7OOg==", - "requires": { - "bluebird": "^3.5.0", - "buffer": "^5.0.5", - "decompress": "^4.0.0", - "eth-lib": "^0.1.26", - "fs-extra": "^4.0.2", - "got": "^7.1.0", - "mime-types": "^2.1.16", - "mkdirp-promise": "^5.0.1", - "mock-fs": "^4.1.0", - "setimmediate": "^1.0.5", - "tar": "^4.0.2", - "xhr-request-promise": "^0.1.2" - }, - "dependencies": { - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" - }, - "got": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", - "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", - "requires": { - "decompress-response": "^3.2.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-plain-obj": "^1.1.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "p-cancelable": "^0.3.0", - "p-timeout": "^1.1.1", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "url-parse-lax": "^1.0.0", - "url-to-options": "^1.0.1" - } - }, - "p-cancelable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", - "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==" - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "requires": { - "prepend-http": "^1.0.1" - } - } - } - }, - "sync-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", - "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", - "requires": { - "http-response-object": "^3.0.1", - "sync-rpc": "^1.2.1", - "then-request": "^6.0.0" - } - }, - "sync-rpc": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", - "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", - "requires": { - "get-port": "^3.1.0" - } - }, - "tar": { - "version": "4.4.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", - "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - } - }, - "tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" - } - }, - "then-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", - "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", - "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": "^8.1.1", - "http-response-object": "^3.0.1", - "promise": "^8.0.0", - "qs": "^6.4.0" - }, - "dependencies": { - "@types/node": { - "version": "8.10.59", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.59.tgz", - "integrity": "sha512-8RkBivJrDCyPpBXhVZcjh7cQxVBSmRk9QM7hOketZzp6Tg79c0N8kkpAIito9bnJ3HCVCHVYz+KHTEbfQNfeVQ==" - } - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "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=" - }, - "to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" - }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" - }, - "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=" - } - } - }, - "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" - } - }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "type-is": { - "version": "1.6.16", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.18" - } - }, - "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" - } - }, - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" - }, - "unbzip2-stream": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", - "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", - "requires": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "underscore": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", - "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, - "unorm": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", - "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==" - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "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-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "requires": { - "prepend-http": "^2.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=" - }, - "url-to-options": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", - "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" - }, - "utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", - "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "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.2.4", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.4.tgz", - "integrity": "sha512-xPXGe+w0x0t88Wj+s/dmAdASr3O9wmA9mpZRtixGZxmBexAF0MjfqYM+MS4tVl5s11hMTN3AZb8cDD4VLfC57A==", - "requires": { - "@types/node": "^12.6.1", - "web3-bzz": "1.2.4", - "web3-core": "1.2.4", - "web3-eth": "1.2.4", - "web3-eth-personal": "1.2.4", - "web3-net": "1.2.4", - "web3-shh": "1.2.4", - "web3-utils": "1.2.4" - }, - "dependencies": { - "@types/node": { - "version": "12.12.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.24.tgz", - "integrity": "sha512-1Ciqv9pqwVtW6FsIUKSZNB82E5Cu1I2bBTj1xuIHXLe/1zYLl3956Nbhg2MzSYHVfl9/rmanjbQIb7LibfCnug==" - } - } - }, - "web3-bzz": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.4.tgz", - "integrity": "sha512-MqhAo/+0iQSMBtt3/QI1rU83uvF08sYq8r25+OUZ+4VtihnYsmkkca+rdU0QbRyrXY2/yGIpI46PFdh0khD53A==", - "requires": { - "@types/node": "^10.12.18", - "got": "9.6.0", - "swarm-js": "0.1.39", - "underscore": "1.9.1" - }, - "dependencies": { - "@types/node": { - "version": "10.17.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz", - "integrity": "sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==" - } - } - }, - "web3-core": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.4.tgz", - "integrity": "sha512-CHc27sMuET2cs1IKrkz7xzmTdMfZpYswe7f0HcuyneTwS1yTlTnHyqjAaTy0ZygAb/x4iaVox+Gvr4oSAqSI+A==", - "requires": { - "@types/bignumber.js": "^5.0.0", - "@types/bn.js": "^4.11.4", - "@types/node": "^12.6.1", - "web3-core-helpers": "1.2.4", - "web3-core-method": "1.2.4", - "web3-core-requestmanager": "1.2.4", - "web3-utils": "1.2.4" - }, - "dependencies": { - "@types/node": { - "version": "12.12.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.24.tgz", - "integrity": "sha512-1Ciqv9pqwVtW6FsIUKSZNB82E5Cu1I2bBTj1xuIHXLe/1zYLl3956Nbhg2MzSYHVfl9/rmanjbQIb7LibfCnug==" - } - } - }, - "web3-core-helpers": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.4.tgz", - "integrity": "sha512-U7wbsK8IbZvF3B7S+QMSNP0tni/6VipnJkB0tZVEpHEIV2WWeBHYmZDnULWcsS/x/jn9yKhJlXIxWGsEAMkjiw==", - "requires": { - "underscore": "1.9.1", - "web3-eth-iban": "1.2.4", - "web3-utils": "1.2.4" - } - }, - "web3-core-method": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.4.tgz", - "integrity": "sha512-8p9kpL7di2qOVPWgcM08kb+yKom0rxRCMv6m/K+H+yLSxev9TgMbCgMSbPWAHlyiF3SJHw7APFKahK5Z+8XT5A==", - "requires": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.4", - "web3-core-promievent": "1.2.4", - "web3-core-subscriptions": "1.2.4", - "web3-utils": "1.2.4" - } - }, - "web3-core-promievent": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.4.tgz", - "integrity": "sha512-gEUlm27DewUsfUgC3T8AxkKi8Ecx+e+ZCaunB7X4Qk3i9F4C+5PSMGguolrShZ7Zb6717k79Y86f3A00O0VAZw==", - "requires": { - "any-promise": "1.3.0", - "eventemitter3": "3.1.2" - } - }, - "web3-core-requestmanager": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.4.tgz", - "integrity": "sha512-eZJDjyNTDtmSmzd3S488nR/SMJtNnn/GuwxnMh3AzYCqG3ZMfOylqTad2eYJPvc2PM5/Gj1wAMQcRpwOjjLuPg==", - "requires": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.4", - "web3-providers-http": "1.2.4", - "web3-providers-ipc": "1.2.4", - "web3-providers-ws": "1.2.4" - } - }, - "web3-core-subscriptions": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.4.tgz", - "integrity": "sha512-3D607J2M8ymY9V+/WZq4MLlBulwCkwEjjC2U+cXqgVO1rCyVqbxZNCmHyNYHjDDCxSEbks9Ju5xqJxDSxnyXEw==", - "requires": { - "eventemitter3": "3.1.2", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.4" - } - }, - "web3-eth": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.4.tgz", - "integrity": "sha512-+j+kbfmZsbc3+KJpvHM16j1xRFHe2jBAniMo1BHKc3lho6A8Sn9Buyut6odubguX2AxoRArCdIDCkT9hjUERpA==", - "requires": { - "underscore": "1.9.1", - "web3-core": "1.2.4", - "web3-core-helpers": "1.2.4", - "web3-core-method": "1.2.4", - "web3-core-subscriptions": "1.2.4", - "web3-eth-abi": "1.2.4", - "web3-eth-accounts": "1.2.4", - "web3-eth-contract": "1.2.4", - "web3-eth-ens": "1.2.4", - "web3-eth-iban": "1.2.4", - "web3-eth-personal": "1.2.4", - "web3-net": "1.2.4", - "web3-utils": "1.2.4" - } - }, - "web3-eth-abi": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.4.tgz", - "integrity": "sha512-8eLIY4xZKoU3DSVu1pORluAw9Ru0/v4CGdw5so31nn+7fR8zgHMgwbFe0aOqWQ5VU42PzMMXeIJwt4AEi2buFg==", - "requires": { - "ethers": "4.0.0-beta.3", - "underscore": "1.9.1", - "web3-utils": "1.2.4" - } - }, - "web3-eth-accounts": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.4.tgz", - "integrity": "sha512-04LzT/UtWmRFmi4hHRewP5Zz43fWhuHiK5XimP86sUQodk/ByOkXQ3RoXyGXFMNoRxdcAeRNxSfA2DpIBc9xUw==", - "requires": { - "@web3-js/scrypt-shim": "^0.1.0", - "any-promise": "1.3.0", - "crypto-browserify": "3.12.0", - "eth-lib": "0.2.7", - "ethereumjs-common": "^1.3.2", - "ethereumjs-tx": "^2.1.1", - "underscore": "1.9.1", - "uuid": "3.3.2", - "web3-core": "1.2.4", - "web3-core-helpers": "1.2.4", - "web3-core-method": "1.2.4", - "web3-utils": "1.2.4" - }, - "dependencies": { - "eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - } - } - }, - "web3-eth-contract": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.4.tgz", - "integrity": "sha512-b/9zC0qjVetEYnzRA1oZ8gF1OSSUkwSYi5LGr4GeckLkzXP7osEnp9lkO/AQcE4GpG+l+STnKPnASXJGZPgBRQ==", - "requires": { - "@types/bn.js": "^4.11.4", - "underscore": "1.9.1", - "web3-core": "1.2.4", - "web3-core-helpers": "1.2.4", - "web3-core-method": "1.2.4", - "web3-core-promievent": "1.2.4", - "web3-core-subscriptions": "1.2.4", - "web3-eth-abi": "1.2.4", - "web3-utils": "1.2.4" - } - }, - "web3-eth-ens": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.4.tgz", - "integrity": "sha512-g8+JxnZlhdsCzCS38Zm6R/ngXhXzvc3h7bXlxgKU4coTzLLoMpgOAEz71GxyIJinWTFbLXk/WjNY0dazi9NwVw==", - "requires": { - "eth-ens-namehash": "2.0.8", - "underscore": "1.9.1", - "web3-core": "1.2.4", - "web3-core-helpers": "1.2.4", - "web3-core-promievent": "1.2.4", - "web3-eth-abi": "1.2.4", - "web3-eth-contract": "1.2.4", - "web3-utils": "1.2.4" - } - }, - "web3-eth-iban": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.4.tgz", - "integrity": "sha512-D9HIyctru/FLRpXakRwmwdjb5bWU2O6UE/3AXvRm6DCOf2e+7Ve11qQrPtaubHfpdW3KWjDKvlxV9iaFv/oTMQ==", - "requires": { - "bn.js": "4.11.8", - "web3-utils": "1.2.4" - } - }, - "web3-eth-personal": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.4.tgz", - "integrity": "sha512-5Russ7ZECwHaZXcN3DLuLS7390Vzgrzepl4D87SD6Sn1DHsCZtvfdPIYwoTmKNp69LG3mORl7U23Ga5YxqkICw==", - "requires": { - "@types/node": "^12.6.1", - "web3-core": "1.2.4", - "web3-core-helpers": "1.2.4", - "web3-core-method": "1.2.4", - "web3-net": "1.2.4", - "web3-utils": "1.2.4" - }, - "dependencies": { - "@types/node": { - "version": "12.12.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.24.tgz", - "integrity": "sha512-1Ciqv9pqwVtW6FsIUKSZNB82E5Cu1I2bBTj1xuIHXLe/1zYLl3956Nbhg2MzSYHVfl9/rmanjbQIb7LibfCnug==" - } - } - }, - "web3-net": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.4.tgz", - "integrity": "sha512-wKOsqhyXWPSYTGbp7ofVvni17yfRptpqoUdp3SC8RAhDmGkX6irsiT9pON79m6b3HUHfLoBilFQyt/fTUZOf7A==", - "requires": { - "web3-core": "1.2.4", - "web3-core-method": "1.2.4", - "web3-utils": "1.2.4" - } - }, - "web3-providers-http": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.4.tgz", - "integrity": "sha512-dzVCkRrR/cqlIrcrWNiPt9gyt0AZTE0J+MfAu9rR6CyIgtnm1wFUVVGaxYRxuTGQRO4Dlo49gtoGwaGcyxqiTw==", - "requires": { - "web3-core-helpers": "1.2.4", - "xhr2-cookies": "1.1.0" - } - }, - "web3-providers-ipc": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.4.tgz", - "integrity": "sha512-8J3Dguffin51gckTaNrO3oMBo7g+j0UNk6hXmdmQMMNEtrYqw4ctT6t06YOf9GgtOMjSAc1YEh3LPrvgIsR7og==", - "requires": { - "oboe": "2.1.4", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.4" - } - }, - "web3-providers-ws": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.4.tgz", - "integrity": "sha512-F/vQpDzeK+++oeeNROl1IVTufFCwCR2hpWe5yRXN0ApLwHqXrMI7UwQNdJ9iyibcWjJf/ECbauEEQ8CHgE+MYQ==", - "requires": { - "@web3-js/websocket": "^1.0.29", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.4" - } - }, - "web3-shh": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.4.tgz", - "integrity": "sha512-z+9SCw0dE+69Z/Hv8809XDbLj7lTfEv9Sgu8eKEIdGntZf4v7ewj5rzN5bZZSz8aCvfK7Y6ovz1PBAu4QzS4IQ==", - "requires": { - "web3-core": "1.2.4", - "web3-core-method": "1.2.4", - "web3-core-subscriptions": "1.2.4", - "web3-net": "1.2.4" - } - }, - "web3-utils": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.4.tgz", - "integrity": "sha512-+S86Ip+jqfIPQWvw2N/xBQq5JNqCO0dyvukGdJm8fEWHZbckT4WxSpHbx+9KLEWY4H4x9pUwnoRkK87pYyHfgQ==", - "requires": { - "bn.js": "4.11.8", - "eth-lib": "0.2.7", - "ethereum-bloom-filters": "^1.0.6", - "ethjs-unit": "0.1.6", - "number-to-bn": "1.7.0", - "randombytes": "^2.1.0", - "underscore": "1.9.1", - "utf8": "3.0.0" - }, - "dependencies": { - "eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - }, - "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.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "yaeti": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - } - } -} From 592d24e3f7bb185d6980464e4f6056d3fbc2bdc9 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev Date: Sun, 15 Nov 2020 13:50:44 +0300 Subject: [PATCH 02/36] Add VXC and update package description --- config.json | 2 +- package.json | 47 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/config.json b/config.json index 5219482..acbdeb3 100644 --- a/config.json +++ b/config.json @@ -2,7 +2,7 @@ "crypto_cmc": ["ADM", "BTC", "ETH", "DASH", "LSK", "DOGE", "BZ", "BCH", "USDT", "LTC", "TRX", "BSV", "BNB", "XMR", "XEM", "NEO", "ETC", "USDC", "ZEC", "TUSD", "KCS", "USDS"], "crypto_cc": [], "crypto_cg": [], - "crypto_cg_coinids": ["resfinex-token"], + "crypto_cg_coinids": ["resfinex-token", "vinx-coin"], "baseCoins": ["USD", "RUB", "EUR", "CNY", "JPY", "BTC", "ETH"], "fiat": { "USD/RUB": "USDRUB_TOM", diff --git a/package.json b/package.json index 7c36991..99e6df0 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,56 @@ { "name": "adamant-currencyinfo-services", - "version": "2.0.0", - "description": "", + "version": "2.1.0", + "description": "Crypto and fiat currency rates service provider. MOEX, Coinmarketcap, CryptoCompare and Coingecko.", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, - "author": "", - "license": "ISC", + "keywords": [ + "blockchain", + "bitcoin", + "ethereum", + "trading", + "trade", + "adm", + "adamant", + "exchange", + "crypto", + "cryptocurrency", + "coingecko", + "coinmarketcap", + "cryptocompare", + "ticker", + "rate", + "exchange rate", + "moex", + "fiat", + "money", + "usd", + "eur", + "cny", + "jpy", + "rub", + "btc", + "eth" + ], + "author": "ADAMANT Dev Team, Aleksei Lebedev (https://adamant.im)", + "license": "GPL-3.0", "dependencies": { "adamant-api": "^0.1.22", "body-parser": "^1.18.3", "jsonminify": "^0.4.1", "express": "^4.16.4", - "micex.api": "zyuhel/micex.api#2e48988", "mongodb": "^3.1.13", "request": "^2.88.0", "underscore": "^1.9.1" - } + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Adamant-im/adamant-currencyinfo-services.git" + }, + "bugs": { + "url": "https://github.com/Adamant-im/adamant-currencyinfo-services/issues" + }, + "homepage": "https://github.com/Adamant-im/adamant-currencyinfo-services#readme" } From 140e5927e9e9c763bdfaca5213314ca95b3c0967 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev Date: Sun, 15 Nov 2020 14:51:38 +0300 Subject: [PATCH 03/36] Update notify --- helpers/notify.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/helpers/notify.js b/helpers/notify.js index 374e30c..011c41c 100644 --- a/helpers/notify.js +++ b/helpers/notify.js @@ -4,7 +4,9 @@ const log = require('./log'); const api = require('../modules/api'); module.exports = (message, type) => { + try { + log[type](message.replace(/\*/g, '').replace(/_/g, '')); if (!config.slack && !config.adamant_notify) { @@ -16,18 +18,16 @@ module.exports = (message, type) => { case ('error'): color = '#FF0000'; break; - case ('warn'): color = '#FFFF00'; break; - case ('info'): color = '#00FF00'; break; case ('log'): - color = '#ffffff'; + color = '#FFFFFF'; break; - } + } const opts = { uri: config.slack, method: 'POST', @@ -41,7 +41,7 @@ module.exports = (message, type) => { }] } }; - if (config.slack && config.slack.length > 5) { + if (config.slack && config.slack.length > 35) { request(opts); } if (config.adamant_notify && config.adamant_notify.length > 5 && config.adamant_notify.startsWith('U') && config.passPhrase && config.passPhrase.length > 30) { From f509455bc1a364948fa230021e4c522869d868da Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 10 Jan 2022 00:07:00 +0300 Subject: [PATCH 04/36] Update readme --- README.md | 4 ++-- config.json | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 41e880f..e93c0a8 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ Features: ## Requirements -- Ubuntu 16 / Ubuntu 18 (we didn't test with others) -- NodeJS v 8+ +- Ubuntu 18 / 20 (we didn't test with others) +- NodeJS v12+ - MongoDB ([installation instructions](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/)) ## Setup diff --git a/config.json b/config.json index acbdeb3..44ca557 100644 --- a/config.json +++ b/config.json @@ -1,8 +1,9 @@ { - "crypto_cmc": ["ADM", "BTC", "ETH", "DASH", "LSK", "DOGE", "BZ", "BCH", "USDT", "LTC", "TRX", "BSV", "BNB", "XMR", "XEM", "NEO", "ETC", "USDC", "ZEC", "TUSD", "KCS", "USDS"], + "crypto_cmc": ["BTC", "ETH", "DASH", "LSK", "DOGE", "BZ", "BCH", "USDT", "LTC", "TRX", + "BSV", "BNB", "XMR", "XEM", "NEO", "ETC", "USDC", "ZEC", "TUSD", "KCS", "USDS"], "crypto_cc": [], "crypto_cg": [], - "crypto_cg_coinids": ["resfinex-token", "vinx-coin"], + "crypto_cg_coinids": ["adamant-messenger", "resfinex-token"], "baseCoins": ["USD", "RUB", "EUR", "CNY", "JPY", "BTC", "ETH"], "fiat": { "USD/RUB": "USDRUB_TOM", @@ -16,8 +17,8 @@ "cgApiKey": "No need for Coingecko API key", "port": 36668, "refreshInterval": 10, - "slack": "https://hooks.slack.com/services/", - "adamant_notify": "", + "slack": "https://hooks.slack.com/services/..", + "adamant_notify": "", "passPhrase": "joy logic job estate kite", "node_ADM": [ "http://localhost:36666", From 9c9437c6509f796ea6f5d480e41502c1e076fc79 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 10 Jan 2022 00:18:30 +0300 Subject: [PATCH 05/36] Add devDependencies --- .eslintrc.js | 87 +++++++++++---------------- app.js | 108 +++++++++++++++++----------------- config.json | 62 ++++++++++---------- db/mongodb.js | 126 ++++++++++++++++++++-------------------- helpers/configReader.js | 12 ++-- helpers/getCc.js | 52 ++++++++--------- helpers/getCg.js | 94 +++++++++++++++--------------- helpers/getCmc.js | 66 ++++++++++----------- helpers/getMoex.js | 66 ++++++++++----------- helpers/log.js | 76 ++++++++++++------------ helpers/notify.js | 84 +++++++++++++-------------- modules/router.js | 74 +++++++++++------------ package.json | 12 ++++ 13 files changed, 456 insertions(+), 463 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 26c15fc..b0b1e8f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,54 +1,35 @@ module.exports = { - "parserOptions": { - "ecmaVersion": 6, - "sourceType": "module", - "ecmaFeatures": { - "experimentalObjectRestSpread": true - } - }, - "rules": { - "semi": "warn", // обязательно ; - "semi-spacing": ["error", { - "before": false, - "after": true - }], - "indent": ["error", "tab"], - "space-infix-ops": "error", // отступы вокруг + - * / = и тд - "eqeqeq": "error", // обязательно === и !== (нельзя == и !=) - // "no-eq-null": "error", // обязательно === и !== (нельзя == и !=) но тоько в отношении null - "curly": "error", // проверка шаблонов `${name}` - "space-before-function-paren": [ // отступ до и после function - "error", { - "anonymous": "always", - "named": "always", - "asyncArrow": "ignore" - } - ], - "key-spacing": ["error", { - "mode": "strict" - }], // оформление обЪекта - "space-in-parens": ["error", "never"], // запрет отступов ( a,b) - "computed-property-spacing": ["error", "never"], // запрет лишних отступов в выражениях a[ i] - "array-bracket-spacing": ["error", "never"], - "no-multi-spaces": "error", // запрет лишних пробелов var a = 2 - "no-sparse-arrays": "warn", // предупреждение при дырке в массиве - "no-mixed-spaces-and-tabs": "error", // нельзя миксовать табы и пробелы - "keyword-spacing": ["error", { - "after": true - }], - "comma-spacing": ["error", { - "before": false, - "after": true - }], // отступ после запятой, а перед нельзя - "no-undef": "error", - "array-callback-return": "error" // коллбек методов массива типа arr.map arr.filter должны иметь return в коллбеке - }, - "env": { - "node": true - }, - "globals": { - "Promise": true, - "Symbol": true - }, - "plugins": [] -} \ No newline at end of file + env: { + commonjs: true, + es2021: true, + node: true, + }, + extends: [ + 'google', + ], + parserOptions: { + ecmaVersion: 12, + }, + rules: { + 'object-curly-spacing': ['error', 'always'], + 'max-len': ['error', + { 'code': 131, + 'ignoreTrailingComments': true, + 'ignoreUrls': true, + 'ignoreStrings': true, + 'ignoreTemplateLiterals': true, + 'ignoreRegExpLiterals': true, + }], + 'require-jsdoc': ['off'], + 'valid-jsdoc': ['off'], + 'no-array-constructor': ['off'], + 'no-caller': ['off'], + 'prefer-promise-reject-errors': ['off'], + 'guard-for-in': ['off'], + 'no-unused-vars': ['off'], + 'padded-blocks': ['off'], + 'new-cap': ['off'], + 'camelcase': ['off'], + 'eqeqeq': ['error', 'always'], + }, +}; diff --git a/app.js b/app.js index 754d9ec..e156551 100644 --- a/app.js +++ b/app.js @@ -14,55 +14,55 @@ let fetched; router(tickers); function refresh () { - - log.info('------------ Rates update started -------------'); - - fetched = true; - Cmc('USD', data => { - if (data) { - Object.assign(tickers, data); - } else { - fetched = false; - notify(`Error: Unable to get data from Coinmarketcap. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); - } + + log.info('------------ Rates update started -------------'); + + fetched = true; + Cmc('USD', data => { + if (data) { + Object.assign(tickers, data); + } else { + fetched = false; + notify(`Error: Unable to get data from Coinmarketcap. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); + } - Moex(data => { - if (data) { - Object.assign(tickers, data); - } else { - fetched = false; - notify(`Error: Unable to get data from MOEX. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); - } + Moex(data => { + if (data) { + Object.assign(tickers, data); + } else { + fetched = false; + notify(`Error: Unable to get data from MOEX. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); + } - Cc('USD', data => { - if (data) { - Object.assign(tickers, data); - } else { - fetched = false; - notify(`Error: Unable to get data from CryptoCompare. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); - } + Cc('USD', data => { + if (data) { + Object.assign(tickers, data); + } else { + fetched = false; + notify(`Error: Unable to get data from CryptoCompare. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); + } - Cg('USD', data => { - if (data) { - Object.assign(tickers, data); - } else { - fetched = false; - notify(`Error: Unable to get data from Coingecko. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); - } - - converter(tickers); - if (fetched) { - try { - db.save(tickers); - log.info('New rates from all sources saved successfully'); - } catch (e) { - notify(`Error: Unable to save new rates in history database: ${e}`, 'error'); - } - } - }); // Coingecko - }); // Cryptocompare - }); // Moex - }); // Coinmarketcap + Cg('USD', data => { + if (data) { + Object.assign(tickers, data); + } else { + fetched = false; + notify(`Error: Unable to get data from Coingecko. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); + } + + converter(tickers); + if (fetched) { + try { + db.save(tickers); + log.info('New rates from all sources saved successfully'); + } catch (e) { + notify(`Error: Unable to save new rates in history database: ${e}`, 'error'); + } + } + }); // Coingecko + }); // Cryptocompare + }); // Moex + }); // Coinmarketcap } // refresh @@ -70,12 +70,12 @@ setTimeout(refresh, 5000); setInterval(refresh, config.refreshInterval * 60000); function converter (tickers) { - config.baseCoins.forEach(b => { - const price = tickers['USD/' + b] || 1 / tickers[b + '/USD']; - if (!price) {return;} - config.crypto_all.forEach(c => { - const priceAlt = 1 / tickers[c + '/USD']; - tickers[c + '/' + b] = +(price / priceAlt).toFixed(8); - }); - }); + config.baseCoins.forEach(b => { + const price = tickers['USD/' + b] || 1 / tickers[b + '/USD']; + if (!price) {return;} + config.crypto_all.forEach(c => { + const priceAlt = 1 / tickers[c + '/USD']; + tickers[c + '/' + b] = +(price / priceAlt).toFixed(8); + }); + }); } \ No newline at end of file diff --git a/config.json b/config.json index 44ca557..42717f7 100644 --- a/config.json +++ b/config.json @@ -1,34 +1,34 @@ { - "crypto_cmc": ["BTC", "ETH", "DASH", "LSK", "DOGE", "BZ", "BCH", "USDT", "LTC", "TRX", - "BSV", "BNB", "XMR", "XEM", "NEO", "ETC", "USDC", "ZEC", "TUSD", "KCS", "USDS"], - "crypto_cc": [], - "crypto_cg": [], - "crypto_cg_coinids": ["adamant-messenger", "resfinex-token"], - "baseCoins": ["USD", "RUB", "EUR", "CNY", "JPY", "BTC", "ETH"], - "fiat": { - "USD/RUB": "USDRUB_TOM", - "EUR/RUB": "EURRUB_TOM", - "GBR/RUB": "GBPRUB_TOM", - "CNY/RUB": "CNYRUB_TOM", - "JPY/RUB": "JPYRUB_TOD" - }, - "cmcApiKey": "Put yours Coinmarketcap API key", - "ccApiKey": "Put yours CryptoCompare API key", - "cgApiKey": "No need for Coingecko API key", - "port": 36668, - "refreshInterval": 10, - "slack": "https://hooks.slack.com/services/..", + "crypto_cmc": ["BTC", "ETH", "DASH", "LSK", "DOGE", "BZ", "BCH", "USDT", "LTC", "TRX", + "BSV", "BNB", "XMR", "XEM", "NEO", "ETC", "USDC", "ZEC", "TUSD", "KCS", "USDS"], + "crypto_cc": [], + "crypto_cg": [], + "crypto_cg_coinids": ["adamant-messenger", "resfinex-token"], + "baseCoins": ["USD", "RUB", "EUR", "CNY", "JPY", "BTC", "ETH"], + "fiat": { + "USD/RUB": "USDRUB_TOM", + "EUR/RUB": "EURRUB_TOM", + "GBR/RUB": "GBPRUB_TOM", + "CNY/RUB": "CNYRUB_TOM", + "JPY/RUB": "JPYRUB_TOD" + }, + "cmcApiKey": "Put yours Coinmarketcap API key", + "ccApiKey": "Put yours CryptoCompare API key", + "cgApiKey": "No need for Coingecko API key", + "port": 36668, + "refreshInterval": 10, + "slack": "https://hooks.slack.com/services/..", "adamant_notify": "", - "passPhrase": "joy logic job estate kite", - "node_ADM": [ - "http://localhost:36666", - "https://endless.adamant.im", - "https://clown.adamant.im", - "https://bid.adamant.im", - "https://unusual.adamant.im", - "https://debate.adamant.im", - "http://185.231.245.26:36666", - "http://80.211.177.181:36666", - "https://lake.adamant.im" - ] + "passPhrase": "joy logic job estate kite", + "node_ADM": [ + "http://localhost:36666", + "https://endless.adamant.im", + "https://clown.adamant.im", + "https://bid.adamant.im", + "https://unusual.adamant.im", + "https://debate.adamant.im", + "http://185.231.245.26:36666", + "http://80.211.177.181:36666", + "https://lake.adamant.im" + ] } diff --git a/db/mongodb.js b/db/mongodb.js index eb0143d..1c9d364 100644 --- a/db/mongodb.js +++ b/db/mongodb.js @@ -2,85 +2,85 @@ const log = require('../helpers/log'); const MongoClient = require("mongodb").MongoClient; const mongoClient = new MongoClient("mongodb://localhost:27017/", { - useNewUrlParser: true + useNewUrlParser: true }); let TickersDB; mongoClient.connect((err, client) => { - if (err) { - throw (err); - } - const db = client.db("tickersdb"); - TickersDB = db.collection("tickers"); + if (err) { + throw (err); + } + const db = client.db("tickersdb"); + TickersDB = db.collection("tickers"); }); // module.exports.save = (tickers, cb) => { -// TickersDB.insertOne({ -// date: new Date().getTime(), -// tickers -// }, (err, result) => { -// if (err){ -// cb(false); -// } else { -// cb(result); -// } -// }); +// TickersDB.insertOne({ +// date: new Date().getTime(), +// tickers +// }, (err, result) => { +// if (err){ +// cb(false); +// } else { +// cb(result); +// } +// }); // }; module.exports.save = (tickers) => { - TickersDB.insertOne({ - date: new Date().getTime(), - tickers - }); + TickersDB.insertOne({ + date: new Date().getTime(), + tickers + }); }; module.exports.getHistory = (params, cb) => { - try { - if (!Object.keys(params).length) { - cb(false, 'Provide parameters for getHistory request'); - return; - } + try { + if (!Object.keys(params).length) { + cb(false, 'Provide parameters for getHistory request'); + return; + } - let {limit, from, to, timestamp, coin} = params; - const q = {}; + let {limit, from, to, timestamp, coin} = params; + const q = {}; - if (from && to){ - q.date = { $gte: +from * 1000, $lte: +to * 1000}; - limit = limit || 100; - if (+from > +to) { - cb(false, `Wrong time interval: 'to' should be more, than 'from'`); - return; - } - } - if (timestamp){ - q.date = {$lte: timestamp * 1000}; - limit = 1; - } - limit = Math.min(100, limit); + if (from && to){ + q.date = { $gte: +from * 1000, $lte: +to * 1000}; + limit = limit || 100; + if (+from > +to) { + cb(false, `Wrong time interval: 'to' should be more, than 'from'`); + return; + } + } + if (timestamp){ + q.date = {$lte: timestamp * 1000}; + limit = 1; + } + limit = Math.min(100, limit); - TickersDB.find(q) - .sort({date: -1}) - .limit(+limit) - .toArray((err, docs) => { - if (err){ - cb(false, err); - } else { - if (coin){ - docs.tickers = docs.forEach(d =>{ - Object.keys(d.tickers).forEach(pair =>{ - if (!~pair.indexOf(coin)){ - delete d.tickers[pair]; - } - }); - }); - } - cb(docs); - } - }); - } catch (e){ - cb(false, e); - log.error('Error at getHistory: ', params, e); - } + TickersDB.find(q) + .sort({date: -1}) + .limit(+limit) + .toArray((err, docs) => { + if (err){ + cb(false, err); + } else { + if (coin){ + docs.tickers = docs.forEach(d =>{ + Object.keys(d.tickers).forEach(pair =>{ + if (!~pair.indexOf(coin)){ + delete d.tickers[pair]; + } + }); + }); + } + cb(docs); + } + }); + } catch (e){ + cb(false, e); + log.error('Error at getHistory: ', params, e); + } }; \ No newline at end of file diff --git a/helpers/configReader.js b/helpers/configReader.js index fba979e..822464f 100644 --- a/helpers/configReader.js +++ b/helpers/configReader.js @@ -5,13 +5,13 @@ const isDev = process.argv.includes('dev'); let config = {}; try { - if (isDev) { - config = JSON.parse(jsonminify(fs.readFileSync('./config.test', 'utf-8'))); - } else { - config = JSON.parse(jsonminify(fs.readFileSync('./config.json', 'utf-8'))); - } + if (isDev) { + config = JSON.parse(jsonminify(fs.readFileSync('./config.test', 'utf-8'))); + } else { + config = JSON.parse(jsonminify(fs.readFileSync('./config.json', 'utf-8'))); + } } catch (e) { - log.error('Error reading config: ' + e); + log.error('Error reading config: ' + e); } config.isDev = isDev; diff --git a/helpers/getCc.js b/helpers/getCc.js index d1b8142..e89bf33 100644 --- a/helpers/getCc.js +++ b/helpers/getCc.js @@ -8,36 +8,36 @@ module.exports = (base, cb) => { if (!config.crypto_cc || config.crypto_cc.length == 0 || !config.ccApiKey) { cb({}); - return; + return; } - request( - 'https://min-api.cryptocompare.com/data/pricemulti', { - qs: { - fsyms: config.crypto_cc.join(), - tsyms: base, + request( + 'https://min-api.cryptocompare.com/data/pricemulti', { + qs: { + fsyms: config.crypto_cc.join(), + tsyms: base, api_key: config.ccApiKey - }, - json: true, - }, (err, res, body) => { - if (err) { - notify(`Unable to process request to min-api.cryptocompare.com`, 'error'); - cb(false); - return; - } - try { + }, + json: true, + }, (err, res, body) => { + if (err) { + notify(`Unable to process request to min-api.cryptocompare.com`, 'error'); + cb(false); + return; + } + try { const info = body; - const data = {}; - config.crypto_cc.forEach(t => { - data[t + '/' + base] = +info[t][base].toFixed(8); - }); + const data = {}; + config.crypto_cc.forEach(t => { + data[t + '/' + base] = +info[t][base].toFixed(8); + }); - cb(data); - log.info(`CryptoCompare rates updated against ${base} successfully`) - } catch (e) { - notify(`Unable to process data from request to min-api.cryptocompare.com. Wrong CryptoCompare API key? Error: ${e}`, 'error'); - cb(false); - } + cb(data); + log.info(`CryptoCompare rates updated against ${base} successfully`) + } catch (e) { + notify(`Unable to process data from request to min-api.cryptocompare.com. Wrong CryptoCompare API key? Error: ${e}`, 'error'); + cb(false); + } - }); + }); }; \ No newline at end of file diff --git a/helpers/getCg.js b/helpers/getCg.js index e1148eb..96f05ee 100644 --- a/helpers/getCg.js +++ b/helpers/getCg.js @@ -9,32 +9,32 @@ function getCgCoinIds() { config.crypto_cg_full = []; if ((!config.crypto_cg || config.crypto_cg.length == 0) && (!config.crypto_cg_coinids || config.crypto_cg_coinids.length == 0)) { - return; + return; } request( - 'https://api.coingecko.com/api/v3/coins/list', { - json: true, - }, (err, res, body) => { - if (err) { - notify(`Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko.`, 'error'); - return; - } - try { - const info = body; - config.crypto_cg.forEach(t => { - const currency = _.findWhere(info, { - symbol: t.toLowerCase() + 'https://api.coingecko.com/api/v3/coins/list', { + json: true, + }, (err, res, body) => { + if (err) { + notify(`Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko.`, 'error'); + return; + } + try { + const info = body; + config.crypto_cg.forEach(t => { + const currency = _.findWhere(info, { + symbol: t.toLowerCase() }); cg_crypto = { symbol: t, cg_id: currency.id } config.crypto_cg_full.push(cg_crypto) - }); - config.crypto_cg_coinids.forEach(t => { - const currency = _.findWhere(info, { - id: t + }); + config.crypto_cg_coinids.forEach(t => { + const currency = _.findWhere(info, { + id: t }); cg_crypto = { symbol: currency.symbol.toUpperCase(), @@ -45,11 +45,11 @@ function getCgCoinIds() { config.crypto_all = config.crypto_all.concat(config.crypto_cg_full.map(e => e.symbol)); log.info(`Coingecko coin ids fetched successfully`) - } catch (e) { - notify(`Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko. Error: ${e}`, 'error'); - } + } catch (e) { + notify(`Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko. Error: ${e}`, 'error'); + } - }); + }); } @@ -59,35 +59,35 @@ module.exports = (base, cb) => { if (!config.crypto_cg_full || config.crypto_cg_full.length == 0) { cb({}); - return; + return; } - request( - 'https://api.coingecko.com/api/v3/simple/price', { - qs: { - ids: config.crypto_cg_full.map(e => e.cg_id).join(","), // join string by field cg_id - vs_currencies: base - }, - json: true, - }, (err, res, body) => { - if (err) { - notify(`Unable to process request to api.coingecko.com`, 'error'); - cb(false); - return; - } - try { - const info = body; - const data = {}; - config.crypto_cg_full.forEach(t => { + request( + 'https://api.coingecko.com/api/v3/simple/price', { + qs: { + ids: config.crypto_cg_full.map(e => e.cg_id).join(","), // join string by field cg_id + vs_currencies: base + }, + json: true, + }, (err, res, body) => { + if (err) { + notify(`Unable to process request to api.coingecko.com`, 'error'); + cb(false); + return; + } + try { + const info = body; + const data = {}; + config.crypto_cg_full.forEach(t => { data[t['symbol'] + '/' + base] = +info[t['cg_id']][base.toLowerCase()].toFixed(8); - }); + }); - cb(data); - log.info(`Coingecko rates updated against ${base} successfully`) - } catch (e) { - notify(`Unable to process data from request to api.coingecko.com. Error: ${e}`, 'error'); - cb(false); - } + cb(data); + log.info(`Coingecko rates updated against ${base} successfully`) + } catch (e) { + notify(`Unable to process data from request to api.coingecko.com. Error: ${e}`, 'error'); + cb(false); + } - }); + }); }; \ No newline at end of file diff --git a/helpers/getCmc.js b/helpers/getCmc.js index 0d66714..246c10e 100644 --- a/helpers/getCmc.js +++ b/helpers/getCmc.js @@ -8,41 +8,41 @@ module.exports = (base, cb) => { if (!config.crypto_cmc || config.crypto_cmc.length == 0 || !config.cmcApiKey) { cb({}); - return; + return; } - request( - 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest', { - qs: { - symbol: config.crypto_cmc.join(), - convert: base - }, - headers: { - 'X-CMC_PRO_API_KEY': config.cmcApiKey - }, - json: true, - }, (err, res, body) => { - if (err) { - notify(`Unable to process request to pro-api.coinmarketcap.com`, 'error'); - cb(false); - return; - } - try { - const info = body.data; - const data = {}; - config.crypto_cmc.forEach(t => { - const currency = _.findWhere(info, { - symbol: t - }); - data[t + '/' + base] = +currency.quote[base].price.toFixed(8); - }); + request( + 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest', { + qs: { + symbol: config.crypto_cmc.join(), + convert: base + }, + headers: { + 'X-CMC_PRO_API_KEY': config.cmcApiKey + }, + json: true, + }, (err, res, body) => { + if (err) { + notify(`Unable to process request to pro-api.coinmarketcap.com`, 'error'); + cb(false); + return; + } + try { + const info = body.data; + const data = {}; + config.crypto_cmc.forEach(t => { + const currency = _.findWhere(info, { + symbol: t + }); + data[t + '/' + base] = +currency.quote[base].price.toFixed(8); + }); - cb(data); - log.info(`Coinmarketcap rates updated against ${base} successfully`) - } catch (e) { - notify(`Unable to process data from request to pro-api.coinmarketcap.com. Wrong Coinmarketcap API key? Error: ${e}`, 'error'); - cb(false); - } + cb(data); + log.info(`Coinmarketcap rates updated against ${base} successfully`) + } catch (e) { + notify(`Unable to process data from request to pro-api.coinmarketcap.com. Wrong Coinmarketcap API key? Error: ${e}`, 'error'); + cb(false); + } - }); + }); }; \ No newline at end of file diff --git a/helpers/getMoex.js b/helpers/getMoex.js index e49c8d5..78e30fc 100644 --- a/helpers/getMoex.js +++ b/helpers/getMoex.js @@ -5,37 +5,37 @@ const log = require('./log'); const notify = require('./notify'); module.exports = (cb) => { - request('https://iss.moex.com/iss/engines/currency/markets/selt/securities.jsonp', {json: true}, (err, response, body) => { - try { - if (err) { - notify(`Unable to process request to iss.moex.com`, 'error'); - cb(false); - return; - } - const data = {}; - const info = body.securities.data; - Object.keys(config.fiat).forEach(m => { - const code = config.fiat[m]; - const c = _.findWhere(info, { - 2: code - }); - let price = (c[14] + c[15]) / 2; - if (m === 'JPY/RUB') - price /= 100; - data[m] = +price.toFixed(8); - if (m === 'USD/RUB') { - data['RUB/USD'] = +(1 / data['USD/RUB']).toFixed(8); - } else { - const market = 'USD/' + m.replace('/RUB', ''); - const price = data['USD/RUB'] / data[m]; - data[market] = +price.toFixed(8); - } - }); - cb(data); - log.info(`MOEX rates updated successfully`) - } catch (e) { - notify(`Unable to process request to iss.moex.com. Error: ${e}`, 'error'); - cb(false); - } - }); + request('https://iss.moex.com/iss/engines/currency/markets/selt/securities.jsonp', {json: true}, (err, response, body) => { + try { + if (err) { + notify(`Unable to process request to iss.moex.com`, 'error'); + cb(false); + return; + } + const data = {}; + const info = body.securities.data; + Object.keys(config.fiat).forEach(m => { + const code = config.fiat[m]; + const c = _.findWhere(info, { + 2: code + }); + let price = (c[14] + c[15]) / 2; + if (m === 'JPY/RUB') + price /= 100; + data[m] = +price.toFixed(8); + if (m === 'USD/RUB') { + data['RUB/USD'] = +(1 / data['USD/RUB']).toFixed(8); + } else { + const market = 'USD/' + m.replace('/RUB', ''); + const price = data['USD/RUB'] / data[m]; + data[market] = +price.toFixed(8); + } + }); + cb(data); + log.info(`MOEX rates updated successfully`) + } catch (e) { + notify(`Unable to process request to iss.moex.com. Error: ${e}`, 'error'); + cb(false); + } + }); }; diff --git a/helpers/log.js b/helpers/log.js index dce93f0..6739b00 100644 --- a/helpers/log.js +++ b/helpers/log.js @@ -1,10 +1,10 @@ let fs = require('fs'); if (!fs.existsSync('./logs')) { - fs.mkdirSync('./logs'); + fs.mkdirSync('./logs'); } let infoStr = fs.createWriteStream('./logs/' + date() + '.log', { - flags: 'a' + flags: 'a' }); infoStr.write(` @@ -12,50 +12,50 @@ _________________${fullTime()}_________________ `); module.exports = { - error(str) { - infoStr.write(` - ` + 'InfoService error|' + time() + '|' + str); - console.log('\x1b[31m', 'error|' + time(), '\x1b[0m', str); - }, - info(str) { - console.log('\x1b[32m', 'info|' + time(), '\x1b[0m', str); - - infoStr.write(` - ` + 'InfoService info|' + time() + '|' + str); - }, - warn(str) { - console.log('\x1b[33m', 'warn|' + time(), '\x1b[0m', str); - - infoStr.write(` - ` + 'InfoService warn|' + time() + '|' + str); - }, - log(str) { - console.log('\x1b[34m', 'log|' + time(), '\x1b[0m', str); - - infoStr.write(` - ` + 'InfoService log|[' + time() + '|' + str); - } + error(str) { + infoStr.write(` + ` + 'InfoService error|' + time() + '|' + str); + console.log('\x1b[31m', 'error|' + time(), '\x1b[0m', str); + }, + info(str) { + console.log('\x1b[32m', 'info|' + time(), '\x1b[0m', str); + + infoStr.write(` + ` + 'InfoService info|' + time() + '|' + str); + }, + warn(str) { + console.log('\x1b[33m', 'warn|' + time(), '\x1b[0m', str); + + infoStr.write(` + ` + 'InfoService warn|' + time() + '|' + str); + }, + log(str) { + console.log('\x1b[34m', 'log|' + time(), '\x1b[0m', str); + + infoStr.write(` + ` + 'InfoService log|[' + time() + '|' + str); + } }; function time() { - var options = { - hour: 'numeric', - minute: 'numeric', - second: 'numeric' - }; + var options = { + hour: 'numeric', + minute: 'numeric', + second: 'numeric' + }; - return new Date().toLocaleString('en', options); + return new Date().toLocaleString('en', options); } function date() { - var options = { - day: 'numeric', - month: 'numeric', - year: 'numeric' - }; - return (new Date().toLocaleString('en', options)).replace(/\//g, '-'); + var options = { + day: 'numeric', + month: 'numeric', + year: 'numeric' + }; + return (new Date().toLocaleString('en', options)).replace(/\//g, '-'); } function fullTime() { - return date() + ' ' + time(); + return date() + ' ' + time(); } diff --git a/helpers/notify.js b/helpers/notify.js index 011c41c..8ad47fa 100644 --- a/helpers/notify.js +++ b/helpers/notify.js @@ -5,49 +5,49 @@ const api = require('../modules/api'); module.exports = (message, type) => { - try { + try { - log[type](message.replace(/\*/g, '').replace(/_/g, '')); + log[type](message.replace(/\*/g, '').replace(/_/g, '')); - if (!config.slack && !config.adamant_notify) { - return; - } + if (!config.slack && !config.adamant_notify) { + return; + } - let color; - switch (type) { - case ('error'): - color = '#FF0000'; - break; - case ('warn'): - color = '#FFFF00'; - break; - case ('info'): - color = '#00FF00'; - break; - case ('log'): - color = '#FFFFFF'; - break; - } - const opts = { - uri: config.slack, - method: 'POST', - json: true, - body: { - 'attachments': [{ - 'fallback': message, - 'color': color, - 'text': message, - 'mrkdwn_in': ['text'] - }] - } - }; - if (config.slack && config.slack.length > 35) { - request(opts); - } - if (config.adamant_notify && config.adamant_notify.length > 5 && config.adamant_notify.startsWith('U') && config.passPhrase && config.passPhrase.length > 30) { - api.send(config.passPhrase, config.adamant_notify, `${type}| ${message.replace(/\*/g, '**')}`, 'message'); - } - } catch (e) { - log.error('Notifier error: ' + e); - } + let color; + switch (type) { + case ('error'): + color = '#FF0000'; + break; + case ('warn'): + color = '#FFFF00'; + break; + case ('info'): + color = '#00FF00'; + break; + case ('log'): + color = '#FFFFFF'; + break; + } + const opts = { + uri: config.slack, + method: 'POST', + json: true, + body: { + 'attachments': [{ + 'fallback': message, + 'color': color, + 'text': message, + 'mrkdwn_in': ['text'] + }] + } + }; + if (config.slack && config.slack.length > 35) { + request(opts); + } + if (config.adamant_notify && config.adamant_notify.length > 5 && config.adamant_notify.startsWith('U') && config.passPhrase && config.passPhrase.length > 30) { + api.send(config.passPhrase, config.adamant_notify, `${type}| ${message.replace(/\*/g, '**')}`, 'message'); + } + } catch (e) { + log.error('Notifier error: ' + e); + } }; diff --git a/modules/router.js b/modules/router.js index caeb1ae..11e54a3 100644 --- a/modules/router.js +++ b/modules/router.js @@ -10,57 +10,57 @@ let tickers; app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ - extended: true + extended: true })); app.get('/get', (req, res) => { - let coins = req.query.coin; - if (!coins) { - res.json(respSuccess(tickers)); - } else { - coins = coins.toUpperCase(); - const filterredTickers = {}; - let arrCoins = [coins]; - if (~coins.indexOf(',')) { - arrCoins = coins.split(','); - } - arrCoins.forEach(coin => { - const filteredMarkets = Object.keys(tickers).filter(c => ~c.indexOf(coin.trim())); - filteredMarkets.forEach(c => filterredTickers[c] = tickers[c]); - }); - res.json(respSuccess(filterredTickers)); - } + let coins = req.query.coin; + if (!coins) { + res.json(respSuccess(tickers)); + } else { + coins = coins.toUpperCase(); + const filterredTickers = {}; + let arrCoins = [coins]; + if (~coins.indexOf(',')) { + arrCoins = coins.split(','); + } + arrCoins.forEach(coin => { + const filteredMarkets = Object.keys(tickers).filter(c => ~c.indexOf(coin.trim())); + filteredMarkets.forEach(c => filterredTickers[c] = tickers[c]); + }); + res.json(respSuccess(filterredTickers)); + } }); app.get('/getHistory', (req, res) => { - db.getHistory(req.query, (h, msg) => { - if (h){ - res.json(respSuccess(h)); - } else { - res.json(respError(msg)); - } - }); + db.getHistory(req.query, (h, msg) => { + if (h){ + res.json(respSuccess(h)); + } else { + res.json(respError(msg)); + } + }); }); module.exports = (tickers_) => { - tickers = tickers_; + tickers = tickers_; }; app.listen(config.port, () => notify('ADAMANT-INFO server is listening on port ' + config.port, 'info')); function respSuccess (data) { - if (Object.entries(data).length === 0 && data.constructor === Object) // Empty object - return respError('No data available') - else return { - success: true, - date: new Date().getTime(), - result: data - }; + if (Object.entries(data).length === 0 && data.constructor === Object) // Empty object + return respError('No data available') + else return { + success: true, + date: new Date().getTime(), + result: data + }; } function respError (msg) { - return { - success: false, - date: new Date().getTime(), - msg - }; + return { + success: false, + date: new Date().getTime(), + msg + }; } \ No newline at end of file diff --git a/package.json b/package.json index 99e6df0..ce9eef7 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,11 @@ "description": "Crypto and fiat currency rates service provider. MOEX, Coinmarketcap, CryptoCompare and Coingecko.", "main": "index.js", "scripts": { + "lint": "npx eslint -f visualstudio .", + "lint:fix": "npx eslint -f visualstudio --fix", + "lint:fixrule": "npx eslint -f visualstudio --no-eslintrc --fix --env node,es2021,commonjs --parser-options=ecmaVersion:12 --rule", + "start": "node app.js", + "start:dev": "node app.js dev", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ @@ -45,6 +50,13 @@ "request": "^2.88.0", "underscore": "^1.9.1" }, + "devDependencies": { + "eslint": "^7.32.0", + "eslint-config-google": "^0.14.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^5.1.1" + }, "repository": { "type": "git", "url": "git+https://github.com/Adamant-im/adamant-currencyinfo-services.git" From 9aa62ec1e08391b94617a15afab05ac9021897d6 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 10 Jan 2022 00:21:45 +0300 Subject: [PATCH 06/36] Fix LF endline --- db/mongodb.js | 170 +++++++++++++++++++++++++------------------------- 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/db/mongodb.js b/db/mongodb.js index 1c9d364..3718f41 100644 --- a/db/mongodb.js +++ b/db/mongodb.js @@ -1,86 +1,86 @@ -const log = require('../helpers/log'); -const MongoClient = require("mongodb").MongoClient; - -const mongoClient = new MongoClient("mongodb://localhost:27017/", { - useNewUrlParser: true -}); - -let TickersDB; - -mongoClient.connect((err, client) => { - if (err) { - throw (err); - } - const db = client.db("tickersdb"); - TickersDB = db.collection("tickers"); -}); - -// module.exports.save = (tickers, cb) => { -// TickersDB.insertOne({ -// date: new Date().getTime(), -// tickers -// }, (err, result) => { -// if (err){ -// cb(false); -// } else { -// cb(result); -// } -// }); -// }; - - -module.exports.save = (tickers) => { - TickersDB.insertOne({ - date: new Date().getTime(), - tickers - }); -}; - -module.exports.getHistory = (params, cb) => { - try { - if (!Object.keys(params).length) { - cb(false, 'Provide parameters for getHistory request'); - return; - } - - let {limit, from, to, timestamp, coin} = params; - const q = {}; - - if (from && to){ - q.date = { $gte: +from * 1000, $lte: +to * 1000}; - limit = limit || 100; - if (+from > +to) { - cb(false, `Wrong time interval: 'to' should be more, than 'from'`); - return; - } - } - if (timestamp){ - q.date = {$lte: timestamp * 1000}; - limit = 1; - } - limit = Math.min(100, limit); - - TickersDB.find(q) - .sort({date: -1}) - .limit(+limit) - .toArray((err, docs) => { - if (err){ - cb(false, err); - } else { - if (coin){ - docs.tickers = docs.forEach(d =>{ - Object.keys(d.tickers).forEach(pair =>{ - if (!~pair.indexOf(coin)){ - delete d.tickers[pair]; - } - }); - }); - } - cb(docs); - } - }); - } catch (e){ - cb(false, e); - log.error('Error at getHistory: ', params, e); - } +const log = require('../helpers/log'); +const MongoClient = require("mongodb").MongoClient; + +const mongoClient = new MongoClient("mongodb://localhost:27017/", { + useNewUrlParser: true +}); + +let TickersDB; + +mongoClient.connect((err, client) => { + if (err) { + throw (err); + } + const db = client.db("tickersdb"); + TickersDB = db.collection("tickers"); +}); + +// module.exports.save = (tickers, cb) => { +// TickersDB.insertOne({ +// date: new Date().getTime(), +// tickers +// }, (err, result) => { +// if (err){ +// cb(false); +// } else { +// cb(result); +// } +// }); +// }; + + +module.exports.save = (tickers) => { + TickersDB.insertOne({ + date: new Date().getTime(), + tickers + }); +}; + +module.exports.getHistory = (params, cb) => { + try { + if (!Object.keys(params).length) { + cb(false, 'Provide parameters for getHistory request'); + return; + } + + let {limit, from, to, timestamp, coin} = params; + const q = {}; + + if (from && to){ + q.date = { $gte: +from * 1000, $lte: +to * 1000}; + limit = limit || 100; + if (+from > +to) { + cb(false, `Wrong time interval: 'to' should be more, than 'from'`); + return; + } + } + if (timestamp){ + q.date = {$lte: timestamp * 1000}; + limit = 1; + } + limit = Math.min(100, limit); + + TickersDB.find(q) + .sort({date: -1}) + .limit(+limit) + .toArray((err, docs) => { + if (err){ + cb(false, err); + } else { + if (coin){ + docs.tickers = docs.forEach(d =>{ + Object.keys(d.tickers).forEach(pair =>{ + if (!~pair.indexOf(coin)){ + delete d.tickers[pair]; + } + }); + }); + } + cb(docs); + } + }); + } catch (e){ + cb(false, e); + log.error('Error at getHistory: ', params, e); + } }; \ No newline at end of file From ce2e020aaf3a0d5e543d2220e1920760163b1bfa Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 10 Jan 2022 00:28:05 +0300 Subject: [PATCH 07/36] Lint fixes --- app.js | 23 ++++---- db/mongodb.js | 60 ++++++++++---------- helpers/getCc.js | 60 ++++++++++---------- helpers/getCg.js | 137 ++++++++++++++++++++++----------------------- helpers/getCmc.js | 68 +++++++++++----------- helpers/getMoex.js | 82 +++++++++++++-------------- modules/router.js | 134 ++++++++++++++++++++++---------------------- 7 files changed, 282 insertions(+), 282 deletions(-) diff --git a/app.js b/app.js index e156551..0c58174 100644 --- a/app.js +++ b/app.js @@ -13,12 +13,11 @@ let fetched; router(tickers); -function refresh () { - +function refresh() { log.info('------------ Rates update started -------------'); - + fetched = true; - Cmc('USD', data => { + Cmc('USD', (data) => { if (data) { Object.assign(tickers, data); } else { @@ -26,7 +25,7 @@ function refresh () { notify(`Error: Unable to get data from Coinmarketcap. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); } - Moex(data => { + Moex((data) => { if (data) { Object.assign(tickers, data); } else { @@ -34,7 +33,7 @@ function refresh () { notify(`Error: Unable to get data from MOEX. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); } - Cc('USD', data => { + Cc('USD', (data) => { if (data) { Object.assign(tickers, data); } else { @@ -42,14 +41,14 @@ function refresh () { notify(`Error: Unable to get data from CryptoCompare. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); } - Cg('USD', data => { + Cg('USD', (data) => { if (data) { Object.assign(tickers, data); } else { fetched = false; notify(`Error: Unable to get data from Coingecko. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); } - + converter(tickers); if (fetched) { try { @@ -69,13 +68,13 @@ function refresh () { setTimeout(refresh, 5000); setInterval(refresh, config.refreshInterval * 60000); -function converter (tickers) { - config.baseCoins.forEach(b => { +function converter(tickers) { + config.baseCoins.forEach((b) => { const price = tickers['USD/' + b] || 1 / tickers[b + '/USD']; if (!price) {return;} - config.crypto_all.forEach(c => { + config.crypto_all.forEach((c) => { const priceAlt = 1 / tickers[c + '/USD']; tickers[c + '/' + b] = +(price / priceAlt).toFixed(8); }); }); -} \ No newline at end of file +} diff --git a/db/mongodb.js b/db/mongodb.js index 3718f41..6a0f968 100644 --- a/db/mongodb.js +++ b/db/mongodb.js @@ -1,8 +1,8 @@ const log = require('../helpers/log'); -const MongoClient = require("mongodb").MongoClient; +const MongoClient = require('mongodb').MongoClient; -const mongoClient = new MongoClient("mongodb://localhost:27017/", { - useNewUrlParser: true +const mongoClient = new MongoClient('mongodb://localhost:27017/', { + useNewUrlParser: true, }); let TickersDB; @@ -11,8 +11,8 @@ mongoClient.connect((err, client) => { if (err) { throw (err); } - const db = client.db("tickersdb"); - TickersDB = db.collection("tickers"); + const db = client.db('tickersdb'); + TickersDB = db.collection('tickers'); }); // module.exports.save = (tickers, cb) => { @@ -32,7 +32,7 @@ mongoClient.connect((err, client) => { module.exports.save = (tickers) => { TickersDB.insertOne({ date: new Date().getTime(), - tickers + tickers, }); }; @@ -43,44 +43,44 @@ module.exports.getHistory = (params, cb) => { return; } - let {limit, from, to, timestamp, coin} = params; + let { limit, from, to, timestamp, coin } = params; const q = {}; - if (from && to){ - q.date = { $gte: +from * 1000, $lte: +to * 1000}; + if (from && to) { + q.date = { $gte: +from * 1000, $lte: +to * 1000 }; limit = limit || 100; if (+from > +to) { cb(false, `Wrong time interval: 'to' should be more, than 'from'`); return; } } - if (timestamp){ - q.date = {$lte: timestamp * 1000}; + if (timestamp) { + q.date = { $lte: timestamp * 1000 }; limit = 1; } limit = Math.min(100, limit); TickersDB.find(q) - .sort({date: -1}) - .limit(+limit) - .toArray((err, docs) => { - if (err){ - cb(false, err); - } else { - if (coin){ - docs.tickers = docs.forEach(d =>{ - Object.keys(d.tickers).forEach(pair =>{ - if (!~pair.indexOf(coin)){ - delete d.tickers[pair]; - } + .sort({ date: -1 }) + .limit(+limit) + .toArray((err, docs) => { + if (err) { + cb(false, err); + } else { + if (coin) { + docs.tickers = docs.forEach(d =>{ + Object.keys(d.tickers).forEach(pair =>{ + if (!~pair.indexOf(coin)) { + delete d.tickers[pair]; + } + }); }); - }); + } + cb(docs); } - cb(docs); - } - }); - } catch (e){ + }); + } catch (e) { cb(false, e); log.error('Error at getHistory: ', params, e); - } -}; \ No newline at end of file + } +}; diff --git a/helpers/getCc.js b/helpers/getCc.js index e89bf33..a9cf791 100644 --- a/helpers/getCc.js +++ b/helpers/getCc.js @@ -6,38 +6,38 @@ const notify = require('./notify'); module.exports = (base, cb) => { - if (!config.crypto_cc || config.crypto_cc.length == 0 || !config.ccApiKey) { - cb({}); + if (!config.crypto_cc || config.crypto_cc.length == 0 || !config.ccApiKey) { + cb({}); return; - } + } request( - 'https://min-api.cryptocompare.com/data/pricemulti', { - qs: { - fsyms: config.crypto_cc.join(), - tsyms: base, - api_key: config.ccApiKey - }, - json: true, - }, (err, res, body) => { - if (err) { - notify(`Unable to process request to min-api.cryptocompare.com`, 'error'); - cb(false); - return; - } - try { - const info = body; - const data = {}; - config.crypto_cc.forEach(t => { - data[t + '/' + base] = +info[t][base].toFixed(8); - }); + 'https://min-api.cryptocompare.com/data/pricemulti', { + qs: { + fsyms: config.crypto_cc.join(), + tsyms: base, + api_key: config.ccApiKey, + }, + json: true, + }, (err, res, body) => { + if (err) { + notify(`Unable to process request to min-api.cryptocompare.com`, 'error'); + cb(false); + return; + } + try { + const info = body; + const data = {}; + config.crypto_cc.forEach(t => { + data[t + '/' + base] = +info[t][base].toFixed(8); + }); - cb(data); - log.info(`CryptoCompare rates updated against ${base} successfully`) - } catch (e) { - notify(`Unable to process data from request to min-api.cryptocompare.com. Wrong CryptoCompare API key? Error: ${e}`, 'error'); - cb(false); - } + cb(data); + log.info(`CryptoCompare rates updated against ${base} successfully`); + } catch (e) { + notify(`Unable to process data from request to min-api.cryptocompare.com. Wrong CryptoCompare API key? Error: ${e}`, 'error'); + cb(false); + } - }); -}; \ No newline at end of file + }); +}; diff --git a/helpers/getCg.js b/helpers/getCg.js index 96f05ee..395ed47 100644 --- a/helpers/getCg.js +++ b/helpers/getCg.js @@ -6,88 +6,87 @@ const notify = require('./notify'); function getCgCoinIds() { - config.crypto_cg_full = []; + config.crypto_cg_full = []; - if ((!config.crypto_cg || config.crypto_cg.length == 0) && (!config.crypto_cg_coinids || config.crypto_cg_coinids.length == 0)) { + if ((!config.crypto_cg || config.crypto_cg.length === 0) && (!config.crypto_cg_coinids || config.crypto_cg_coinids.length === 0)) { return; - } + } - request( - 'https://api.coingecko.com/api/v3/coins/list', { - json: true, - }, (err, res, body) => { - if (err) { - notify(`Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko.`, 'error'); - return; - } - try { - const info = body; - config.crypto_cg.forEach(t => { - const currency = _.findWhere(info, { - symbol: t.toLowerCase() - }); - cg_crypto = { - symbol: t, - cg_id: currency.id - } - config.crypto_cg_full.push(cg_crypto) - }); - config.crypto_cg_coinids.forEach(t => { - const currency = _.findWhere(info, { - id: t - }); - cg_crypto = { - symbol: currency.symbol.toUpperCase(), - cg_id: t - } - config.crypto_cg_full.push(cg_crypto) - }); - config.crypto_all = config.crypto_all.concat(config.crypto_cg_full.map(e => e.symbol)); - - log.info(`Coingecko coin ids fetched successfully`) - } catch (e) { - notify(`Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko. Error: ${e}`, 'error'); - } + request( + 'https://api.coingecko.com/api/v3/coins/list', { + json: true, + }, (err, res, body) => { + if (err) { + notify(`Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko.`, 'error'); + return; + } + try { + const info = body; + config.crypto_cg.forEach(t => { + const currency = _.findWhere(info, { + symbol: t.toLowerCase(), + }); + cg_crypto = { + symbol: t, + cg_id: currency.id, + } + config.crypto_cg_full.push(cg_crypto); + }); + config.crypto_cg_coinids.forEach(t => { + const currency = _.findWhere(info, { + id: t, + }); + cg_crypto = { + symbol: currency.symbol.toUpperCase(), + cg_id: t, + } + config.crypto_cg_full.push(cg_crypto) + }); + config.crypto_all = config.crypto_all.concat(config.crypto_cg_full.map(e => e.symbol)); + log.info(`Coingecko coin ids fetched successfully`) + } catch (e) { + notify(`Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko. Error: ${e}`, 'error'); + } + + }); - }); - } getCgCoinIds(); module.exports = (base, cb) => { - if (!config.crypto_cg_full || config.crypto_cg_full.length == 0) { - cb({}); + if (!config.crypto_cg_full || config.crypto_cg_full.length == 0) { + cb({}); return; - } + } request( - 'https://api.coingecko.com/api/v3/simple/price', { - qs: { - ids: config.crypto_cg_full.map(e => e.cg_id).join(","), // join string by field cg_id - vs_currencies: base - }, - json: true, - }, (err, res, body) => { - if (err) { - notify(`Unable to process request to api.coingecko.com`, 'error'); - cb(false); - return; - } - try { - const info = body; - const data = {}; - config.crypto_cg_full.forEach(t => { - data[t['symbol'] + '/' + base] = +info[t['cg_id']][base.toLowerCase()].toFixed(8); - }); + 'https://api.coingecko.com/api/v3/simple/price', { + qs: { + ids: config.crypto_cg_full.map(e => e.cg_id).join(","), // join string by field cg_id + vs_currencies: base, + }, + json: true, + }, (err, res, body) => { + if (err) { + notify(`Unable to process request to api.coingecko.com`, 'error'); + cb(false); + return; + } + try { + const info = body; + const data = {}; + config.crypto_cg_full.forEach(t => { + data[t['symbol'] + '/' + base] = +info[t['cg_id']][base.toLowerCase()].toFixed(8); + }); - cb(data); - log.info(`Coingecko rates updated against ${base} successfully`) - } catch (e) { - notify(`Unable to process data from request to api.coingecko.com. Error: ${e}`, 'error'); - cb(false); - } + cb(data); + log.info(`Coingecko rates updated against ${base} successfully`); + } catch (e) { + notify(`Unable to process data from request to api.coingecko.com. Error: ${e}`, 'error'); + cb(false); + } - }); + }); }; \ No newline at end of file diff --git a/helpers/getCmc.js b/helpers/getCmc.js index 246c10e..18b9ba5 100644 --- a/helpers/getCmc.js +++ b/helpers/getCmc.js @@ -6,43 +6,43 @@ const notify = require('./notify'); module.exports = (base, cb) => { - if (!config.crypto_cmc || config.crypto_cmc.length == 0 || !config.cmcApiKey) { - cb({}); + if (!config.crypto_cmc || config.crypto_cmc.length == 0 || !config.cmcApiKey) { + cb({}); return; - } + } request( - 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest', { - qs: { - symbol: config.crypto_cmc.join(), - convert: base - }, - headers: { - 'X-CMC_PRO_API_KEY': config.cmcApiKey - }, - json: true, - }, (err, res, body) => { - if (err) { - notify(`Unable to process request to pro-api.coinmarketcap.com`, 'error'); - cb(false); - return; - } - try { - const info = body.data; - const data = {}; - config.crypto_cmc.forEach(t => { - const currency = _.findWhere(info, { - symbol: t + 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest', { + qs: { + symbol: config.crypto_cmc.join(), + convert: base + }, + headers: { + 'X-CMC_PRO_API_KEY': config.cmcApiKey + }, + json: true, + }, (err, res, body) => { + if (err) { + notify(`Unable to process request to pro-api.coinmarketcap.com`, 'error'); + cb(false); + return; + } + try { + const info = body.data; + const data = {}; + config.crypto_cmc.forEach(t => { + const currency = _.findWhere(info, { + symbol: t + }); + data[t + '/' + base] = +currency.quote[base].price.toFixed(8); }); - data[t + '/' + base] = +currency.quote[base].price.toFixed(8); - }); - cb(data); - log.info(`Coinmarketcap rates updated against ${base} successfully`) - } catch (e) { - notify(`Unable to process data from request to pro-api.coinmarketcap.com. Wrong Coinmarketcap API key? Error: ${e}`, 'error'); - cb(false); - } + cb(data); + log.info(`Coinmarketcap rates updated against ${base} successfully`) + } catch (e) { + notify(`Unable to process data from request to pro-api.coinmarketcap.com. Wrong Coinmarketcap API key? Error: ${e}`, 'error'); + cb(false); + } - }); -}; \ No newline at end of file + }); +}; diff --git a/helpers/getMoex.js b/helpers/getMoex.js index 78e30fc..e548009 100644 --- a/helpers/getMoex.js +++ b/helpers/getMoex.js @@ -1,41 +1,41 @@ -const request = require('request'); -const _ = require('underscore'); -const config = require('./configReader'); -const log = require('./log'); -const notify = require('./notify'); - -module.exports = (cb) => { - request('https://iss.moex.com/iss/engines/currency/markets/selt/securities.jsonp', {json: true}, (err, response, body) => { - try { - if (err) { - notify(`Unable to process request to iss.moex.com`, 'error'); - cb(false); - return; - } - const data = {}; - const info = body.securities.data; - Object.keys(config.fiat).forEach(m => { - const code = config.fiat[m]; - const c = _.findWhere(info, { - 2: code - }); - let price = (c[14] + c[15]) / 2; - if (m === 'JPY/RUB') - price /= 100; - data[m] = +price.toFixed(8); - if (m === 'USD/RUB') { - data['RUB/USD'] = +(1 / data['USD/RUB']).toFixed(8); - } else { - const market = 'USD/' + m.replace('/RUB', ''); - const price = data['USD/RUB'] / data[m]; - data[market] = +price.toFixed(8); - } - }); - cb(data); - log.info(`MOEX rates updated successfully`) - } catch (e) { - notify(`Unable to process request to iss.moex.com. Error: ${e}`, 'error'); - cb(false); - } - }); -}; +const request = require('request'); +const _ = require('underscore'); +const config = require('./configReader'); +const log = require('./log'); +const notify = require('./notify'); + +module.exports = (cb) => { + request('https://iss.moex.com/iss/engines/currency/markets/selt/securities.jsonp', {json: true}, (err, response, body) => { + try { + if (err) { + notify(`Unable to process request to iss.moex.com`, 'error'); + cb(false); + return; + } + const data = {}; + const info = body.securities.data; + Object.keys(config.fiat).forEach(m => { + const code = config.fiat[m]; + const c = _.findWhere(info, { + 2: code + }); + let price = (c[14] + c[15]) / 2; + if (m === 'JPY/RUB') + price /= 100; + data[m] = +price.toFixed(8); + if (m === 'USD/RUB') { + data['RUB/USD'] = +(1 / data['USD/RUB']).toFixed(8); + } else { + const market = 'USD/' + m.replace('/RUB', ''); + const price = data['USD/RUB'] / data[m]; + data[market] = +price.toFixed(8); + } + }); + cb(data); + log.info(`MOEX rates updated successfully`); + } catch (e) { + notify(`Unable to process request to iss.moex.com. Error: ${e}`, 'error'); + cb(false); + } + }); +}; diff --git a/modules/router.js b/modules/router.js index 11e54a3..c1c408f 100644 --- a/modules/router.js +++ b/modules/router.js @@ -1,66 +1,68 @@ -const db = require('../db/mongodb'); -const express = require('express'); -const app = express(); -var bodyParser = require('body-parser'); -const config = require('../helpers/configReader'); -const log = require('../helpers/log'); -const notify = require('../helpers/notify'); - -let tickers; - -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ - extended: true -})); - -app.get('/get', (req, res) => { - let coins = req.query.coin; - if (!coins) { - res.json(respSuccess(tickers)); - } else { - coins = coins.toUpperCase(); - const filterredTickers = {}; - let arrCoins = [coins]; - if (~coins.indexOf(',')) { - arrCoins = coins.split(','); - } - arrCoins.forEach(coin => { - const filteredMarkets = Object.keys(tickers).filter(c => ~c.indexOf(coin.trim())); - filteredMarkets.forEach(c => filterredTickers[c] = tickers[c]); - }); - res.json(respSuccess(filterredTickers)); - } -}); - -app.get('/getHistory', (req, res) => { - db.getHistory(req.query, (h, msg) => { - if (h){ - res.json(respSuccess(h)); - } else { - res.json(respError(msg)); - } - }); -}); - -module.exports = (tickers_) => { - tickers = tickers_; -}; - -app.listen(config.port, () => notify('ADAMANT-INFO server is listening on port ' + config.port, 'info')); - -function respSuccess (data) { - if (Object.entries(data).length === 0 && data.constructor === Object) // Empty object - return respError('No data available') - else return { - success: true, - date: new Date().getTime(), - result: data - }; -} -function respError (msg) { - return { - success: false, - date: new Date().getTime(), - msg - }; -} \ No newline at end of file +const db = require('../db/mongodb'); +const express = require('express'); +const app = express(); +var bodyParser = require('body-parser'); +const config = require('../helpers/configReader'); +const log = require('../helpers/log'); +const notify = require('../helpers/notify'); + +let tickers; + +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ + extended: true, +})); + +app.get('/get', (req, res) => { + let coins = req.query.coin; + if (!coins) { + res.json(respSuccess(tickers)); + } else { + coins = coins.toUpperCase(); + const filterredTickers = {}; + let arrCoins = [coins]; + if (~coins.indexOf(',')) { + arrCoins = coins.split(','); + } + arrCoins.forEach(coin => { + const filteredMarkets = Object.keys(tickers).filter(c => ~c.indexOf(coin.trim())); + filteredMarkets.forEach(c => filterredTickers[c] = tickers[c]); + }); + res.json(respSuccess(filterredTickers)); + } +}); + +app.get('/getHistory', (req, res) => { + db.getHistory(req.query, (h, msg) => { + if (h) { + res.json(respSuccess(h)); + } else { + res.json(respError(msg)); + } + }); +}); + +module.exports = (tickers_) => { + tickers = tickers_; +}; + +app.listen(config.port, () => notify('ADAMANT-INFO server is listening on port ' + config.port, 'info')); + +function respSuccess(data) { + if (Object.entries(data).length === 0 && data.constructor === Object) { // Empty object + return respError('No data available'); + } else { + return { + success: true, + date: new Date().getTime(), + result: data, + }; + } +} +function respError(msg) { + return { + success: false, + date: new Date().getTime(), + msg, + }; +} From dc07389269511b8337d41dad9048f707097a50c4 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 10 Jan 2022 21:48:46 +0300 Subject: [PATCH 08/36] More lint fixes --- app.js | 2 +- db/mongodb.js | 4 ++-- helpers/getCc.js | 4 ++-- helpers/getCg.js | 27 +++++++++++++++------------ helpers/getCmc.js | 12 ++++++------ helpers/getMoex.js | 9 ++++----- helpers/notify.js | 32 ++++++++++++++++---------------- modules/api.js | 2 +- modules/router.js | 8 ++++---- 9 files changed, 51 insertions(+), 49 deletions(-) diff --git a/app.js b/app.js index 0c58174..b123154 100644 --- a/app.js +++ b/app.js @@ -71,7 +71,7 @@ setInterval(refresh, config.refreshInterval * 60000); function converter(tickers) { config.baseCoins.forEach((b) => { const price = tickers['USD/' + b] || 1 / tickers[b + '/USD']; - if (!price) {return;} + if (!price) return; config.crypto_all.forEach((c) => { const priceAlt = 1 / tickers[c + '/USD']; tickers[c + '/' + b] = +(price / priceAlt).toFixed(8); diff --git a/db/mongodb.js b/db/mongodb.js index 6a0f968..8f96e7c 100644 --- a/db/mongodb.js +++ b/db/mongodb.js @@ -68,8 +68,8 @@ module.exports.getHistory = (params, cb) => { cb(false, err); } else { if (coin) { - docs.tickers = docs.forEach(d =>{ - Object.keys(d.tickers).forEach(pair =>{ + docs.tickers = docs.forEach((d) =>{ + Object.keys(d.tickers).forEach((pair) =>{ if (!~pair.indexOf(coin)) { delete d.tickers[pair]; } diff --git a/helpers/getCc.js b/helpers/getCc.js index a9cf791..b3c6dd7 100644 --- a/helpers/getCc.js +++ b/helpers/getCc.js @@ -6,7 +6,7 @@ const notify = require('./notify'); module.exports = (base, cb) => { - if (!config.crypto_cc || config.crypto_cc.length == 0 || !config.ccApiKey) { + if (!config.crypto_cc || config.crypto_cc.length === 0 || !config.ccApiKey) { cb({}); return; } @@ -28,7 +28,7 @@ module.exports = (base, cb) => { try { const info = body; const data = {}; - config.crypto_cc.forEach(t => { + config.crypto_cc.forEach((t) => { data[t + '/' + base] = +info[t][base].toFixed(8); }); diff --git a/helpers/getCg.js b/helpers/getCg.js index 395ed47..62897cf 100644 --- a/helpers/getCg.js +++ b/helpers/getCg.js @@ -8,7 +8,10 @@ function getCgCoinIds() { config.crypto_cg_full = []; - if ((!config.crypto_cg || config.crypto_cg.length === 0) && (!config.crypto_cg_coinids || config.crypto_cg_coinids.length === 0)) { + if ( + (!config.crypto_cg || config.crypto_cg.length === 0) && + (!config.crypto_cg_coinids || config.crypto_cg_coinids.length === 0) + ) { return; } @@ -22,28 +25,28 @@ function getCgCoinIds() { } try { const info = body; - config.crypto_cg.forEach(t => { + config.crypto_cg.forEach((t) => { const currency = _.findWhere(info, { symbol: t.toLowerCase(), }); cg_crypto = { symbol: t, cg_id: currency.id, - } + }, config.crypto_cg_full.push(cg_crypto); }); - config.crypto_cg_coinids.forEach(t => { + config.crypto_cg_coinids.forEach((t) => { const currency = _.findWhere(info, { id: t, }); cg_crypto = { symbol: currency.symbol.toUpperCase(), cg_id: t, - } - config.crypto_cg_full.push(cg_crypto) + }; + config.crypto_cg_full.push(cg_crypto); }); - config.crypto_all = config.crypto_all.concat(config.crypto_cg_full.map(e => e.symbol)); - log.info(`Coingecko coin ids fetched successfully`) + config.crypto_all = config.crypto_all.concat(config.crypto_cg_full.map((e) => e.symbol)); + log.info(`Coingecko coin ids fetched successfully`); } catch (e) { notify(`Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko. Error: ${e}`, 'error'); } @@ -56,7 +59,7 @@ getCgCoinIds(); module.exports = (base, cb) => { - if (!config.crypto_cg_full || config.crypto_cg_full.length == 0) { + if (!config.crypto_cg_full || config.crypto_cg_full.length === 0) { cb({}); return; } @@ -64,7 +67,7 @@ module.exports = (base, cb) => { request( 'https://api.coingecko.com/api/v3/simple/price', { qs: { - ids: config.crypto_cg_full.map(e => e.cg_id).join(","), // join string by field cg_id + ids: config.crypto_cg_full.map((e) => e.cg_id).join(','), // join string by field cg_id vs_currencies: base, }, json: true, @@ -77,7 +80,7 @@ module.exports = (base, cb) => { try { const info = body; const data = {}; - config.crypto_cg_full.forEach(t => { + config.crypto_cg_full.forEach((t) => { data[t['symbol'] + '/' + base] = +info[t['cg_id']][base.toLowerCase()].toFixed(8); }); @@ -89,4 +92,4 @@ module.exports = (base, cb) => { } }); -}; \ No newline at end of file +}; diff --git a/helpers/getCmc.js b/helpers/getCmc.js index 18b9ba5..1c8723f 100644 --- a/helpers/getCmc.js +++ b/helpers/getCmc.js @@ -6,7 +6,7 @@ const notify = require('./notify'); module.exports = (base, cb) => { - if (!config.crypto_cmc || config.crypto_cmc.length == 0 || !config.cmcApiKey) { + if (!config.crypto_cmc || config.crypto_cmc.length === 0 || !config.cmcApiKey) { cb({}); return; } @@ -15,10 +15,10 @@ module.exports = (base, cb) => { 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest', { qs: { symbol: config.crypto_cmc.join(), - convert: base + convert: base, }, headers: { - 'X-CMC_PRO_API_KEY': config.cmcApiKey + 'X-CMC_PRO_API_KEY': config.cmcApiKey, }, json: true, }, (err, res, body) => { @@ -30,15 +30,15 @@ module.exports = (base, cb) => { try { const info = body.data; const data = {}; - config.crypto_cmc.forEach(t => { + config.crypto_cmc.forEach((t) => { const currency = _.findWhere(info, { - symbol: t + symbol: t, }); data[t + '/' + base] = +currency.quote[base].price.toFixed(8); }); cb(data); - log.info(`Coinmarketcap rates updated against ${base} successfully`) + log.info(`Coinmarketcap rates updated against ${base} successfully`); } catch (e) { notify(`Unable to process data from request to pro-api.coinmarketcap.com. Wrong Coinmarketcap API key? Error: ${e}`, 'error'); cb(false); diff --git a/helpers/getMoex.js b/helpers/getMoex.js index e548009..b951953 100644 --- a/helpers/getMoex.js +++ b/helpers/getMoex.js @@ -5,7 +5,7 @@ const log = require('./log'); const notify = require('./notify'); module.exports = (cb) => { - request('https://iss.moex.com/iss/engines/currency/markets/selt/securities.jsonp', {json: true}, (err, response, body) => { + request('https://iss.moex.com/iss/engines/currency/markets/selt/securities.jsonp', { json: true }, (err, response, body) => { try { if (err) { notify(`Unable to process request to iss.moex.com`, 'error'); @@ -14,14 +14,13 @@ module.exports = (cb) => { } const data = {}; const info = body.securities.data; - Object.keys(config.fiat).forEach(m => { + Object.keys(config.fiat).forEach((m) => { const code = config.fiat[m]; const c = _.findWhere(info, { - 2: code + 2: code, }); let price = (c[14] + c[15]) / 2; - if (m === 'JPY/RUB') - price /= 100; + if (m === 'JPY/RUB') price /= 100; data[m] = +price.toFixed(8); if (m === 'USD/RUB') { data['RUB/USD'] = +(1 / data['USD/RUB']).toFixed(8); diff --git a/helpers/notify.js b/helpers/notify.js index 8ad47fa..c92604c 100644 --- a/helpers/notify.js +++ b/helpers/notify.js @@ -15,19 +15,19 @@ module.exports = (message, type) => { let color; switch (type) { - case ('error'): - color = '#FF0000'; - break; - case ('warn'): - color = '#FFFF00'; - break; - case ('info'): - color = '#00FF00'; - break; - case ('log'): - color = '#FFFFFF'; - break; - } + case ('error'): + color = '#FF0000'; + break; + case ('warn'): + color = '#FFFF00'; + break; + case ('info'): + color = '#00FF00'; + break; + case ('log'): + color = '#FFFFFF'; + break; + } const opts = { uri: config.slack, method: 'POST', @@ -37,9 +37,9 @@ module.exports = (message, type) => { 'fallback': message, 'color': color, 'text': message, - 'mrkdwn_in': ['text'] - }] - } + 'mrkdwn_in': ['text'], + }], + }, }; if (config.slack && config.slack.length > 35) { request(opts); diff --git a/modules/api.js b/modules/api.js index 128e9e5..a25d176 100644 --- a/modules/api.js +++ b/modules/api.js @@ -1,3 +1,3 @@ const log = require('../helpers/log'); const config = require('../helpers/configReader'); -module.exports = require('adamant-api')({passPhrase: config.passPhrase, node: config.node_ADM}, log); +module.exports = require('adamant-api')({ passPhrase: config.passPhrase, node: config.node_ADM }, log); diff --git a/modules/router.js b/modules/router.js index c1c408f..7b45328 100644 --- a/modules/router.js +++ b/modules/router.js @@ -1,7 +1,7 @@ const db = require('../db/mongodb'); const express = require('express'); const app = express(); -var bodyParser = require('body-parser'); +const bodyParser = require('body-parser'); const config = require('../helpers/configReader'); const log = require('../helpers/log'); const notify = require('../helpers/notify'); @@ -24,9 +24,9 @@ app.get('/get', (req, res) => { if (~coins.indexOf(',')) { arrCoins = coins.split(','); } - arrCoins.forEach(coin => { - const filteredMarkets = Object.keys(tickers).filter(c => ~c.indexOf(coin.trim())); - filteredMarkets.forEach(c => filterredTickers[c] = tickers[c]); + arrCoins.forEach((coin) => { + const filteredMarkets = Object.keys(tickers).filter((c) => ~c.indexOf(coin.trim())); + filteredMarkets.forEach((c) => filterredTickers[c] = tickers[c]); }); res.json(respSuccess(filterredTickers)); } From 516881dfb7f72ef8d9dcea4adde098b1153fd5f8 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 10 Jan 2022 22:12:56 +0300 Subject: [PATCH 09/36] Update logger --- README.md | 1 + config.json | 3 +- helpers/configReader.js | 14 ++++--- helpers/log.js | 85 +++++++++++++++++++++++------------------ 4 files changed, 60 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index e93c0a8..fc2669c 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ Parameters: - `adamant_notify` ADM address to receive alerts for InfoService administrator. Recommended. - `passPhrase` The secret phrase for account you want to send alerts from. Obligatory in case of you set `adamant_notify` - `node_ADM` List of nodes for API work, obligatorily in case of you set `adamant_notify` +- `log_level` The software will use verbosity according to `log_level`. It can be `none` < `error` < `warn` < `info` < `log`. ## Launching diff --git a/config.json b/config.json index 42717f7..0eaa3b3 100644 --- a/config.json +++ b/config.json @@ -30,5 +30,6 @@ "http://185.231.245.26:36666", "http://80.211.177.181:36666", "https://lake.adamant.im" - ] + ], + "log_level": "log" } diff --git a/helpers/configReader.js b/helpers/configReader.js index 822464f..2a03532 100644 --- a/helpers/configReader.js +++ b/helpers/configReader.js @@ -1,6 +1,5 @@ const jsonminify = require('jsonminify'); const fs = require('fs'); -const log = require('./log'); const isDev = process.argv.includes('dev'); let config = {}; @@ -10,11 +9,16 @@ try { } else { config = JSON.parse(jsonminify(fs.readFileSync('./config.json', 'utf-8'))); } + + config.notifyName = `${config.bot_name} (${config.address})`; + config.version = require('../package.json').version; + config.isDev = isDev; + config.crypto_all = config.crypto_cmc.concat(config.crypto_cc); // Also, Coingecko coins will be added in getCg module + console.info(`InfoService successfully read a config-file${isDev ? ' (dev)' : ''}.`); + } catch (e) { - log.error('Error reading config: ' + e); + console.error('Error reading config: ' + e); + process.exit(-1); } -config.isDev = isDev; -config.crypto_all = config.crypto_cmc.concat(config.crypto_cc); // Coingecko will be added in getCg module - module.exports = config; diff --git a/helpers/log.js b/helpers/log.js index 6739b00..cf98638 100644 --- a/helpers/log.js +++ b/helpers/log.js @@ -1,61 +1,72 @@ -let fs = require('fs'); +const config = require('./configReader'); + +const fs = require('fs'); if (!fs.existsSync('./logs')) { fs.mkdirSync('./logs'); } -let infoStr = fs.createWriteStream('./logs/' + date() + '.log', { - flags: 'a' +const infoStr = fs.createWriteStream('./logs/' + date() + '.log', { + flags: 'a', }); -infoStr.write(` -_________________${fullTime()}_________________ -`); +infoStr.write(`\n\n[The InfoService started] _________________${fullTime()}_________________\n`); module.exports = { error(str) { - infoStr.write(` - ` + 'InfoService error|' + time() + '|' + str); - console.log('\x1b[31m', 'error|' + time(), '\x1b[0m', str); - }, - info(str) { - console.log('\x1b[32m', 'info|' + time(), '\x1b[0m', str); - - infoStr.write(` - ` + 'InfoService info|' + time() + '|' + str); + if (['error', 'warn', 'info', 'log'].includes(config.log_level)) { + infoStr.write(`\n ` + 'error|' + fullTime() + '|' + str); + console.log('\x1b[31m', 'error|' + fullTime(), '\x1b[0m', str); + } }, warn(str) { - console.log('\x1b[33m', 'warn|' + time(), '\x1b[0m', str); - - infoStr.write(` - ` + 'InfoService warn|' + time() + '|' + str); + if (['warn', 'info', 'log'].includes(config.log_level)) { + console.log('\x1b[33m', 'warn|' + fullTime(), '\x1b[0m', str); + infoStr.write(`\n ` + 'warn|' + fullTime() + '|' + str); + } + }, + info(str) { + if (['info', 'log'].includes(config.log_level)) { + console.log('\x1b[32m', 'info|' + fullTime(), '\x1b[0m', str); + infoStr.write(`\n ` + 'info|' + fullTime() + '|' + str); + } }, log(str) { - console.log('\x1b[34m', 'log|' + time(), '\x1b[0m', str); - - infoStr.write(` - ` + 'InfoService log|[' + time() + '|' + str); - } + if (['log'].includes(config.log_level)) { + console.log('\x1b[34m', 'log|' + fullTime(), '\x1b[0m', str); + infoStr.write(`\n ` + 'log|[' + fullTime() + '|' + str); + } + }, }; function time() { - var options = { - hour: 'numeric', - minute: 'numeric', - second: 'numeric' - }; - - return new Date().toLocaleString('en', options); + return formatDate(Date.now()).hh_mm_ss; } function date() { - var options = { - day: 'numeric', - month: 'numeric', - year: 'numeric' - }; - return (new Date().toLocaleString('en', options)).replace(/\//g, '-'); + return formatDate(Date.now()).YYYY_MM_DD; } function fullTime() { return date() + ' ' + time(); } + +/** + * Formats unix timestamp to string + * @param {number} timestamp Timestamp to format + * @return {object} Contains different formatted strings + */ +function formatDate(timestamp) { + if (!timestamp) return false; + const formattedDate = {}; + const dateObject = new Date(timestamp); + formattedDate.year = dateObject.getFullYear(); + formattedDate.month = ('0' + (dateObject.getMonth() + 1)).slice(-2); + formattedDate.date = ('0' + dateObject.getDate()).slice(-2); + formattedDate.hours = ('0' + dateObject.getHours()).slice(-2); + formattedDate.minutes = ('0' + dateObject.getMinutes()).slice(-2); + formattedDate.seconds = ('0' + dateObject.getSeconds()).slice(-2); + formattedDate.YYYY_MM_DD = formattedDate.year + '-' + formattedDate.month + '-' + formattedDate.date; + formattedDate.YYYY_MM_DD_hh_mm = formattedDate.year + '-' + formattedDate.month + '-' + formattedDate.date + ' ' + formattedDate.hours + ':' + formattedDate.minutes; + formattedDate.hh_mm_ss = formattedDate.hours + ':' + formattedDate.minutes + ':' + formattedDate.seconds; + return formattedDate; +} From 7a2e50da4a5dbeba2c63c9ba1281e8ea5953d3b7 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 10 Jan 2022 22:24:05 +0300 Subject: [PATCH 10/36] Update notifier --- config.json | 15 +----- helpers/configReader.js | 2 +- helpers/notify.js | 104 ++++++++++++++++++++++++---------------- modules/api.js | 3 -- package.json | 2 +- 5 files changed, 66 insertions(+), 60 deletions(-) delete mode 100644 modules/api.js diff --git a/config.json b/config.json index 0eaa3b3..55802d8 100644 --- a/config.json +++ b/config.json @@ -17,19 +17,6 @@ "cgApiKey": "No need for Coingecko API key", "port": 36668, "refreshInterval": 10, - "slack": "https://hooks.slack.com/services/..", - "adamant_notify": "", - "passPhrase": "joy logic job estate kite", - "node_ADM": [ - "http://localhost:36666", - "https://endless.adamant.im", - "https://clown.adamant.im", - "https://bid.adamant.im", - "https://unusual.adamant.im", - "https://debate.adamant.im", - "http://185.231.245.26:36666", - "http://80.211.177.181:36666", - "https://lake.adamant.im" - ], + "slack": ["https://hooks.slack.com/services/.."], "log_level": "log" } diff --git a/helpers/configReader.js b/helpers/configReader.js index 2a03532..34d783c 100644 --- a/helpers/configReader.js +++ b/helpers/configReader.js @@ -4,13 +4,13 @@ const isDev = process.argv.includes('dev'); let config = {}; try { + if (isDev) { config = JSON.parse(jsonminify(fs.readFileSync('./config.test', 'utf-8'))); } else { config = JSON.parse(jsonminify(fs.readFileSync('./config.json', 'utf-8'))); } - config.notifyName = `${config.bot_name} (${config.address})`; config.version = require('../package.json').version; config.isDev = isDev; config.crypto_all = config.crypto_cmc.concat(config.crypto_cc); // Also, Coingecko coins will be added in getCg module diff --git a/helpers/notify.js b/helpers/notify.js index c92604c..660843a 100644 --- a/helpers/notify.js +++ b/helpers/notify.js @@ -1,53 +1,75 @@ -const request = require('request'); +const axios = require('axios'); const config = require('./configReader'); const log = require('./log'); -const api = require('../modules/api'); - -module.exports = (message, type) => { +const { + slack, +} = config; +module.exports = (message, type, silent_mode = false) => { try { + if (!silent_mode) { + log[type](removeMarkdown(message)); - log[type](message.replace(/\*/g, '').replace(/_/g, '')); + if (slack && slack.length) { + let color; + switch (type) { + case ('error'): + color = '#FF0000'; + break; + case ('warn'): + color = '#FFFF00'; + break; + case ('info'): + color = '#00FF00'; + break; + case ('log'): + color = '#FFFFFF'; + break; + } - if (!config.slack && !config.adamant_notify) { - return; - } + const params = { + 'attachments': [{ + 'fallback': message, + 'color': color, + 'text': makeBoldForSlack(message), + 'mrkdwn_in': ['text'], + }], + }; + + slack.forEach((slackApp) => { + if (typeof slackApp === 'string' && slackApp.length > 34) { + axios.post(slackApp, params) + .catch(function(error) { + log.log(`Request to Slack with message ${message} failed. ${error}.`); + }); + } + }); + } - let color; - switch (type) { - case ('error'): - color = '#FF0000'; - break; - case ('warn'): - color = '#FFFF00'; - break; - case ('info'): - color = '#00FF00'; - break; - case ('log'): - color = '#FFFFFF'; - break; - } - const opts = { - uri: config.slack, - method: 'POST', - json: true, - body: { - 'attachments': [{ - 'fallback': message, - 'color': color, - 'text': message, - 'mrkdwn_in': ['text'], - }], - }, - }; - if (config.slack && config.slack.length > 35) { - request(opts); - } - if (config.adamant_notify && config.adamant_notify.length > 5 && config.adamant_notify.startsWith('U') && config.passPhrase && config.passPhrase.length > 30) { - api.send(config.passPhrase, config.adamant_notify, `${type}| ${message.replace(/\*/g, '**')}`, 'message'); } + } catch (e) { log.error('Notifier error: ' + e); } + }; + +function removeMarkdown(text) { + return doubleAsterisksToSingle(text).replace(/([_*]\b|\b[_*])/g, ''); +} + +function doubleAsterisksToSingle(text) { + return text.replace(/(\*\*\b|\b\*\*)/g, '*'); +} + +function singleAsteriskToDouble(text) { + return text.replace(/(\*\b|\b\*)/g, '**'); +} + +function makeBoldForMarkdown(text) { + return singleAsteriskToDouble(doubleAsterisksToSingle(text)); +} + +function makeBoldForSlack(text) { + return doubleAsterisksToSingle(text); +} diff --git a/modules/api.js b/modules/api.js deleted file mode 100644 index a25d176..0000000 --- a/modules/api.js +++ /dev/null @@ -1,3 +0,0 @@ -const log = require('../helpers/log'); -const config = require('../helpers/configReader'); -module.exports = require('adamant-api')({ passPhrase: config.passPhrase, node: config.node_ADM }, log); diff --git a/package.json b/package.json index ce9eef7..02efa47 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "author": "ADAMANT Dev Team, Aleksei Lebedev (https://adamant.im)", "license": "GPL-3.0", "dependencies": { - "adamant-api": "^0.1.22", + "axios": "^0.24.0", "body-parser": "^1.18.3", "jsonminify": "^0.4.1", "express": "^4.16.4", From e4003e9266acf26df30e31a9f9bfbcdd8f1c3ec9 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 08:34:03 +0300 Subject: [PATCH 11/36] Update getCc to axios --- helpers/configReader.js | 1 + helpers/getCc.js | 49 ++++++++++++++++++++--------------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/helpers/configReader.js b/helpers/configReader.js index 34d783c..a213f47 100644 --- a/helpers/configReader.js +++ b/helpers/configReader.js @@ -11,6 +11,7 @@ try { config = JSON.parse(jsonminify(fs.readFileSync('./config.json', 'utf-8'))); } + config.isCc = config.crypto_cc && config.crypto_cc.length !== 0 && config.ccApiKey; config.version = require('../package.json').version; config.isDev = isDev; config.crypto_all = config.crypto_cmc.concat(config.crypto_cc); // Also, Coingecko coins will be added in getCg module diff --git a/helpers/getCc.js b/helpers/getCc.js index b3c6dd7..398da59 100644 --- a/helpers/getCc.js +++ b/helpers/getCc.js @@ -1,43 +1,42 @@ -const request = require('request'); -const _ = require('underscore'); +const axios = require('axios'); const config = require('./configReader'); const log = require('./log'); const notify = require('./notify'); +const url = 'https://min-api.cryptocompare.com/data/pricemulti'; + module.exports = (base, cb) => { - if (!config.crypto_cc || config.crypto_cc.length === 0 || !config.ccApiKey) { + if (!config.isCc) { cb({}); return; } - request( - 'https://min-api.cryptocompare.com/data/pricemulti', { - qs: { - fsyms: config.crypto_cc.join(), - tsyms: base, - api_key: config.ccApiKey, - }, - json: true, - }, (err, res, body) => { - if (err) { - notify(`Unable to process request to min-api.cryptocompare.com`, 'error'); - cb(false); - return; - } + const params = { + fsyms: config.crypto_cc.join(), + tsyms: base, + api_key: config.ccApiKey, + }; + + axios.get(url, { params }) + .then(function(response) { try { - const info = body; - const data = {}; + const data = response.data; + const rates = {}; config.crypto_cc.forEach((t) => { - data[t + '/' + base] = +info[t][base].toFixed(8); + rates[t + '/' + base] = +data[t][base].toFixed(8); }); - - cb(data); - log.info(`CryptoCompare rates updated against ${base} successfully`); + cb(rates); + log.log(`CryptoCompare rates updated against ${base} successfully`); } catch (e) { - notify(`Unable to process data from request to min-api.cryptocompare.com. Wrong CryptoCompare API key? Error: ${e}`, 'error'); + notify(`Unable to process data ${JSON.stringify(response.data)} from request to ${url} ${JSON.stringify(params)}. Wrong CryptoCompare API key? Error: ${e}`, 'error'); cb(false); } - + }) + .catch(function(error) { + console.log('rates1'); + notify(`Request to ${url} ${JSON.stringify(params)} failed with ${error.response?.status} status code, ${error.toString()}${error.response?.data ? '. Message: ' + error.response.data.toString().trim() : ''}.`, 'error'); + cb(false); + return; }); }; From 7aab3fea995dadb95e7e1ecb0074e99142bb4c95 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 08:44:29 +0300 Subject: [PATCH 12/36] Update getMoex to axios --- helpers/getCc.js | 2 -- helpers/getMoex.js | 67 ++++++++++++++++++++++++---------------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/helpers/getCc.js b/helpers/getCc.js index 398da59..b71d229 100644 --- a/helpers/getCc.js +++ b/helpers/getCc.js @@ -34,9 +34,7 @@ module.exports = (base, cb) => { } }) .catch(function(error) { - console.log('rates1'); notify(`Request to ${url} ${JSON.stringify(params)} failed with ${error.response?.status} status code, ${error.toString()}${error.response?.data ? '. Message: ' + error.response.data.toString().trim() : ''}.`, 'error'); cb(false); - return; }); }; diff --git a/helpers/getMoex.js b/helpers/getMoex.js index b951953..d503ff2 100644 --- a/helpers/getMoex.js +++ b/helpers/getMoex.js @@ -1,40 +1,43 @@ -const request = require('request'); -const _ = require('underscore'); +const axios = require('axios'); const config = require('./configReader'); const log = require('./log'); const notify = require('./notify'); +const _ = require('underscore'); + +const url = 'https://iss.moex.com/iss/engines/currency/markets/selt/securities.jsonp'; module.exports = (cb) => { - request('https://iss.moex.com/iss/engines/currency/markets/selt/securities.jsonp', { json: true }, (err, response, body) => { - try { - if (err) { - notify(`Unable to process request to iss.moex.com`, 'error'); - cb(false); - return; - } - const data = {}; - const info = body.securities.data; - Object.keys(config.fiat).forEach((m) => { - const code = config.fiat[m]; - const c = _.findWhere(info, { - 2: code, - }); - let price = (c[14] + c[15]) / 2; - if (m === 'JPY/RUB') price /= 100; - data[m] = +price.toFixed(8); - if (m === 'USD/RUB') { - data['RUB/USD'] = +(1 / data['USD/RUB']).toFixed(8); - } else { - const market = 'USD/' + m.replace('/RUB', ''); - const price = data['USD/RUB'] / data[m]; - data[market] = +price.toFixed(8); + + axios.get(url) + .then(function(response) { + try { + const rates = {}; + const data = response.data.securities.data; + Object.keys(config.fiat).forEach((m) => { + const code = config.fiat[m]; + const c = _.findWhere(data, { + 2: code, + }); + let price = (c[14] + c[15]) / 2; + if (m === 'JPY/RUB') price /= 100; + rates[m] = +price.toFixed(8); + if (m === 'USD/RUB') { + rates['RUB/USD'] = +(1 / rates['USD/RUB']).toFixed(8); + } else { + const market = 'USD/' + m.replace('/RUB', ''); + const price = rates['USD/RUB'] / rates[m]; + rates[market] = +price.toFixed(8); + } + }); + cb(rates); + log.log(`MOEX rates updated successfully`); + } catch (e) { + notify(`Unable to process data ${JSON.stringify(response.data)} from request to ${url}. Error: ${e}`, 'error'); + cb(false); } + }) + .catch(function(error) { + notify(`Request to ${url} failed with ${error.response?.status} status code, ${error.toString()}${error.response?.data ? '. Message: ' + error.response.data.toString().trim() : ''}.`, 'error'); + cb(false); }); - cb(data); - log.info(`MOEX rates updated successfully`); - } catch (e) { - notify(`Unable to process request to iss.moex.com. Error: ${e}`, 'error'); - cb(false); - } - }); }; From 7a3e548cad45ac1a725dc8bfd330261005db981c Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 09:04:41 +0300 Subject: [PATCH 13/36] Update getCmc to axios --- helpers/configReader.js | 1 + helpers/getCc.js | 2 +- helpers/getCmc.js | 56 ++++++++++++++++++++--------------------- helpers/getMoex.js | 2 +- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/helpers/configReader.js b/helpers/configReader.js index a213f47..7a312b6 100644 --- a/helpers/configReader.js +++ b/helpers/configReader.js @@ -12,6 +12,7 @@ try { } config.isCc = config.crypto_cc && config.crypto_cc.length !== 0 && config.ccApiKey; + config.isCmc = config.crypto_cmc && config.crypto_cmc.length !== 0 && config.cmcApiKey; config.version = require('../package.json').version; config.isDev = isDev; config.crypto_all = config.crypto_cmc.concat(config.crypto_cc); // Also, Coingecko coins will be added in getCg module diff --git a/helpers/getCc.js b/helpers/getCc.js index b71d229..934275a 100644 --- a/helpers/getCc.js +++ b/helpers/getCc.js @@ -34,7 +34,7 @@ module.exports = (base, cb) => { } }) .catch(function(error) { - notify(`Request to ${url} ${JSON.stringify(params)} failed with ${error.response?.status} status code, ${error.toString()}${error.response?.data ? '. Message: ' + error.response.data.toString().trim() : ''}.`, 'error'); + notify(`Request to ${url} ${JSON.stringify(params)} failed with ${error.response?.status} status code, ${error.toString()}${error.response?.data ? '. Message: ' + JSON.stringify(error.response.data) : ''}.`, 'error'); cb(false); }); }; diff --git a/helpers/getCmc.js b/helpers/getCmc.js index 1c8723f..dc73e51 100644 --- a/helpers/getCmc.js +++ b/helpers/getCmc.js @@ -1,48 +1,48 @@ -const request = require('request'); -const _ = require('underscore'); +const axios = require('axios'); const config = require('./configReader'); const log = require('./log'); const notify = require('./notify'); +const _ = require('underscore'); + +const url_base = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest'; module.exports = (base, cb) => { - if (!config.crypto_cmc || config.crypto_cmc.length === 0 || !config.cmcApiKey) { + if (!config.isCmc) { cb({}); return; } - request( - 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest', { - qs: { - symbol: config.crypto_cmc.join(), - convert: base, - }, - headers: { - 'X-CMC_PRO_API_KEY': config.cmcApiKey, - }, - json: true, - }, (err, res, body) => { - if (err) { - notify(`Unable to process request to pro-api.coinmarketcap.com`, 'error'); - cb(false); - return; - } + const url = url_base + '?' + 'symbol=' + config.crypto_cmc.join() + '&convert=' + base; + const httpOptions = { + url, + method: 'get', + timeout: 10000, + headers: { + 'X-CMC_PRO_API_KEY': config.cmcApiKey, + }, + }; + + axios(httpOptions) + .then(function(response) { try { - const info = body.data; - const data = {}; + const data = response.data.data; + const rates = {}; config.crypto_cmc.forEach((t) => { - const currency = _.findWhere(info, { + const currency = _.findWhere(data, { symbol: t, }); - data[t + '/' + base] = +currency.quote[base].price.toFixed(8); + rates[t + '/' + base] = +currency.quote[base].price.toFixed(8); }); - - cb(data); - log.info(`Coinmarketcap rates updated against ${base} successfully`); + cb(rates); + log.log(`Coinmarketcap rates updated against ${base} successfully`); } catch (e) { - notify(`Unable to process data from request to pro-api.coinmarketcap.com. Wrong Coinmarketcap API key? Error: ${e}`, 'error'); + notify(`Unable to process data ${JSON.stringify(response.data)} from request to ${url}. Wrong Coinmarketcap API key? Error: ${e}`, 'error'); cb(false); } - + }) + .catch(function(error) { + notify(`Request to ${url} failed with ${error.response?.status} status code, ${error.toString()}${error.response?.data ? '. Message: ' + JSON.stringify(error.response.data) : ''}.`, 'error'); + cb(false); }); }; diff --git a/helpers/getMoex.js b/helpers/getMoex.js index d503ff2..8ff57c1 100644 --- a/helpers/getMoex.js +++ b/helpers/getMoex.js @@ -37,7 +37,7 @@ module.exports = (cb) => { } }) .catch(function(error) { - notify(`Request to ${url} failed with ${error.response?.status} status code, ${error.toString()}${error.response?.data ? '. Message: ' + error.response.data.toString().trim() : ''}.`, 'error'); + notify(`Request to ${url} failed with ${error.response?.status} status code, ${error.toString()}${error.response?.data ? '. Message: ' + JSON.stringify(error.response.data) : ''}.`, 'error'); cb(false); }); }; From 05da6f7fa33dc9fa23bb1104e3763e953b5a6e63 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 09:45:22 +0300 Subject: [PATCH 14/36] Update getCgCoinIds() to use axios --- helpers/configReader.js | 2 ++ helpers/getCg.js | 35 +++++++++++++---------------------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/helpers/configReader.js b/helpers/configReader.js index 7a312b6..47614b6 100644 --- a/helpers/configReader.js +++ b/helpers/configReader.js @@ -12,6 +12,8 @@ try { } config.isCc = config.crypto_cc && config.crypto_cc.length !== 0 && config.ccApiKey; + config.isCg = (config.crypto_cg && config.crypto_cg.length !== 0) || + (config.crypto_cg_coinids && config.crypto_cg_coinids.length !== 0); config.isCmc = config.crypto_cmc && config.crypto_cmc.length !== 0 && config.cmcApiKey; config.version = require('../package.json').version; config.isDev = isDev; diff --git a/helpers/getCg.js b/helpers/getCg.js index 62897cf..6f5cb39 100644 --- a/helpers/getCg.js +++ b/helpers/getCg.js @@ -1,4 +1,5 @@ const request = require('request'); +const axios = require('axios'); const _ = require('underscore'); const config = require('./configReader'); const log = require('./log'); @@ -7,26 +8,15 @@ const notify = require('./notify'); function getCgCoinIds() { config.crypto_cg_full = []; + if (!config.isCg) return; - if ( - (!config.crypto_cg || config.crypto_cg.length === 0) && - (!config.crypto_cg_coinids || config.crypto_cg_coinids.length === 0) - ) { - return; - } - - request( - 'https://api.coingecko.com/api/v3/coins/list', { - json: true, - }, (err, res, body) => { - if (err) { - notify(`Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko.`, 'error'); - return; - } + const url = 'https://api.coingecko.com/api/v3/coins/list'; + axios.get(url) + .then(function(response) { try { - const info = body; + const data = response.data; config.crypto_cg.forEach((t) => { - const currency = _.findWhere(info, { + const currency = _.findWhere(data, { symbol: t.toLowerCase(), }); cg_crypto = { @@ -36,7 +26,7 @@ function getCgCoinIds() { config.crypto_cg_full.push(cg_crypto); }); config.crypto_cg_coinids.forEach((t) => { - const currency = _.findWhere(info, { + const currency = _.findWhere(data, { id: t, }); cg_crypto = { @@ -46,13 +36,14 @@ function getCgCoinIds() { config.crypto_cg_full.push(cg_crypto); }); config.crypto_all = config.crypto_all.concat(config.crypto_cg_full.map((e) => e.symbol)); - log.info(`Coingecko coin ids fetched successfully`); + log.log(`Coingecko coin ids fetched successfully`); } catch (e) { - notify(`Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko. Error: ${e}`, 'error'); + notify(`Unable to process data ${JSON.stringify(response.data)} from request to ${url}. Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko. Error: ${e}`, 'error'); } - + }) + .catch(function(error) { + notify(`Request to ${url} failed with ${error.response?.status} status code, ${error.toString()}. Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko.`, 'error'); }); - } getCgCoinIds(); From 33db99e81c3dc1c74dec4bac76decc113d459768 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 09:53:29 +0300 Subject: [PATCH 15/36] Update getCg to use axios --- helpers/getCg.js | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/helpers/getCg.js b/helpers/getCg.js index 6f5cb39..1f2a1f7 100644 --- a/helpers/getCg.js +++ b/helpers/getCg.js @@ -36,6 +36,7 @@ function getCgCoinIds() { config.crypto_cg_full.push(cg_crypto); }); config.crypto_all = config.crypto_all.concat(config.crypto_cg_full.map((e) => e.symbol)); + config.isCgFull = true; log.log(`Coingecko coin ids fetched successfully`); } catch (e) { notify(`Unable to process data ${JSON.stringify(response.data)} from request to ${url}. Unable to get Coingecko coin ids. Try to restart InfoService or there will be no rates from Coingecko. Error: ${e}`, 'error'); @@ -50,37 +51,36 @@ getCgCoinIds(); module.exports = (base, cb) => { - if (!config.crypto_cg_full || config.crypto_cg_full.length === 0) { + if (!config.isCgFull) { cb({}); return; } - request( - 'https://api.coingecko.com/api/v3/simple/price', { - qs: { - ids: config.crypto_cg_full.map((e) => e.cg_id).join(','), // join string by field cg_id - vs_currencies: base, - }, - json: true, - }, (err, res, body) => { - if (err) { - notify(`Unable to process request to api.coingecko.com`, 'error'); - cb(false); - return; - } + const params = { + ids: config.crypto_cg_full.map((e) => e.cg_id).join(','), // join string by field cg_id + vs_currencies: base, + }; + + const url = 'https://api.coingecko.com/api/v3/simple/price'; + + axios.get(url, { params }) + .then(function(response) { try { - const info = body; - const data = {}; + const data = response.data; + const rates = {}; config.crypto_cg_full.forEach((t) => { - data[t['symbol'] + '/' + base] = +info[t['cg_id']][base.toLowerCase()].toFixed(8); + rates[t['symbol'] + '/' + base] = +data[t['cg_id']][base.toLowerCase()].toFixed(8); }); - - cb(data); - log.info(`Coingecko rates updated against ${base} successfully`); + cb(rates); + log.log(`Coingecko rates updated against ${base} successfully`); } catch (e) { - notify(`Unable to process data from request to api.coingecko.com. Error: ${e}`, 'error'); + notify(`Unable to process data ${JSON.stringify(response.data)} from request to ${url} ${JSON.stringify(params)}. Error: ${e}`, 'error'); cb(false); } - + }) + .catch(function(error) { + notify(`Request to ${url} ${JSON.stringify(params)} failed with ${error.response?.status} status code, ${error.toString()}${error.response?.data ? '. Message: ' + JSON.stringify(error.response.data) : ''}.`, 'error'); + cb(false); }); + }; From d5e116a27c4da30159a4845d92ef61fd49ab4a34 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 10:02:16 +0300 Subject: [PATCH 16/36] Refactor db module --- db/mongodb.js | 33 ++++++++++----------------------- helpers/getCg.js | 1 - 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/db/mongodb.js b/db/mongodb.js index 8f96e7c..d79f663 100644 --- a/db/mongodb.js +++ b/db/mongodb.js @@ -1,33 +1,20 @@ -const log = require('../helpers/log'); const MongoClient = require('mongodb').MongoClient; - -const mongoClient = new MongoClient('mongodb://localhost:27017/', { - useNewUrlParser: true, -}); +const mongoClient = new MongoClient('mongodb://localhost:27017/', { useNewUrlParser: true, useUnifiedTopology: true, serverSelectionTimeoutMS: 3000 }); +const log = require('../helpers/log'); let TickersDB; -mongoClient.connect((err, client) => { - if (err) { - throw (err); +mongoClient.connect((error, client) => { + + if (error) { + log.error(`Unable to connect to MongoBD, ` + error); + process.exit(-1); } const db = client.db('tickersdb'); TickersDB = db.collection('tickers'); -}); - -// module.exports.save = (tickers, cb) => { -// TickersDB.insertOne({ -// date: new Date().getTime(), -// tickers -// }, (err, result) => { -// if (err){ -// cb(false); -// } else { -// cb(result); -// } -// }); -// }; + log.log(`InfoService successfully connected to 'tradebotdb' MongoDB.`); +}); module.exports.save = (tickers) => { TickersDB.insertOne({ @@ -81,6 +68,6 @@ module.exports.getHistory = (params, cb) => { }); } catch (e) { cb(false, e); - log.error('Error at getHistory: ', params, e); + log.error('Error at getHistory(): ', params, e); } }; diff --git a/helpers/getCg.js b/helpers/getCg.js index 1f2a1f7..ea34722 100644 --- a/helpers/getCg.js +++ b/helpers/getCg.js @@ -1,4 +1,3 @@ -const request = require('request'); const axios = require('axios'); const _ = require('underscore'); const config = require('./configReader'); From 429fe95172d97c8ea60af592d538ffbceceb5f1f Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 10:06:44 +0300 Subject: [PATCH 17/36] Update router --- modules/router.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/router.js b/modules/router.js index 7b45328..6bd7266 100644 --- a/modules/router.js +++ b/modules/router.js @@ -46,7 +46,7 @@ module.exports = (tickers_) => { tickers = tickers_; }; -app.listen(config.port, () => notify('ADAMANT-INFO server is listening on port ' + config.port, 'info')); +app.listen(config.port, () => notify('InfoService is listening on port ' + config.port, 'info')); function respSuccess(data) { if (Object.entries(data).length === 0 && data.constructor === Object) { // Empty object From 127d918d4a57bd9401fd052d28a73609a236751f Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 12:29:42 +0300 Subject: [PATCH 18/36] Update logging --- app.js | 20 ++++++++++---------- helpers/getCc.js | 2 +- helpers/getCg.js | 2 +- helpers/getCmc.js | 2 +- helpers/getMoex.js | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app.js b/app.js index b123154..3872e68 100644 --- a/app.js +++ b/app.js @@ -3,25 +3,25 @@ const Moex = require('./helpers/getMoex'); const Cmc = require('./helpers/getCmc'); const Cc = require('./helpers/getCc'); const Cg = require('./helpers/getCg'); -const _ = require('underscore'); const router = require('./modules/router'); const config = require('./helpers/configReader'); const log = require('./helpers/log'); const db = require('./db/mongodb'); const notify = require('./helpers/notify'); -let fetched; +let fetchedAll; router(tickers); function refresh() { - log.info('------------ Rates update started -------------'); - fetched = true; + log.log('Updating rates…'); + fetchedAll = true; + Cmc('USD', (data) => { if (data) { Object.assign(tickers, data); } else { - fetched = false; + fetchedAll = false; notify(`Error: Unable to get data from Coinmarketcap. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); } @@ -29,7 +29,7 @@ function refresh() { if (data) { Object.assign(tickers, data); } else { - fetched = false; + fetchedAll = false; notify(`Error: Unable to get data from MOEX. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); } @@ -37,7 +37,7 @@ function refresh() { if (data) { Object.assign(tickers, data); } else { - fetched = false; + fetchedAll = false; notify(`Error: Unable to get data from CryptoCompare. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); } @@ -45,15 +45,15 @@ function refresh() { if (data) { Object.assign(tickers, data); } else { - fetched = false; + fetchedAll = false; notify(`Error: Unable to get data from Coingecko. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); } converter(tickers); - if (fetched) { + if (fetchedAll) { try { db.save(tickers); - log.info('New rates from all sources saved successfully'); + log.info('Rates from all sources saved successfully'); } catch (e) { notify(`Error: Unable to save new rates in history database: ${e}`, 'error'); } diff --git a/helpers/getCc.js b/helpers/getCc.js index 934275a..5422750 100644 --- a/helpers/getCc.js +++ b/helpers/getCc.js @@ -26,8 +26,8 @@ module.exports = (base, cb) => { config.crypto_cc.forEach((t) => { rates[t + '/' + base] = +data[t][base].toFixed(8); }); - cb(rates); log.log(`CryptoCompare rates updated against ${base} successfully`); + cb(rates); } catch (e) { notify(`Unable to process data ${JSON.stringify(response.data)} from request to ${url} ${JSON.stringify(params)}. Wrong CryptoCompare API key? Error: ${e}`, 'error'); cb(false); diff --git a/helpers/getCg.js b/helpers/getCg.js index ea34722..d3cec57 100644 --- a/helpers/getCg.js +++ b/helpers/getCg.js @@ -70,8 +70,8 @@ module.exports = (base, cb) => { config.crypto_cg_full.forEach((t) => { rates[t['symbol'] + '/' + base] = +data[t['cg_id']][base.toLowerCase()].toFixed(8); }); - cb(rates); log.log(`Coingecko rates updated against ${base} successfully`); + cb(rates); } catch (e) { notify(`Unable to process data ${JSON.stringify(response.data)} from request to ${url} ${JSON.stringify(params)}. Error: ${e}`, 'error'); cb(false); diff --git a/helpers/getCmc.js b/helpers/getCmc.js index dc73e51..3f1df06 100644 --- a/helpers/getCmc.js +++ b/helpers/getCmc.js @@ -34,8 +34,8 @@ module.exports = (base, cb) => { }); rates[t + '/' + base] = +currency.quote[base].price.toFixed(8); }); - cb(rates); log.log(`Coinmarketcap rates updated against ${base} successfully`); + cb(rates); } catch (e) { notify(`Unable to process data ${JSON.stringify(response.data)} from request to ${url}. Wrong Coinmarketcap API key? Error: ${e}`, 'error'); cb(false); diff --git a/helpers/getMoex.js b/helpers/getMoex.js index 8ff57c1..b9e5aee 100644 --- a/helpers/getMoex.js +++ b/helpers/getMoex.js @@ -29,8 +29,8 @@ module.exports = (cb) => { rates[market] = +price.toFixed(8); } }); - cb(rates); log.log(`MOEX rates updated successfully`); + cb(rates); } catch (e) { notify(`Unable to process data ${JSON.stringify(response.data)} from request to ${url}. Error: ${e}`, 'error'); cb(false); From 11c992afaeb5e9b401c9f092fad82fb1ee39c0de Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 16:12:15 +0300 Subject: [PATCH 19/36] Reliable: uses different sources for one coin, and notifies about significant deviation --- .gitignore | 1 + README.md | 9 ++++--- app.js | 68 ++++++++++++++++++++++++++++++++++++++++++++---- db/mongodb.js | 2 +- helpers/utils.js | 34 ++++++++++++++++++++++++ 5 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 helpers/utils.js diff --git a/.gitignore b/.gitignore index fd1de43..d25410b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ node_modules/ logs/ .vscode/ config.test +config.test2 package-lock.json tests.js diff --git a/README.md b/README.md index fc2669c..ab5452d 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,15 @@ Features: - Collects rates from Coinmarketcap for crypto tickers - Collects rates from CryptoCompare for crypto tickers - Collects rates from Coingecko for crypto tickers +- Reliable: uses different sources for one coin, and notifies about significant deviation - Minimum API calls. Free API keys fit. -- Notifications in case of errors to ADAMANT and Slack +- Notifications in case of errors to Slack - Stores history on server, no need to make additional request -- Easy setup, settings in config file +- Easy setup, settings are in a config file - Provides [RESTful API](https://github.com/Adamant-im/adamant-currencyinfo-services/wiki/InfoServices-API-documentation) -- Fast and low hardware requirements +- It is fast; low hardware requirements - Open source -- Free use for any purposes +- Free to use for any purposes # Installation diff --git a/app.js b/app.js index 3872e68..ca18229 100644 --- a/app.js +++ b/app.js @@ -1,4 +1,3 @@ -const tickers = {}; const Moex = require('./helpers/getMoex'); const Cmc = require('./helpers/getCmc'); const Cc = require('./helpers/getCc'); @@ -6,10 +5,14 @@ const Cg = require('./helpers/getCg'); const router = require('./modules/router'); const config = require('./helpers/configReader'); const log = require('./helpers/log'); +const utils = require('./helpers/utils'); const db = require('./db/mongodb'); const notify = require('./helpers/notify'); let fetchedAll; +let tickers = {}; +let tickersInfo; +const RATE_DIFFERENCE_PERCENT_THRESHOLD = 20; router(tickers); function refresh() { @@ -19,7 +22,13 @@ function refresh() { Cmc('USD', (data) => { if (data) { - Object.assign(tickers, data); + tickersInfo = mergeData(tickers, data, 'Null', 'Cmc'); + if (tickersInfo.isAlert) { + notify(`Error: rates from different sources significantly differs: ${tickersInfo.alertString}. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); + fetchedAll = false; + } else { + tickers = tickersInfo.merged; + } } else { fetchedAll = false; notify(`Error: Unable to get data from Coinmarketcap. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); @@ -27,7 +36,13 @@ function refresh() { Moex((data) => { if (data) { - Object.assign(tickers, data); + tickersInfo = mergeData(tickers, data, 'Cmc', 'Moex'); + if (tickersInfo.isAlert) { + notify(`Error: rates from different sources significantly differs: ${tickersInfo.alertString}. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); + fetchedAll = false; + } else { + tickers = tickersInfo.merged; + } } else { fetchedAll = false; notify(`Error: Unable to get data from MOEX. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); @@ -35,7 +50,13 @@ function refresh() { Cc('USD', (data) => { if (data) { - Object.assign(tickers, data); + tickersInfo = mergeData(tickers, data, 'Cmc+Moex', 'Cc'); + if (tickersInfo.isAlert) { + notify(`Error: rates from different sources significantly differs: ${tickersInfo.alertString}. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); + fetchedAll = false; + } else { + tickers = tickersInfo.merged; + } } else { fetchedAll = false; notify(`Error: Unable to get data from CryptoCompare. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); @@ -43,7 +64,13 @@ function refresh() { Cg('USD', (data) => { if (data) { - Object.assign(tickers, data); + tickersInfo = mergeData(tickers, data, 'Cmc+Moex+Cc', 'Cg'); + if (tickersInfo.isAlert) { + notify(`Error: rates from different sources significantly differs: ${tickersInfo.alertString}. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); + fetchedAll = false; + } else { + tickers = tickersInfo.merged; + } } else { fetchedAll = false; notify(`Error: Unable to get data from Coingecko. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); @@ -68,6 +95,37 @@ function refresh() { setTimeout(refresh, 5000); setInterval(refresh, config.refreshInterval * 60000); +/** + * Merges two objects, containing rates. If both have same ticker, validate its value. + * @param {Object} tickers1 Object 1 with rates + * @param {Object} tickers2 Object 2 with rates + * @param {String} source1 Object 1 source, e. g., Cmc + * @param {String} source2 Object 2 source + * @return {Object} Merged object with rates, and alertString + */ +function mergeData(tickers1, tickers2, source1, source2) { + const merged = Object.assign({}, tickers1, tickers2); + const alertTickers = []; + Object.keys(merged).forEach((m) => { + if (utils.isPositiveOrZeroNumber(tickers1[m]) && utils.isPositiveOrZeroNumber(tickers2[m])) { + const diff = utils.numbersDifferencePercent(tickers1[m], tickers2[m]); + if (diff > RATE_DIFFERENCE_PERCENT_THRESHOLD) { + alertTickers.push(`**${m}** ${diff.toFixed(0)}%: ${+tickers1[m].toFixed(8)} (${source1}) — ${+tickers2[m].toFixed(8)} (${source2})`); + } + } + }); + return { + merged, + isAlert: alertTickers.length > 0, + alertString: alertTickers.join(', '), + }; +} + +/** + * Calculates rates for each base coin using USD rate + * Modifies tickers object + * @param {Object} tickers Rates object + */ function converter(tickers) { config.baseCoins.forEach((b) => { const price = tickers['USD/' + b] || 1 / tickers[b + '/USD']; diff --git a/db/mongodb.js b/db/mongodb.js index d79f663..e962d87 100644 --- a/db/mongodb.js +++ b/db/mongodb.js @@ -12,7 +12,7 @@ mongoClient.connect((error, client) => { } const db = client.db('tickersdb'); TickersDB = db.collection('tickers'); - log.log(`InfoService successfully connected to 'tradebotdb' MongoDB.`); + log.log(`InfoService successfully connected to 'tickersdb' MongoDB.`); }); diff --git a/helpers/utils.js b/helpers/utils.js new file mode 100644 index 0000000..7edbf84 --- /dev/null +++ b/helpers/utils.js @@ -0,0 +1,34 @@ +module.exports = { + + /** + * Checks if number is finite + * @param {number} value Number to validate + * @return {boolean} + */ + isNumber(value) { + if (typeof (value) !== 'number' || isNaN(value) || !Number.isFinite(value)) { + return false; + } else { + return true; + } + }, + + /** + * Checks if number is finite and not less, than 0 + * @param {number} value Number to validate + * @return {boolean} + */ + isPositiveOrZeroNumber(value) { + if (!this.isNumber(value) || value < 0) { + return false; + } else { + return true; + } + }, + + numbersDifferencePercent(a, b) { + if (!this.isNumber(a) || !this.isNumber(b)) return undefined; + return 100 * Math.abs( ( a - b ) / ( (a + b)/2 ) ); + }, + +}; From f27f0ba4d3a9a76a8fc61015c912bb4778bfd478 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 16:25:07 +0300 Subject: [PATCH 20/36] Update config --- config.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/config.json b/config.json index 55802d8..244dc1e 100644 --- a/config.json +++ b/config.json @@ -1,9 +1,11 @@ { - "crypto_cmc": ["BTC", "ETH", "DASH", "LSK", "DOGE", "BZ", "BCH", "USDT", "LTC", "TRX", + "crypto_cmc": ["BTC", "ETH", "DASH", "LSK", "DOGE", "BCH", "USDT", "LTC", "TRX", "ADM", + "BSV", "BNB", "XMR", "XEM", "NEO", "ETC", "USDC", "ZEC", "TUSD", "KCS", "USDS"], + "crypto_cc": ["BTC", "ETH", "DASH", "LSK", "DOGE", "BCH", "USDT", "LTC", "TRX", "ADM", "BSV", "BNB", "XMR", "XEM", "NEO", "ETC", "USDC", "ZEC", "TUSD", "KCS", "USDS"], - "crypto_cc": [], "crypto_cg": [], - "crypto_cg_coinids": ["adamant-messenger", "resfinex-token"], + "crypto_cg_coinids": ["bitcoin", "ethereum", "dash", "lisk", "dogecoin", "tether", "litecoin", "adamant-messenger", + "binancecoin", "ethereum-classic", "usd-coin", "true-usd", "stableusd", "resfinex-token"], "baseCoins": ["USD", "RUB", "EUR", "CNY", "JPY", "BTC", "ETH"], "fiat": { "USD/RUB": "USDRUB_TOM", From 7bfeda015f1b503d88ea78cf6b818bfd2656a79d Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 16:25:30 +0300 Subject: [PATCH 21/36] Pump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 02efa47..7fac996 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adamant-currencyinfo-services", - "version": "2.1.0", + "version": "3.0.0", "description": "Crypto and fiat currency rates service provider. MOEX, Coinmarketcap, CryptoCompare and Coingecko.", "main": "index.js", "scripts": { From 092d8c031b62cae7263a69693727a9be914cd93d Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 16:40:08 +0300 Subject: [PATCH 22/36] Fix router --- app.js | 2 +- modules/router.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app.js b/app.js index ca18229..fa4454e 100644 --- a/app.js +++ b/app.js @@ -13,7 +13,6 @@ let fetchedAll; let tickers = {}; let tickersInfo; const RATE_DIFFERENCE_PERCENT_THRESHOLD = 20; -router(tickers); function refresh() { @@ -80,6 +79,7 @@ function refresh() { if (fetchedAll) { try { db.save(tickers); + router(Object.assign({}, tickers)); log.info('Rates from all sources saved successfully'); } catch (e) { notify(`Error: Unable to save new rates in history database: ${e}`, 'error'); diff --git a/modules/router.js b/modules/router.js index 6bd7266..6df638b 100644 --- a/modules/router.js +++ b/modules/router.js @@ -6,7 +6,7 @@ const config = require('../helpers/configReader'); const log = require('../helpers/log'); const notify = require('../helpers/notify'); -let tickers; +let tickers = {}; app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ From 3011cc5cb41dad8a95da24bb14653ec9f06f81c8 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 17:35:33 +0300 Subject: [PATCH 23/36] Upgrade packages --- package.json | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 7fac996..c69d65e 100644 --- a/package.json +++ b/package.json @@ -43,17 +43,16 @@ "license": "GPL-3.0", "dependencies": { "axios": "^0.24.0", - "body-parser": "^1.18.3", - "jsonminify": "^0.4.1", - "express": "^4.16.4", - "mongodb": "^3.1.13", - "request": "^2.88.0", - "underscore": "^1.9.1" + "body-parser": "^1.19.1", + "jsonminify": "^0.4.2", + "express": "^4.17.2", + "mongodb": "^4.3.0", + "underscore": "^1.13.2" }, "devDependencies": { "eslint": "^7.32.0", "eslint-config-google": "^0.14.0", - "eslint-plugin-import": "^2.25.3", + "eslint-plugin-import": "^2.25.4", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^5.1.1" }, From 4ec0d91387261f52954f6e087aac9952ac18031e Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 17:35:45 +0300 Subject: [PATCH 24/36] Pump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c69d65e..3298061 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adamant-currencyinfo-services", - "version": "3.0.0", + "version": "3.1.0", "description": "Crypto and fiat currency rates service provider. MOEX, Coinmarketcap, CryptoCompare and Coingecko.", "main": "index.js", "scripts": { From 0085f9986a8f510d5f8b9cec6b442e07560121fd Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 18:46:20 +0300 Subject: [PATCH 25/36] Reliable: add Currency-Api for fiat --- app.js | 66 ++++++++++++++++++++++++--------------- helpers/getCurrencyApi.js | 36 +++++++++++++++++++++ 2 files changed, 77 insertions(+), 25 deletions(-) create mode 100644 helpers/getCurrencyApi.js diff --git a/app.js b/app.js index fa4454e..0f8dd2d 100644 --- a/app.js +++ b/app.js @@ -1,4 +1,5 @@ const Moex = require('./helpers/getMoex'); +const CurrencyApi = require('./helpers/getCurrencyApi'); const Cmc = require('./helpers/getCmc'); const Cc = require('./helpers/getCc'); const Cg = require('./helpers/getCg'); @@ -19,9 +20,9 @@ function refresh() { log.log('Updating rates…'); fetchedAll = true; - Cmc('USD', (data) => { + CurrencyApi((data) => { if (data) { - tickersInfo = mergeData(tickers, data, 'Null', 'Cmc'); + tickersInfo = mergeData(tickers, data, 'Null', 'CurrencyApi'); if (tickersInfo.isAlert) { notify(`Error: rates from different sources significantly differs: ${tickersInfo.alertString}. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); fetchedAll = false; @@ -30,12 +31,12 @@ function refresh() { } } else { fetchedAll = false; - notify(`Error: Unable to get data from Coinmarketcap. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); + notify(`Error: Unable to get data from CurrencyApi. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); } - Moex((data) => { + Cmc('USD', (data) => { if (data) { - tickersInfo = mergeData(tickers, data, 'Cmc', 'Moex'); + tickersInfo = mergeData(tickers, data, 'CurrencyApi', 'Cmc'); if (tickersInfo.isAlert) { notify(`Error: rates from different sources significantly differs: ${tickersInfo.alertString}. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); fetchedAll = false; @@ -44,12 +45,12 @@ function refresh() { } } else { fetchedAll = false; - notify(`Error: Unable to get data from MOEX. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); + notify(`Error: Unable to get data from Coinmarketcap. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); } - Cc('USD', (data) => { + Moex((data) => { if (data) { - tickersInfo = mergeData(tickers, data, 'Cmc+Moex', 'Cc'); + tickersInfo = mergeData(tickers, data, 'CurrencyApi+Cmc', 'Moex'); if (tickersInfo.isAlert) { notify(`Error: rates from different sources significantly differs: ${tickersInfo.alertString}. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); fetchedAll = false; @@ -58,12 +59,12 @@ function refresh() { } } else { fetchedAll = false; - notify(`Error: Unable to get data from CryptoCompare. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); + notify(`Error: Unable to get data from MOEX. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); } - Cg('USD', (data) => { + Cc('USD', (data) => { if (data) { - tickersInfo = mergeData(tickers, data, 'Cmc+Moex+Cc', 'Cg'); + tickersInfo = mergeData(tickers, data, 'CurrencyApi+Cmc+Moex', 'Cc'); if (tickersInfo.isAlert) { notify(`Error: rates from different sources significantly differs: ${tickersInfo.alertString}. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); fetchedAll = false; @@ -72,23 +73,38 @@ function refresh() { } } else { fetchedAll = false; - notify(`Error: Unable to get data from Coingecko. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); + notify(`Error: Unable to get data from CryptoCompare. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); } - converter(tickers); - if (fetchedAll) { - try { - db.save(tickers); - router(Object.assign({}, tickers)); - log.info('Rates from all sources saved successfully'); - } catch (e) { - notify(`Error: Unable to save new rates in history database: ${e}`, 'error'); + Cg('USD', (data) => { + if (data) { + tickersInfo = mergeData(tickers, data, 'CurrencyApi+Cmc+Moex+Cc', 'Cg'); + if (tickersInfo.isAlert) { + notify(`Error: rates from different sources significantly differs: ${tickersInfo.alertString}. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); + fetchedAll = false; + } else { + tickers = tickersInfo.merged; + } + } else { + fetchedAll = false; + notify(`Error: Unable to get data from Coingecko. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); } - } - }); // Coingecko - }); // Cryptocompare - }); // Moex - }); // Coinmarketcap + + converter(tickers); + if (fetchedAll) { + try { + db.save(tickers); + router(Object.assign({}, tickers)); + log.info('Rates from all sources saved successfully'); + } catch (e) { + notify(`Error: Unable to save new rates in history database: ${e}`, 'error'); + } + } + }); // Coingecko + }); // Cryptocompare + }); // Moex + }); // Coinmarketcap + }); // CurrencyApi } // refresh diff --git a/helpers/getCurrencyApi.js b/helpers/getCurrencyApi.js new file mode 100644 index 0000000..a36a468 --- /dev/null +++ b/helpers/getCurrencyApi.js @@ -0,0 +1,36 @@ +const axios = require('axios'); +const config = require('./configReader'); +const log = require('./log'); +const notify = require('./notify'); + +// https://github.com/fawazahmed0/currency-api#readme +const url = 'https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies/usd.json'; +// This service updates only once in 24h, so skip cryptos +const skipCoins = ['USD', 'BTC', 'ETH']; + +module.exports = (cb) => { + + axios.get(url) + .then(function(response) { + try { + const rates = {}; + const data = response.data.usd; + config.baseCoins.forEach((currency) => { + const rate = data[currency.toLowerCase()]; + if (!skipCoins.includes(currency) && rate) { + rates['USD/' + currency.toUpperCase()] = +rate.toFixed(8); + rates[currency.toUpperCase() + '/USD'] = +(1 / +rate).toFixed(8); + } + }); + log.log(`Cryptocurrency-Api rates updated successfully`); + cb(rates); + } catch (e) { + notify(`Unable to process data ${JSON.stringify(response.data)} from request to ${url}. Error: ${e}`, 'error'); + cb(false); + } + }) + .catch(function(error) { + notify(`Request to ${url} failed with ${error.response?.status} status code, ${error.toString()}${error.response?.data ? '. Message: ' + JSON.stringify(error.response.data) : ''}.`, 'error'); + cb(false); + }); +}; From 6b7396399167e445213baa3fbf61c9df0158404c Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 18:47:27 +0300 Subject: [PATCH 26/36] Update description --- README.md | 3 ++- package.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ab5452d..8e907f6 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ -ADAMANT InfoServices is a crypto and fiat currency rates service provider. It collects rates from MOEX, Coinmarketcap, CryptoCompare and Coingecko and calculates cross-rates, and provides information via API. +ADAMANT InfoServices is a crypto and fiat currency rates service provider. It collects rates from MOEX, Currency-Api, Coinmarketcap, CryptoCompare and Coingecko and calculates cross-rates, and provides information via API. Features: - Collects rates from MOEX for fiat tickers +- Collects rates from Currency-Api for fiat tickers - Collects rates from Coinmarketcap for crypto tickers - Collects rates from CryptoCompare for crypto tickers - Collects rates from Coingecko for crypto tickers diff --git a/package.json b/package.json index 3298061..e336e4a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adamant-currencyinfo-services", - "version": "3.1.0", + "version": "3.2.0", "description": "Crypto and fiat currency rates service provider. MOEX, Coinmarketcap, CryptoCompare and Coingecko.", "main": "index.js", "scripts": { @@ -25,6 +25,7 @@ "coingecko", "coinmarketcap", "cryptocompare", + "currency-api", "ticker", "rate", "exchange rate", From 0c32539b39bbdaab1e2a188d9fe4f515506cdc4a Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 18:47:39 +0300 Subject: [PATCH 27/36] Pump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e336e4a..798e9c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adamant-currencyinfo-services", - "version": "3.2.0", + "version": "3.3.0", "description": "Crypto and fiat currency rates service provider. MOEX, Coinmarketcap, CryptoCompare and Coingecko.", "main": "index.js", "scripts": { From 4b3d3a0da61911aba206599cef3c60a0a0ed44be Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 20:05:49 +0300 Subject: [PATCH 28/36] Fix tickers bug --- app.js | 4 +++- modules/router.js | 2 +- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app.js b/app.js index 0f8dd2d..f3b3bf3 100644 --- a/app.js +++ b/app.js @@ -19,10 +19,12 @@ function refresh() { log.log('Updating rates…'); fetchedAll = true; + tickers = {}; CurrencyApi((data) => { if (data) { - tickersInfo = mergeData(tickers, data, 'Null', 'CurrencyApi'); + console.log(tickers); + tickersInfo = mergeData({}, data, 'Null', 'CurrencyApi'); if (tickersInfo.isAlert) { notify(`Error: rates from different sources significantly differs: ${tickersInfo.alertString}. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); fetchedAll = false; diff --git a/modules/router.js b/modules/router.js index 6df638b..644d2b6 100644 --- a/modules/router.js +++ b/modules/router.js @@ -46,7 +46,7 @@ module.exports = (tickers_) => { tickers = tickers_; }; -app.listen(config.port, () => notify('InfoService is listening on port ' + config.port, 'info')); +app.listen(config.port, () => notify(`InfoService v${config.version} is listening on port ${config.port}`, 'info')); function respSuccess(data) { if (Object.entries(data).length === 0 && data.constructor === Object) { // Empty object diff --git a/package.json b/package.json index 798e9c6..e100c74 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adamant-currencyinfo-services", - "version": "3.3.0", + "version": "3.3.1", "description": "Crypto and fiat currency rates service provider. MOEX, Coinmarketcap, CryptoCompare and Coingecko.", "main": "index.js", "scripts": { From 05bdc8def307d4eec6942bcc872ca7944fe18051 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Tue, 11 Jan 2022 20:06:56 +0300 Subject: [PATCH 29/36] Clean up --- app.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app.js b/app.js index f3b3bf3..391d42e 100644 --- a/app.js +++ b/app.js @@ -23,7 +23,6 @@ function refresh() { CurrencyApi((data) => { if (data) { - console.log(tickers); tickersInfo = mergeData({}, data, 'Null', 'CurrencyApi'); if (tickersInfo.isAlert) { notify(`Error: rates from different sources significantly differs: ${tickersInfo.alertString}. InfoService will provide previous rates; historical rates wouldn't be saved.`, 'error'); From a682f0ad9d859fd6890da631e5c1cd4791b9539d Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 22 Jan 2022 11:39:04 +0300 Subject: [PATCH 30/36] Change RATE_DIFFERENCE_PERCENT_THRESHOLD from 20 to 25 --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 391d42e..3bbf793 100644 --- a/app.js +++ b/app.js @@ -13,7 +13,7 @@ let fetchedAll; let tickers = {}; let tickersInfo; -const RATE_DIFFERENCE_PERCENT_THRESHOLD = 20; +const RATE_DIFFERENCE_PERCENT_THRESHOLD = 25; function refresh() { From ddc1f448c3ef0aa2888ff25aafe8c58bf3e80f73 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 22 Jan 2022 11:41:23 +0300 Subject: [PATCH 31/36] Remove USDS from Cryptocompare --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 244dc1e..efc8cee 100644 --- a/config.json +++ b/config.json @@ -2,7 +2,7 @@ "crypto_cmc": ["BTC", "ETH", "DASH", "LSK", "DOGE", "BCH", "USDT", "LTC", "TRX", "ADM", "BSV", "BNB", "XMR", "XEM", "NEO", "ETC", "USDC", "ZEC", "TUSD", "KCS", "USDS"], "crypto_cc": ["BTC", "ETH", "DASH", "LSK", "DOGE", "BCH", "USDT", "LTC", "TRX", "ADM", - "BSV", "BNB", "XMR", "XEM", "NEO", "ETC", "USDC", "ZEC", "TUSD", "KCS", "USDS"], + "BSV", "BNB", "XMR", "XEM", "NEO", "ETC", "USDC", "ZEC", "TUSD", "KCS"], "crypto_cg": [], "crypto_cg_coinids": ["bitcoin", "ethereum", "dash", "lisk", "dogecoin", "tether", "litecoin", "adamant-messenger", "binancecoin", "ethereum-classic", "usd-coin", "true-usd", "stableusd", "resfinex-token"], From ec2671dd7fe91f8729725f70dd2ba8fcd24ae4a0 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sat, 22 Jan 2022 11:52:28 +0300 Subject: [PATCH 32/36] Pump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e100c74..c83a780 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adamant-currencyinfo-services", - "version": "3.3.1", + "version": "3.3.2", "description": "Crypto and fiat currency rates service provider. MOEX, Coinmarketcap, CryptoCompare and Coingecko.", "main": "index.js", "scripts": { From 5c0a052fc6491de92f7f591991a5816ca78f50f2 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sun, 23 Jan 2022 11:13:07 +0300 Subject: [PATCH 33/36] Update dependencies --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index c83a780..4a6ac5c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adamant-currencyinfo-services", - "version": "3.3.2", + "version": "3.3.3", "description": "Crypto and fiat currency rates service provider. MOEX, Coinmarketcap, CryptoCompare and Coingecko.", "main": "index.js", "scripts": { @@ -43,11 +43,11 @@ "author": "ADAMANT Dev Team, Aleksei Lebedev (https://adamant.im)", "license": "GPL-3.0", "dependencies": { - "axios": "^0.24.0", + "axios": "^0.25.0", "body-parser": "^1.19.1", "jsonminify": "^0.4.2", "express": "^4.17.2", - "mongodb": "^4.3.0", + "mongodb": "^4.3.1", "underscore": "^1.13.2" }, "devDependencies": { From 2b485223a1389e2ff144ad57def165edc02a0cc2 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Sun, 23 Jan 2022 12:09:38 +0300 Subject: [PATCH 34/36] Workaround for 'bad record mac' --- helpers/getMoex.js | 9 +++++++-- package.json | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/helpers/getMoex.js b/helpers/getMoex.js index b9e5aee..9e1869c 100644 --- a/helpers/getMoex.js +++ b/helpers/getMoex.js @@ -37,7 +37,12 @@ module.exports = (cb) => { } }) .catch(function(error) { - notify(`Request to ${url} failed with ${error.response?.status} status code, ${error.toString()}${error.response?.data ? '. Message: ' + JSON.stringify(error.response.data) : ''}.`, 'error'); - cb(false); + if (error.toString().includes('decryption failed or bad record mac')) { + log.warn(`Request to MOEX ${url} failed: ${error.toString()}. Retrying…`); + return module.exports(cb); + } else { + notify(`Request to ${url} failed with ${error.response?.status} status code, ${error.toString()}${error.response?.data ? '. Message: ' + JSON.stringify(error.response.data) : ''}.`, 'error'); + cb(false); + } }); }; diff --git a/package.json b/package.json index 4a6ac5c..e49cfd9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adamant-currencyinfo-services", - "version": "3.3.3", + "version": "3.3.4", "description": "Crypto and fiat currency rates service provider. MOEX, Coinmarketcap, CryptoCompare and Coingecko.", "main": "index.js", "scripts": { From 3d12bec7cc58a8791d097e533888d878c865ef64 Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 Jan 2022 11:16:28 +0300 Subject: [PATCH 35/36] Update MOEX to read 'CETS' rates --- helpers/getMoex.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/helpers/getMoex.js b/helpers/getMoex.js index 9e1869c..fc392bb 100644 --- a/helpers/getMoex.js +++ b/helpers/getMoex.js @@ -12,20 +12,20 @@ module.exports = (cb) => { .then(function(response) { try { const rates = {}; - const data = response.data.securities.data; - Object.keys(config.fiat).forEach((m) => { - const code = config.fiat[m]; - const c = _.findWhere(data, { + const data = response.data.securities.data.filter((tickerData) => tickerData[1] === 'CETS'); + Object.keys(config.fiat).forEach((pair) => { + const code = config.fiat[pair]; + const tickerData = _.findWhere(data, { 2: code, }); - let price = (c[14] + c[15]) / 2; - if (m === 'JPY/RUB') price /= 100; - rates[m] = +price.toFixed(8); - if (m === 'USD/RUB') { + let price = (tickerData[14] + tickerData[15]) / 2; + if (pair === 'JPY/RUB') price /= 100; + rates[pair] = +price.toFixed(8); + if (pair === 'USD/RUB') { rates['RUB/USD'] = +(1 / rates['USD/RUB']).toFixed(8); } else { - const market = 'USD/' + m.replace('/RUB', ''); - const price = rates['USD/RUB'] / rates[m]; + const market = 'USD/' + pair.replace('/RUB', ''); + const price = rates['USD/RUB'] / rates[pair]; rates[market] = +price.toFixed(8); } }); From 28c4a86dda5950468820e707608b2ec4c8b6e7ff Mon Sep 17 00:00:00 2001 From: adamant-al Date: Mon, 24 Jan 2022 11:16:50 +0300 Subject: [PATCH 36/36] Pump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e49cfd9..ce0e205 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adamant-currencyinfo-services", - "version": "3.3.4", + "version": "3.3.5", "description": "Crypto and fiat currency rates service provider. MOEX, Coinmarketcap, CryptoCompare and Coingecko.", "main": "index.js", "scripts": {