From 4032e66be3ab0458fa1b9e18292f0b79d84c6a83 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Sun, 20 Oct 2019 11:55:46 -0700
Subject: [PATCH 01/49] Created middleware to retrieve JWT token from header
---
package-lock.json | 308 +++++++++++++++++++----------
package.json | 5 +-
src/app.js | 6 +
src/middleware/auth.js | 43 ++++
src/middleware/jwt-auth.js | 43 ++++
src/middleware/route-ratelimit.js | 21 +-
test/v3/integration/rate-limits.js | 194 ++++++++++--------
7 files changed, 436 insertions(+), 184 deletions(-)
create mode 100644 src/middleware/jwt-auth.js
diff --git a/package-lock.json b/package-lock.json
index a1846d6..794791d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -102,16 +102,18 @@
}
},
"@chris.troutner/bch-js": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/@chris.troutner/bch-js/-/bch-js-1.4.4.tgz",
- "integrity": "sha512-928YAVLKhQ0869/toMkIJl76/7Q31UGVNdYFky1tueJ3BibxgiM+nKl2YbQd06doLuZUniwcD9lKm3sHjFqNbw==",
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@chris.troutner/bch-js/-/bch-js-1.6.1.tgz",
+ "integrity": "sha512-Wkv7iVw9wYjNF5/Ewy5Qq995x1AV+DWRqikZg9FQxCl7Tub7PmmDfADcJwp+tNKGZs5Q+dpiL30P6zBld52g7g==",
"requires": {
"apidoc": "^0.17.7",
"assert": "^2.0.0",
"axios": "^0.19.0",
"bc-bip68": "^1.0.5",
"bch-wallet-bridge.js": "github:web3bch/bch-wallet-bridge.js#master",
+ "bchaddrjs-slp": "^0.2.5",
"bigi": "^1.4.2",
+ "bignumber.js": "^9.0.0",
"bip-schnorr": "^0.3.0",
"bip21": "github:Bitcoin-com/bip21",
"bip32-utils": "github:Bitcoin-com/bip32-utils#0.13.1",
@@ -141,7 +143,6 @@
"repl.history": "^0.1.4",
"safe-buffer": "^5.1.2",
"satoshi-bitcoin": "^1.0.4",
- "slpjs": "^0.21.0",
"socket.io": "^2.1.1",
"socket.io-client": "^2.1.1",
"touch": "^3.1.0",
@@ -287,9 +288,9 @@
"dev": true
},
"@semantic-release/github": {
- "version": "5.4.2",
- "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-5.4.2.tgz",
- "integrity": "sha512-8gkOa5tED/+sjAPwZRYsLaGr6VuAGLZinSvLsuF9/l4qLeYV8gvj7fhjFJepGu6y31t7PR2J9SWzmsqsBAyyKQ==",
+ "version": "5.5.4",
+ "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-5.5.4.tgz",
+ "integrity": "sha512-CovZ9zs/rbBOCyyzmstoCwGS5qNEgab3wB8y3SAvOD7TfhtqizWVRkUJV7nzzaevomhUSZD/lp7Cs/fk1sE1Qw==",
"dev": true,
"requires": {
"@octokit/rest": "^16.27.0",
@@ -301,16 +302,49 @@
"fs-extra": "^8.0.0",
"globby": "^10.0.0",
"http-proxy-agent": "^2.1.0",
- "https-proxy-agent": "^2.2.1",
- "issue-parser": "^4.0.0",
+ "https-proxy-agent": "^3.0.0",
+ "issue-parser": "^5.0.0",
"lodash": "^4.17.4",
"mime": "^2.4.3",
"p-filter": "^2.0.0",
"p-retry": "^4.0.0",
- "parse-github-url": "^1.0.1",
"url-join": "^4.0.0"
},
"dependencies": {
+ "https-proxy-agent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.0.tgz",
+ "integrity": "sha512-y4jAxNEihqvBI5F3SaO2rtsjIOnnNA8sEbuiP+UhJZJHeM2NRm6c09ax2tgqme+SgUUvjao2fJXF4h3D6Cb2HQ==",
+ "dev": true,
+ "requires": {
+ "agent-base": "^4.3.0",
+ "debug": "^3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ }
+ }
+ },
+ "issue-parser": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-5.0.0.tgz",
+ "integrity": "sha512-q/16W7EPHRL0FKVz9NU++TUsoygXGj6JOi88oulyAcQG+IEZ0T6teVdE+VLbe19OfL/tbV8Wi3Dfo0HedeHW0Q==",
+ "dev": true,
+ "requires": {
+ "lodash.capitalize": "^4.2.1",
+ "lodash.escaperegexp": "^4.1.2",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.uniqby": "^4.7.0"
+ }
+ },
"mime": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
@@ -1466,8 +1500,8 @@
}
},
"bchaddrjs-slp": {
- "version": "git://github.com/simpleledger/bchaddrjs.git#ea05d679783a6737f2f99adc37ebf485dc64f006",
- "from": "git://github.com/simpleledger/bchaddrjs.git#master",
+ "version": "0.2.6",
+ "resolved": "git://github.com/simpleledger/bchaddrjs.git#ea05d679783a6737f2f99adc37ebf485dc64f006",
"requires": {
"bs58check": "^2.1.2",
"cashaddrjs-slp": "^0.2.11"
@@ -1519,8 +1553,7 @@
"bignumber.js": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
- "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==",
- "dev": true
+ "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A=="
},
"binary-extensions": {
"version": "1.13.1",
@@ -1711,7 +1744,7 @@
"integrity": "sha512-x0wMVSCZ56ZQnSQ+Xim7XfS0IYiOyOwo0pdMCmR+cDNB7zRhICFuH5i3lNdLSgUw1e7Pc3FmUlC9wruQNlYMnA=="
},
"bitcoincashjs-lib": {
- "version": "github:christroutner/bitcoincashjs-lib#0a2291b5c5558241003aa9609f82846313604f15",
+ "version": "github:christroutner/bitcoincashjs-lib#b03ca974d4fd548cb42c7a522863e5d9be6051ef",
"from": "github:christroutner/bitcoincashjs-lib",
"requires": {
"bech32": "^1.1.2",
@@ -1884,6 +1917,11 @@
"integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==",
"dev": true
},
+ "bowser": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.7.0.tgz",
+ "integrity": "sha512-aIlMvstvu8x+34KEiOHD3AsBgdrzg6sxALYiukOWhFvGMbQI6TRP/iY0LMhUrHs56aD6P1G0Z7h45PUJaa5m9w=="
+ },
"boxen": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz",
@@ -2236,6 +2274,11 @@
"resolved": "https://registry.npmjs.org/buffer-compare/-/buffer-compare-1.1.1.tgz",
"integrity": "sha1-W+e+hTr4kZjR9N3AkNHWakiu9ZY="
},
+ "buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
+ },
"buffer-equals": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/buffer-equals/-/buffer-equals-1.0.4.tgz",
@@ -2429,9 +2472,9 @@
"dev": true
},
"cashaddrjs": {
- "version": "0.3.6",
- "resolved": "https://registry.npmjs.org/cashaddrjs/-/cashaddrjs-0.3.6.tgz",
- "integrity": "sha512-TEeTEXT8Gft4cNoZKisCdyrAymnSRYpZHtvCRgXJ9OmOwyTKn5vnCWbPQLL3EiUkm1HeMxSrKNK29nMfvaT2Qw==",
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/cashaddrjs/-/cashaddrjs-0.3.8.tgz",
+ "integrity": "sha512-gpXj9Qki9noucK0ahPB6dx9A539KQ4TbqKLwl/JsCvD4iLLu1thtoAIDy2hwP6PWg6o1nvK+igsutMA6OvO2Mg==",
"requires": {
"big-integer": "1.6.36"
},
@@ -2722,9 +2765,9 @@
}
},
"commander": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.0.tgz",
- "integrity": "sha512-pl3QrGOBa9RZaslQiqnnKX2J068wcQw7j9AIaBQ9/JEp5RY6je4jKTImg0Bd+rpoONSe7GUFSgkxLeo17m3Pow=="
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz",
+ "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow=="
},
"commist": {
"version": "1.1.0",
@@ -3674,6 +3717,14 @@
"safer-buffer": "^2.1.0"
}
},
+ "ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
"ecurve": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/ecurve/-/ecurve-1.0.6.tgz",
@@ -4567,12 +4618,20 @@
}
},
"eslint-utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.0.tgz",
- "integrity": "sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==",
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz",
+ "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==",
"dev": true,
"requires": {
- "eslint-visitor-keys": "^1.0.0"
+ "eslint-visitor-keys": "^1.1.0"
+ },
+ "dependencies": {
+ "eslint-visitor-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz",
+ "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==",
+ "dev": true
+ }
}
},
"eslint-visitor-keys": {
@@ -4814,11 +4873,34 @@
"basic-auth": "^2.0.1"
}
},
+ "express-jwt": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-5.3.1.tgz",
+ "integrity": "sha512-1C9RNq0wMp/JvsH/qZMlg3SIPvKu14YkZ4YYv7gJQ1Vq+Dv8LH9tLKenS5vMNth45gTlEUGx+ycp9IHIlaHP/g==",
+ "requires": {
+ "async": "^1.5.0",
+ "express-unless": "^0.3.0",
+ "jsonwebtoken": "^8.1.0",
+ "lodash.set": "^4.0.0"
+ },
+ "dependencies": {
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ }
+ }
+ },
"express-rate-limit": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.0.0.tgz",
"integrity": "sha512-dhT57wqxfqmkOi4HM7NuT4Gd7gbUgSK2ocG27Y6lwm8lbOAw9XQfeANawGq8wLDtlGPO1ZgDj0HmKsykTxfFAg=="
},
+ "express-unless": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-0.3.1.tgz",
+ "integrity": "sha1-JVfBRudb65A+LSR/m1ugFFJpbiA="
+ },
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -6141,9 +6223,9 @@
"integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA=="
},
"handlebars": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
- "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.3.tgz",
+ "integrity": "sha512-B0W4A2U1ww3q7VVthTKfh+epHx+q4mCt6iK+zEAzbMBpWQAwxCeKxEGpj/1oQTpzPXDNSOG7hmG14TsISH50yw==",
"requires": {
"neo-async": "^2.6.0",
"optimist": "^0.6.1",
@@ -6323,9 +6405,9 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"helmet": {
- "version": "3.20.0",
- "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.20.0.tgz",
- "integrity": "sha512-Ob+TqmQFZ5f7WgP8kBbAzNPsbf6p1lOj5r+327/ymw/IILWih3wcx9u/u/S8Mwv5wbBkO7Li6x5s23t3COhUKw==",
+ "version": "3.21.1",
+ "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.21.1.tgz",
+ "integrity": "sha512-IC/54Lxvvad2YiUdgLmPlNFKLhNuG++waTF5KPYq/Feo3NNhqMFbcLAlbVkai+9q0+4uxjxGPJ9bNykG+3zZNg==",
"requires": {
"depd": "2.0.0",
"dns-prefetch-control": "0.2.0",
@@ -6334,14 +6416,14 @@
"feature-policy": "0.3.0",
"frameguard": "3.1.0",
"helmet-crossdomain": "0.4.0",
- "helmet-csp": "2.8.0",
+ "helmet-csp": "2.9.2",
"hide-powered-by": "1.1.0",
"hpkp": "2.0.0",
"hsts": "2.2.0",
"ienoopen": "1.1.0",
"nocache": "2.1.0",
"referrer-policy": "1.2.0",
- "x-xss-protection": "1.2.0"
+ "x-xss-protection": "1.3.0"
},
"dependencies": {
"depd": {
@@ -6357,14 +6439,14 @@
"integrity": "sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA=="
},
"helmet-csp": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.8.0.tgz",
- "integrity": "sha512-MlCPeM0Sm3pS9RACRihx70VeTHmkQwa7sum9EK1tfw1VZyvFU0dBWym9nHh3CRkTRNlyNm/WFCMvuh9zXkOjNw==",
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.9.2.tgz",
+ "integrity": "sha512-Lt5WqNfbNjEJ6ysD4UNpVktSyjEKfU9LVJ1LaFmPfYseg/xPealPfgHhtqdAdjPDopp5zbg/VWCyp4cluMIckw==",
"requires": {
+ "bowser": "^2.6.1",
"camelize": "1.0.0",
"content-security-policy-builder": "2.1.0",
- "dasherize": "2.0.0",
- "platform": "1.3.5"
+ "dasherize": "2.0.0"
}
},
"help-me": {
@@ -6518,27 +6600,6 @@
"resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="
},
- "https-proxy-agent": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz",
- "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==",
- "dev": true,
- "requires": {
- "agent-base": "^4.3.0",
- "debug": "^3.1.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
- "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
- }
- }
- }
- },
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -7109,19 +7170,6 @@
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
"dev": true
},
- "issue-parser": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-4.0.0.tgz",
- "integrity": "sha512-1RmmAXHl5+cqTZ9dRr861xWy0Gkc9TWTEklgjKv+nhlB1dY1NmGBV8b20jTWRL5cPGpOIXkz84kEcDBM8Nc0cw==",
- "dev": true,
- "requires": {
- "lodash.capitalize": "^4.2.1",
- "lodash.escaperegexp": "^4.1.2",
- "lodash.isplainobject": "^4.0.6",
- "lodash.isstring": "^4.0.1",
- "lodash.uniqby": "^4.7.0"
- }
- },
"istanbul-lib-coverage": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
@@ -7297,6 +7345,30 @@
"resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
"integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA="
},
+ "jsonwebtoken": {
+ "version": "8.5.1",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
+ "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
+ "requires": {
+ "jws": "^3.2.2",
+ "lodash.includes": "^4.3.0",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isinteger": "^4.0.4",
+ "lodash.isnumber": "^3.0.3",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.once": "^4.0.0",
+ "ms": "^2.1.1",
+ "semver": "^5.6.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ }
+ }
+ },
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@@ -7324,6 +7396,25 @@
"integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==",
"dev": true
},
+ "jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "requires": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "requires": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
"keccak": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/keccak/-/keccak-1.4.0.tgz",
@@ -7553,34 +7644,56 @@
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
"dev": true
},
+ "lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
+ },
+ "lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
+ },
+ "lodash.isinteger": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+ "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
+ },
"lodash.ismatch": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz",
"integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=",
"dev": true
},
+ "lodash.isnumber": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+ "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
+ },
"lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
- "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=",
- "dev": true
+ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
},
"lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
- "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=",
- "dev": true
+ "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
},
"lodash.memoize": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
"integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8="
},
+ "lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
+ },
"lodash.set": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
- "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=",
- "dev": true
+ "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM="
},
"lodash.toarray": {
"version": "4.4.0",
@@ -12567,12 +12680,6 @@
"safe-buffer": "^5.1.1"
}
},
- "parse-github-url": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz",
- "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==",
- "dev": true
- },
"parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
@@ -12634,6 +12741,14 @@
"passport-strategy": "1.x.x"
}
},
+ "passport-local": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
+ "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=",
+ "requires": {
+ "passport-strategy": "1.x.x"
+ }
+ },
"passport-strategy": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
@@ -12870,11 +12985,6 @@
"find-up": "^3.0.0"
}
},
- "platform": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.5.tgz",
- "integrity": "sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q=="
- },
"pluralize": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
@@ -15254,19 +15364,19 @@
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"uglify-js": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz",
- "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==",
+ "version": "3.6.3",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.3.tgz",
+ "integrity": "sha512-KfQUgOqTkLp2aZxrMbCuKCDGW9slFYu2A23A36Gs7sGzTLcRBDORdOi5E21KWHFIfkY8kzgi/Pr1cXCh0yIp5g==",
"optional": true,
"requires": {
- "commander": "~2.20.0",
+ "commander": "~2.20.3",
"source-map": "~0.6.1"
},
"dependencies": {
"commander": {
- "version": "2.20.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
- "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"optional": true
},
"source-map": {
@@ -15882,9 +15992,9 @@
}
},
"x-xss-protection": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.2.0.tgz",
- "integrity": "sha512-xN0kV+8XfOQM2OPPBdEbGtbvJNNP1pvZR7sE6d44cjJFQG4OiGDdienPg5iOUGswBTiGbBvtYDURd30BMJwwqg=="
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.3.0.tgz",
+ "integrity": "sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg=="
},
"xdg-basedir": {
"version": "3.0.0",
diff --git a/package.json b/package.json
index 2c593b5..d184714 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,7 @@
"node": ">=10.15.1"
},
"dependencies": {
- "@chris.troutner/bch-js": "^1.3.0",
+ "@chris.troutner/bch-js": "^1.6.1",
"apidoc": "^0.17.7",
"axios": "^0.19.0",
"body-parser": "^1.18.3",
@@ -33,7 +33,7 @@
"express": "^4.15.5",
"express-basic-auth": "^1.1.3",
"express-rate-limit": "^5.0.0",
- "helmet": "^3.12.1",
+ "helmet": "^3.21.1",
"level": "^5.0.1",
"mkdirp": "^0.5.1",
"mocha": "^6.1.4",
@@ -42,6 +42,7 @@
"passport": "^0.4.0",
"passport-anonymous": "^1.0.1",
"passport-http": "^0.3.0",
+ "passport-local": "^1.0.0",
"pg": "^7.11.0",
"pg-hstore": "^2.3.2",
"slp-sdk": "^4.4.1",
diff --git a/src/app.js b/src/app.js
index 0b06579..f487d8d 100644
--- a/src/app.js
+++ b/src/app.js
@@ -15,7 +15,10 @@ const helmet = require("helmet")
const debug = require("debug")("rest-cloud:server")
const http = require("http")
const cors = require("cors")
+
+// Auth and rate limiting middleware libraries.
const AuthMW = require("./middleware/auth")
+const jwtAuth = require("./middleware/jwt-auth")
// v2
const indexV2 = require("./routes/v2/index")
@@ -88,6 +91,9 @@ app.use(express.static(path.join(__dirname, "public")))
const v2prefix = "v2"
const v3prefix = "v3"
+// Inspect the header for a JWT token.
+app.use(`/${v3prefix}/`, jwtAuth.getTokenFromHeaders)
+
// Instantiate the authorization middleware, used to implement pro-tier rate limiting.
const auth = new AuthMW()
app.use(`/${v2prefix}/`, auth.mw())
diff --git a/src/middleware/auth.js b/src/middleware/auth.js
index f734a4b..86a9e1b 100644
--- a/src/middleware/auth.js
+++ b/src/middleware/auth.js
@@ -1,6 +1,13 @@
/*
Handle authorization for bypassing rate limits.
+ 1) Default is 'Anonymous Authentication', which unlocks the freemimum tier by
+ default.
+ 2) Hard-coded 'Basic Authentication' is a token that does not expire and is
+ provided to buisiness partners.
+ 3) JWT-based 'Local Authentication' is used for normal users that pay to
+ access the premium pro-tier services.
+
This file uses the passport npm library to check the header of each REST API
call for the prescence of a Basic authorization header:
https://en.wikipedia.org/wiki/Basic_access_authentication
@@ -14,7 +21,9 @@
const passport = require("passport")
const BasicStrategy = require("passport-http").BasicStrategy
const AnonymousStrategy = require("passport-anonymous")
+const LocalStrategy = require("passport-local")
const wlogger = require("../util/winston-logging")
+const axios = require("axios")
// Used for debugging and iterrogating JS objects.
const util = require("util")
@@ -88,6 +97,40 @@ class AuthMW {
return done(null, true)
})
)
+
+ // JWT token based authentication.
+ passport.use(
+ new LocalStrategy(
+ {
+ usernameField: "user[email]",
+ passwordField: "user[password]",
+ passReqToCallback: true,
+ session: false
+ },
+ async (req, email, password, done) => {
+ console.log(`Checking against local strategy.`)
+
+ const userData = {}
+ const isValid = true
+
+ // Lookup the user from the database.
+ // const userData = await userDB.findByEmail(email)
+ //console.log(`userData: ${util.inspect(userDataRaw)}`)
+
+ // Hash the password and see if it matches the saved hash.
+ // const isValid = jwt.validatePassword(userData, password)
+
+ if (isValid) {
+ //console.log(`Passwords match!`)
+ return done(null, userData)
+ }
+
+ return done(null, false, {
+ errors: { "email or password": "is invalid" }
+ })
+ }
+ )
+ )
}
// Middleware called by the route.
diff --git a/src/middleware/jwt-auth.js b/src/middleware/jwt-auth.js
new file mode 100644
index 0000000..485e7fa
--- /dev/null
+++ b/src/middleware/jwt-auth.js
@@ -0,0 +1,43 @@
+/*
+ This middleware inspects the request header for a JWT token.
+ If found, will populate req.locals.jwtToken with the JWT token.
+*/
+
+"use strict"
+
+// This function searches the header for the a JWT token in the authorization header.
+// If one is found, this middleware passes the JWT token through the
+// req.locals.jwtToken property.
+const getTokenFromHeaders = (req, res, next) => {
+ try {
+ // console.log(`getTokenFromHeaders2: Searching headers for a JWT token.`)
+
+ // console.log(`req.headers: `, req.headers)
+
+ // If the authorization header exists.
+ if (req.headers.authorization) {
+ const authStr = req.headers.authorization
+
+ // If the header is proceeded by the word 'Token'
+ if (authStr.split(" ")[0] === "Token") {
+ const token = authStr.split(" ")[1]
+
+ // console.log(`JWT found: ${token}`)
+
+ // Create the req.locals property if it does not yet exist.
+ if (!req.locals) req.locals = {}
+ req.locals.jwtToken = token
+ }
+ }
+ } catch (err) {
+ console.log(`Error in getTokenFromHeaders2: `, err)
+ }
+
+ next()
+}
+
+const jwtAuth = {
+ getTokenFromHeaders
+}
+
+module.exports = jwtAuth
diff --git a/src/middleware/route-ratelimit.js b/src/middleware/route-ratelimit.js
index 25aab88..70e2c20 100644
--- a/src/middleware/route-ratelimit.js
+++ b/src/middleware/route-ratelimit.js
@@ -24,11 +24,28 @@ const PRO_RPM = 10 * maxRequests
const uniqueRateLimits = {}
const routeRateLimit = function(req, res, next) {
+ // Disable rate limiting if 0 passed from RATE_LIMIT_MAX_REQUESTS
+ if (maxRequests === 0) return next()
+
// Create a res.locals object if not passed in.
if (!req.locals) req.locals = {}
- // Disable rate limiting if 0 passed from RATE_LIMIT_MAX_REQUESTS
- if (maxRequests === 0) return next()
+ if (req.locals.jwtToken)
+ console.log(`req.locals.jwtToken: ${req.locals.jwtToken}`)
+
+ // If no JWT token was provided, skip
+ if (req.payload)
+ console.log(`req.payload: ${JSON.stringify(req.payload, null, 2)}`)
+ // // Unlock the pro-tier rate limits if the user passed in a valid JWT token.
+ // if (!proRateLimits) {
+ // const user = await getUserFromJWT(req)
+ //
+ // // Enable pro-tier rate limits for this user.
+ // if(user) {
+ // console.log(`${user.email} (${user.id}) passed in valid JWT`)
+ // proRateLimits = true
+ // }
+ // }
// Current route
const rateLimitTier = req.locals.proLimit ? "PRO" : "BASIC"
diff --git a/test/v3/integration/rate-limits.js b/test/v3/integration/rate-limits.js
index e487d2d..3a71efa 100644
--- a/test/v3/integration/rate-limits.js
+++ b/test/v3/integration/rate-limits.js
@@ -14,8 +14,11 @@ const axios = require("axios")
const util = require("util")
util.inspect.defaultOptions = { depth: 1 }
-const SERVER = `http://192.168.0.36:12400/v3/`
-//const SERVER = `http://localhost:3000/v2/`
+// const SERVER = `http://192.168.0.36:12400/v3/`
+const SERVER = `http://localhost:3000/v3/`
+
+const TEST_JWT =
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYTc5ZDk4OTYyMjRjNjM2MmQwYzkwMiIsImlhdCI6MTU3MTUzOTU1MSwiZXhwIjoxNTc0MTMxNTUxfQ.PfPW_Z2NYT1O2zUHXopcz2aLGHSGudaKOIGnt7SuAi4"
describe("#rate limits", () => {
it("should get control/getNetworkInfo() with no auth", async () => {
@@ -32,102 +35,131 @@ describe("#rate limits", () => {
assert.hasAnyKeys(result.data, ["version"])
})
- it("should trigger rate-limit handler if rate limits exceeds 30 request per minute", async () => {
+ // it("should trigger rate-limit handler if rate limits exceeds 30 request per minute", async () => {
+ // try {
+ // // Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
+ // const options = {
+ // method: "GET",
+ // url: `${SERVER}control/getNetworkInfo`
+ // }
+ //
+ // const promises = []
+ // for (let i = 0; i < 30; i++) {
+ // const promise = axios(options)
+ // promises.push(promise)
+ // }
+ //
+ // await Promise.all(promises)
+ //
+ // assert.equal(true, false, "Unexpected result!")
+ // } catch (err) {
+ // //console.log(`err.response: ${util.inspect(err.response)}`)
+ //
+ // assert.equal(err.response.status, 429)
+ // assert.include(err.response.data.error, "Too many requests")
+ // }
+ // })
+
+ // it("should not trigger rate-limit handler if correct pro-tier password is used", async () => {
+ // try {
+ // const username = "BITBOX"
+ //
+ // // Pro-tier is accessed by using the right password.
+ // const password = "BITBOX"
+ // //const password = "something"
+ //
+ // const combined = `${username}:${password}`
+ // const base64Credential = Buffer.from(combined).toString("base64")
+ // const readyCredential = `Basic ${base64Credential}`
+ //
+ // const options = {
+ // method: "GET",
+ // url: `${SERVER}control/getNetworkInfo`,
+ // headers: { Authorization: readyCredential }
+ // }
+ //
+ // const promises = []
+ // for (let i = 0; i < 30; i++) {
+ // const promise = axios(options)
+ // promises.push(promise)
+ // }
+ //
+ // await Promise.all(promises)
+ //
+ // assert.equal(true, true, "Not throwing an error is a pass!")
+ // } catch (err) {
+ // // console.log(`err.response: ${util.inspect(err.response)}`)
+ //
+ // assert.equal(
+ // true,
+ // false,
+ // "This error handler should not have been triggered. Is the password correct?"
+ // )
+ // }
+ // })
+
+ // it("should trigger rate-limit handler if rate limits exceeds pro-tier limit", async () => {
+ // try {
+ // const username = "BITBOX"
+ //
+ // // Pro-tier is accessed by using the right password.
+ // const password = "BITBOX"
+ // //const password = "something"
+ //
+ // const combined = `${username}:${password}`
+ // const base64Credential = Buffer.from(combined).toString("base64")
+ // const readyCredential = `Basic ${base64Credential}`
+ //
+ // // Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
+ // const options = {
+ // method: "GET",
+ // url: `${SERVER}control/getNetworkInfo`,
+ // headers: { Authorization: readyCredential }
+ // }
+ //
+ // const promises = []
+ // for (let i = 0; i < 80; i++) {
+ // const promise = axios(options)
+ // promises.push(promise)
+ // }
+ //
+ // await Promise.all(promises)
+ //
+ // assert.equal(true, false, "Unexpected result!")
+ // } catch (err) {
+ // //console.log(`err.response: ${util.inspect(err.response)}`)
+ //
+ // assert.equal(err.response.status, 429)
+ // assert.include(err.response.data.error, "Too many requests")
+ // }
+ // })
+
+ it("should unlock pro-tier for a valid JWT token", async () => {
try {
// Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
- const options = {
- method: "GET",
- url: `${SERVER}control/getNetworkInfo`
- }
-
- const promises = []
- for (let i = 0; i < 30; i++) {
- const promise = axios(options)
- promises.push(promise)
- }
-
- await Promise.all(promises)
-
- assert.equal(true, false, "Unexpected result!")
- } catch (err) {
- //console.log(`err.response: ${util.inspect(err.response)}`)
-
- assert.equal(err.response.status, 429)
- assert.include(err.response.data.error, "Too many requests")
- }
- })
-
- it("should not trigger rate-limit handler if correct pro-tier password is used", async () => {
- try {
- const username = "BITBOX"
-
- // Pro-tier is accessed by using the right password.
- const password = "BITBOX"
- //const password = "something"
-
- const combined = `${username}:${password}`
- const base64Credential = Buffer.from(combined).toString("base64")
- const readyCredential = `Basic ${base64Credential}`
-
const options = {
method: "GET",
url: `${SERVER}control/getNetworkInfo`,
- headers: { Authorization: readyCredential }
+ headers: {
+ Authorization: `Token ${TEST_JWT}`
+ }
}
const promises = []
- for (let i = 0; i < 30; i++) {
+ for (let i = 0; i < 1; i++) {
const promise = axios(options)
promises.push(promise)
}
await Promise.all(promises)
+ //assert.equal(true, false, "Unexpected result!")
assert.equal(true, true, "Not throwing an error is a pass!")
} catch (err) {
- // console.log(`err.response: ${util.inspect(err.response)}`)
-
- assert.equal(
- true,
- false,
- "This error handler should not have been triggered. Is the password correct?"
- )
- }
- })
-
- it("should trigger rate-limit handler if rate limits exceeds pro-tier limit", async () => {
- try {
- const username = "BITBOX"
-
- // Pro-tier is accessed by using the right password.
- const password = "BITBOX"
- //const password = "something"
-
- const combined = `${username}:${password}`
- const base64Credential = Buffer.from(combined).toString("base64")
- const readyCredential = `Basic ${base64Credential}`
-
- // Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
- const options = {
- method: "GET",
- url: `${SERVER}control/getNetworkInfo`,
- headers: { Authorization: readyCredential }
- }
-
- const promises = []
- for (let i = 0; i < 80; i++) {
- const promise = axios(options)
- promises.push(promise)
- }
-
- await Promise.all(promises)
+ console.log(`err.response: ${util.inspect(err.response)}`)
assert.equal(true, false, "Unexpected result!")
- } catch (err) {
- //console.log(`err.response: ${util.inspect(err.response)}`)
-
- assert.equal(err.response.status, 429)
- assert.include(err.response.data.error, "Too many requests")
}
- })
+ // Override default timeout for this test.
+ }).timeout(20000)
})
From b9b5c52c40809cf8246de2e5c4382d584e3ce7b7 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Sun, 20 Oct 2019 11:59:25 -0700
Subject: [PATCH 02/49] Removed local auth lib and code. Not needed for JWT
---
package-lock.json | 137 +++++++----------------------------------
package.json | 1 -
src/middleware/auth.js | 35 -----------
3 files changed, 22 insertions(+), 151 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 794791d..6af3271 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2274,11 +2274,6 @@
"resolved": "https://registry.npmjs.org/buffer-compare/-/buffer-compare-1.1.1.tgz",
"integrity": "sha1-W+e+hTr4kZjR9N3AkNHWakiu9ZY="
},
- "buffer-equal-constant-time": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
- "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
- },
"buffer-equals": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/buffer-equals/-/buffer-equals-1.0.4.tgz",
@@ -3717,14 +3712,6 @@
"safer-buffer": "^2.1.0"
}
},
- "ecdsa-sig-formatter": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
- "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
- "requires": {
- "safe-buffer": "^5.0.1"
- }
- },
"ecurve": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/ecurve/-/ecurve-1.0.6.tgz",
@@ -4873,34 +4860,11 @@
"basic-auth": "^2.0.1"
}
},
- "express-jwt": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-5.3.1.tgz",
- "integrity": "sha512-1C9RNq0wMp/JvsH/qZMlg3SIPvKu14YkZ4YYv7gJQ1Vq+Dv8LH9tLKenS5vMNth45gTlEUGx+ycp9IHIlaHP/g==",
- "requires": {
- "async": "^1.5.0",
- "express-unless": "^0.3.0",
- "jsonwebtoken": "^8.1.0",
- "lodash.set": "^4.0.0"
- },
- "dependencies": {
- "async": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
- "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
- }
- }
- },
"express-rate-limit": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.0.0.tgz",
"integrity": "sha512-dhT57wqxfqmkOi4HM7NuT4Gd7gbUgSK2ocG27Y6lwm8lbOAw9XQfeANawGq8wLDtlGPO1ZgDj0HmKsykTxfFAg=="
},
- "express-unless": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-0.3.1.tgz",
- "integrity": "sha1-JVfBRudb65A+LSR/m1ugFFJpbiA="
- },
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -7345,30 +7309,6 @@
"resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
"integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA="
},
- "jsonwebtoken": {
- "version": "8.5.1",
- "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
- "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
- "requires": {
- "jws": "^3.2.2",
- "lodash.includes": "^4.3.0",
- "lodash.isboolean": "^3.0.3",
- "lodash.isinteger": "^4.0.4",
- "lodash.isnumber": "^3.0.3",
- "lodash.isplainobject": "^4.0.6",
- "lodash.isstring": "^4.0.1",
- "lodash.once": "^4.0.0",
- "ms": "^2.1.1",
- "semver": "^5.6.0"
- },
- "dependencies": {
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
- }
- }
- },
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@@ -7396,25 +7336,6 @@
"integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==",
"dev": true
},
- "jwa": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
- "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
- "requires": {
- "buffer-equal-constant-time": "1.0.1",
- "ecdsa-sig-formatter": "1.0.11",
- "safe-buffer": "^5.0.1"
- }
- },
- "jws": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
- "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
- "requires": {
- "jwa": "^1.4.1",
- "safe-buffer": "^5.0.1"
- }
- },
"keccak": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/keccak/-/keccak-1.4.0.tgz",
@@ -7644,56 +7565,34 @@
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
"dev": true
},
- "lodash.includes": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
- "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
- },
- "lodash.isboolean": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
- "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
- },
- "lodash.isinteger": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
- "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
- },
"lodash.ismatch": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz",
"integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=",
"dev": true
},
- "lodash.isnumber": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
- "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
- },
"lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
- "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
+ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=",
+ "dev": true
},
"lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
- "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
+ "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=",
+ "dev": true
},
"lodash.memoize": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
"integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8="
},
- "lodash.once": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
- "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
- },
"lodash.set": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
- "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM="
+ "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=",
+ "dev": true
},
"lodash.toarray": {
"version": "4.4.0",
@@ -12741,14 +12640,6 @@
"passport-strategy": "1.x.x"
}
},
- "passport-local": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
- "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=",
- "requires": {
- "passport-strategy": "1.x.x"
- }
- },
"passport-strategy": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
@@ -14138,6 +14029,14 @@
"touch": "^3.1.0"
},
"dependencies": {
+ "bchaddrjs-slp": {
+ "version": "git://github.com/simpleledger/bchaddrjs.git#ea05d679783a6737f2f99adc37ebf485dc64f006",
+ "from": "git://github.com/simpleledger/bchaddrjs.git#master",
+ "requires": {
+ "bs58check": "^2.1.2",
+ "cashaddrjs-slp": "^0.2.11"
+ }
+ },
"bignumber.js": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-8.1.1.tgz",
@@ -14196,6 +14095,14 @@
"is-buffer": "^2.0.2"
}
},
+ "bchaddrjs-slp": {
+ "version": "git://github.com/simpleledger/bchaddrjs.git#ea05d679783a6737f2f99adc37ebf485dc64f006",
+ "from": "git://github.com/simpleledger/bchaddrjs.git#master",
+ "requires": {
+ "bs58check": "^2.1.2",
+ "cashaddrjs-slp": "^0.2.11"
+ }
+ },
"bignumber.js": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-8.1.1.tgz",
diff --git a/package.json b/package.json
index d184714..29938dd 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,6 @@
"passport": "^0.4.0",
"passport-anonymous": "^1.0.1",
"passport-http": "^0.3.0",
- "passport-local": "^1.0.0",
"pg": "^7.11.0",
"pg-hstore": "^2.3.2",
"slp-sdk": "^4.4.1",
diff --git a/src/middleware/auth.js b/src/middleware/auth.js
index 86a9e1b..97ae4df 100644
--- a/src/middleware/auth.js
+++ b/src/middleware/auth.js
@@ -21,7 +21,6 @@
const passport = require("passport")
const BasicStrategy = require("passport-http").BasicStrategy
const AnonymousStrategy = require("passport-anonymous")
-const LocalStrategy = require("passport-local")
const wlogger = require("../util/winston-logging")
const axios = require("axios")
@@ -97,40 +96,6 @@ class AuthMW {
return done(null, true)
})
)
-
- // JWT token based authentication.
- passport.use(
- new LocalStrategy(
- {
- usernameField: "user[email]",
- passwordField: "user[password]",
- passReqToCallback: true,
- session: false
- },
- async (req, email, password, done) => {
- console.log(`Checking against local strategy.`)
-
- const userData = {}
- const isValid = true
-
- // Lookup the user from the database.
- // const userData = await userDB.findByEmail(email)
- //console.log(`userData: ${util.inspect(userDataRaw)}`)
-
- // Hash the password and see if it matches the saved hash.
- // const isValid = jwt.validatePassword(userData, password)
-
- if (isValid) {
- //console.log(`Passwords match!`)
- return done(null, userData)
- }
-
- return done(null, false, {
- errors: { "email or password": "is invalid" }
- })
- }
- )
- )
}
// Middleware called by the route.
From ccb0b3bfab0904f81228152116f5cb461bc7aa60 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Sun, 20 Oct 2019 12:33:16 -0700
Subject: [PATCH 03/49] Integrated remote JWT auth server
---
src/middleware/auth.js | 1 -
src/middleware/route-ratelimit.js | 44 ++++---
test/v3/integration/rate-limits.js | 198 ++++++++++++++---------------
3 files changed, 126 insertions(+), 117 deletions(-)
diff --git a/src/middleware/auth.js b/src/middleware/auth.js
index 97ae4df..682c23d 100644
--- a/src/middleware/auth.js
+++ b/src/middleware/auth.js
@@ -22,7 +22,6 @@ const passport = require("passport")
const BasicStrategy = require("passport-http").BasicStrategy
const AnonymousStrategy = require("passport-anonymous")
const wlogger = require("../util/winston-logging")
-const axios = require("axios")
// Used for debugging and iterrogating JS objects.
const util = require("util")
diff --git a/src/middleware/route-ratelimit.js b/src/middleware/route-ratelimit.js
index 70e2c20..a2d56ee 100644
--- a/src/middleware/route-ratelimit.js
+++ b/src/middleware/route-ratelimit.js
@@ -11,11 +11,12 @@
const express = require("express")
const RateLimit = require("express-rate-limit")
+const axios = require("axios")
// Set max requests per minute
const maxRequests = process.env.RATE_LIMIT_MAX_REQUESTS
? parseInt(process.env.RATE_LIMIT_MAX_REQUESTS)
- : 30
+ : 10
// Pro-tier rate limits are 10x the freemium limits.
const PRO_RPM = 10 * maxRequests
@@ -23,29 +24,38 @@ const PRO_RPM = 10 * maxRequests
// Unique route mapped to its rate limit
const uniqueRateLimits = {}
-const routeRateLimit = function(req, res, next) {
+const routeRateLimit = async function(req, res, next) {
// Disable rate limiting if 0 passed from RATE_LIMIT_MAX_REQUESTS
if (maxRequests === 0) return next()
// Create a res.locals object if not passed in.
if (!req.locals) req.locals = {}
- if (req.locals.jwtToken)
- console.log(`req.locals.jwtToken: ${req.locals.jwtToken}`)
+ // Warn if JWT_AUTH_SERVER env var is not set.
+ const authServer = process.env.JWT_AUTH_SERVER
+ if (!authServer || authServer === "") {
+ console.warn(
+ "JWT_AUTH_SERVER env var is not set. JWT tokens not being evaluated."
+ )
+ } else {
+ // If a JWT token is passed in, validate it and enable pro-tier rate limits
+ // if it's valid.
+ if (req.locals.jwtToken) {
+ // console.log(`req.locals.jwtToken: ${req.locals.jwtToken}`)
- // If no JWT token was provided, skip
- if (req.payload)
- console.log(`req.payload: ${JSON.stringify(req.payload, null, 2)}`)
- // // Unlock the pro-tier rate limits if the user passed in a valid JWT token.
- // if (!proRateLimits) {
- // const user = await getUserFromJWT(req)
- //
- // // Enable pro-tier rate limits for this user.
- // if(user) {
- // console.log(`${user.email} (${user.id}) passed in valid JWT`)
- // proRateLimits = true
- // }
- // }
+ const path = `${authServer}apitoken/isvalid/${req.locals.jwtToken}`
+
+ let isValidJwt = await axios.get(path)
+ isValidJwt = isValidJwt.data
+ // console.log(`isValidJwt: ${JSON.stringify(isValidJwt, null, 2)}`)
+
+ // Enable pro-tier rate limits if JWT if valid.
+ if (isValidJwt) {
+ // console.log(`JWT is valid. Enabling pro-tier rate limits.`)
+ req.locals.proLimit = true
+ }
+ }
+ }
// Current route
const rateLimitTier = req.locals.proLimit ? "PRO" : "BASIC"
diff --git a/test/v3/integration/rate-limits.js b/test/v3/integration/rate-limits.js
index 3a71efa..99ba139 100644
--- a/test/v3/integration/rate-limits.js
+++ b/test/v3/integration/rate-limits.js
@@ -29,124 +29,124 @@ describe("#rate limits", () => {
const result = await axios(options)
//console.log(`result.status: ${result.status}`)
- //console.log(`result.data: ${util.inspect(result.data)}`)
+ // console.log(`result.data: ${util.inspect(result.data)}`)
assert.equal(result.status, 200)
assert.hasAnyKeys(result.data, ["version"])
})
- // it("should trigger rate-limit handler if rate limits exceeds 30 request per minute", async () => {
- // try {
- // // Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
- // const options = {
- // method: "GET",
- // url: `${SERVER}control/getNetworkInfo`
- // }
- //
- // const promises = []
- // for (let i = 0; i < 30; i++) {
- // const promise = axios(options)
- // promises.push(promise)
- // }
- //
- // await Promise.all(promises)
- //
- // assert.equal(true, false, "Unexpected result!")
- // } catch (err) {
- // //console.log(`err.response: ${util.inspect(err.response)}`)
- //
- // assert.equal(err.response.status, 429)
- // assert.include(err.response.data.error, "Too many requests")
- // }
- // })
+ it("should trigger rate-limit handler if rate limits exceeds 30 request per minute", async () => {
+ try {
+ // Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
+ const options = {
+ method: "GET",
+ url: `${SERVER}control/getNetworkInfo`
+ }
- // it("should not trigger rate-limit handler if correct pro-tier password is used", async () => {
- // try {
- // const username = "BITBOX"
- //
- // // Pro-tier is accessed by using the right password.
- // const password = "BITBOX"
- // //const password = "something"
- //
- // const combined = `${username}:${password}`
- // const base64Credential = Buffer.from(combined).toString("base64")
- // const readyCredential = `Basic ${base64Credential}`
- //
- // const options = {
- // method: "GET",
- // url: `${SERVER}control/getNetworkInfo`,
- // headers: { Authorization: readyCredential }
- // }
- //
- // const promises = []
- // for (let i = 0; i < 30; i++) {
- // const promise = axios(options)
- // promises.push(promise)
- // }
- //
- // await Promise.all(promises)
- //
- // assert.equal(true, true, "Not throwing an error is a pass!")
- // } catch (err) {
- // // console.log(`err.response: ${util.inspect(err.response)}`)
- //
- // assert.equal(
- // true,
- // false,
- // "This error handler should not have been triggered. Is the password correct?"
- // )
- // }
- // })
+ const promises = []
+ for (let i = 0; i < 30; i++) {
+ const promise = axios(options)
+ promises.push(promise)
+ }
- // it("should trigger rate-limit handler if rate limits exceeds pro-tier limit", async () => {
- // try {
- // const username = "BITBOX"
- //
- // // Pro-tier is accessed by using the right password.
- // const password = "BITBOX"
- // //const password = "something"
- //
- // const combined = `${username}:${password}`
- // const base64Credential = Buffer.from(combined).toString("base64")
- // const readyCredential = `Basic ${base64Credential}`
- //
- // // Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
- // const options = {
- // method: "GET",
- // url: `${SERVER}control/getNetworkInfo`,
- // headers: { Authorization: readyCredential }
- // }
- //
- // const promises = []
- // for (let i = 0; i < 80; i++) {
- // const promise = axios(options)
- // promises.push(promise)
- // }
- //
- // await Promise.all(promises)
- //
- // assert.equal(true, false, "Unexpected result!")
- // } catch (err) {
- // //console.log(`err.response: ${util.inspect(err.response)}`)
- //
- // assert.equal(err.response.status, 429)
- // assert.include(err.response.data.error, "Too many requests")
- // }
- // })
+ await Promise.all(promises)
+
+ assert.equal(true, false, "Unexpected result!")
+ } catch (err) {
+ //console.log(`err.response: ${util.inspect(err.response)}`)
+
+ assert.equal(err.response.status, 429)
+ assert.include(err.response.data.error, "Too many requests")
+ }
+ })
+
+ it("should not trigger rate-limit handler if correct pro-tier password is used", async () => {
+ try {
+ const username = "BITBOX"
+
+ // Pro-tier is accessed by using the right password.
+ const password = "BITBOX"
+ //const password = "something"
+
+ const combined = `${username}:${password}`
+ const base64Credential = Buffer.from(combined).toString("base64")
+ const readyCredential = `Basic ${base64Credential}`
+
+ const options = {
+ method: "GET",
+ url: `${SERVER}control/getNetworkInfo`,
+ headers: { Authorization: readyCredential }
+ }
+
+ const promises = []
+ for (let i = 0; i < 30; i++) {
+ const promise = axios(options)
+ promises.push(promise)
+ }
+
+ await Promise.all(promises)
+
+ assert.equal(true, true, "Not throwing an error is a pass!")
+ } catch (err) {
+ // console.log(`err.response: ${util.inspect(err.response)}`)
+
+ assert.equal(
+ true,
+ false,
+ "This error handler should not have been triggered. Is the password correct?"
+ )
+ }
+ })
+
+ it("should trigger rate-limit handler if rate limits exceeds pro-tier limit", async () => {
+ try {
+ const username = "BITBOX"
+
+ // Pro-tier is accessed by using the right password.
+ const password = "BITBOX"
+ //const password = "something"
+
+ const combined = `${username}:${password}`
+ const base64Credential = Buffer.from(combined).toString("base64")
+ const readyCredential = `Basic ${base64Credential}`
+
+ // Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
+ const options = {
+ method: "GET",
+ url: `${SERVER}control/getNetworkInfo`,
+ headers: { Authorization: readyCredential }
+ }
+
+ const promises = []
+ for (let i = 0; i < 80; i++) {
+ const promise = axios(options)
+ promises.push(promise)
+ }
+
+ await Promise.all(promises)
+
+ assert.equal(true, false, "Unexpected result!")
+ } catch (err) {
+ //console.log(`err.response: ${util.inspect(err.response)}`)
+
+ assert.equal(err.response.status, 429)
+ assert.include(err.response.data.error, "Too many requests")
+ }
+ })
it("should unlock pro-tier for a valid JWT token", async () => {
try {
// Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
const options = {
method: "GET",
- url: `${SERVER}control/getNetworkInfo`,
+ url: `${SERVER}control/`,
headers: {
Authorization: `Token ${TEST_JWT}`
}
}
const promises = []
- for (let i = 0; i < 1; i++) {
+ for (let i = 0; i < 60; i++) {
const promise = axios(options)
promises.push(promise)
}
From 41d048f6a5f7f099c1d0481bbd048db68abeb0a5 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Thu, 31 Oct 2019 13:21:59 -0700
Subject: [PATCH 04/49] fix(apiLevel): passing apiLevel is req.locals
---
src/middleware/auth.js | 20 ++++-------
src/middleware/jwt-auth.js | 9 +++--
src/middleware/route-ratelimit.js | 18 +++++++---
src/routes/v3/control.js | 55 ++-----------------------------
4 files changed, 29 insertions(+), 73 deletions(-)
diff --git a/src/middleware/auth.js b/src/middleware/auth.js
index 682c23d..307a583 100644
--- a/src/middleware/auth.js
+++ b/src/middleware/auth.js
@@ -42,18 +42,6 @@ class AuthMW {
_this = this
// Initialize passport for 'anonymous' authentication.
- /*
- passport.use(
- new AnonymousStrategy({ passReqToCallback: true }, function(
- req,
- username,
- password,
- done
- ) {
- console.log(`anonymous auth handler triggered.`)
- })
- )
- */
passport.use(new AnonymousStrategy())
// Initialize passport for 'basic' authentication.
@@ -69,7 +57,13 @@ class AuthMW {
//console.log(`password: ${password}`)
// Create the req.locals property if it does not yet exist.
- if (!req.locals) req.locals = {}
+ if (!req.locals) {
+ req.locals = {
+ // default values
+ proLimit: false,
+ apiLevel: 0
+ }
+ }
// Set pro-tier rate limit to flag to false by default.
req.locals.proLimit = false
diff --git a/src/middleware/jwt-auth.js b/src/middleware/jwt-auth.js
index 485e7fa..b006035 100644
--- a/src/middleware/jwt-auth.js
+++ b/src/middleware/jwt-auth.js
@@ -25,8 +25,13 @@ const getTokenFromHeaders = (req, res, next) => {
// console.log(`JWT found: ${token}`)
// Create the req.locals property if it does not yet exist.
- if (!req.locals) req.locals = {}
- req.locals.jwtToken = token
+ if (!req.locals) {
+ req.locals = {
+ jwtToken: token,
+ proLimit: false,
+ apiLevel: 0
+ }
+ }
}
}
} catch (err) {
diff --git a/src/middleware/route-ratelimit.js b/src/middleware/route-ratelimit.js
index a2d56ee..5bc6886 100644
--- a/src/middleware/route-ratelimit.js
+++ b/src/middleware/route-ratelimit.js
@@ -29,7 +29,14 @@ const routeRateLimit = async function(req, res, next) {
if (maxRequests === 0) return next()
// Create a res.locals object if not passed in.
- if (!req.locals) req.locals = {}
+ if (!req.locals) {
+ req.locals = {
+ // default values
+ jwtToken: "",
+ proLimit: false,
+ apiLevel: 0
+ }
+ }
// Warn if JWT_AUTH_SERVER env var is not set.
const authServer = process.env.JWT_AUTH_SERVER
@@ -45,14 +52,15 @@ const routeRateLimit = async function(req, res, next) {
const path = `${authServer}apitoken/isvalid/${req.locals.jwtToken}`
- let isValidJwt = await axios.get(path)
- isValidJwt = isValidJwt.data
- // console.log(`isValidJwt: ${JSON.stringify(isValidJwt, null, 2)}`)
+ let jwtInfo = await axios.get(path)
+ jwtInfo = jwtInfo.data
+ // console.log(`jwtInfo: ${JSON.stringify(jwtInfo, null, 2)}`)
// Enable pro-tier rate limits if JWT if valid.
- if (isValidJwt) {
+ if (jwtInfo.isValid) {
// console.log(`JWT is valid. Enabling pro-tier rate limits.`)
req.locals.proLimit = true
+ req.locals.apiLevel = jwtInfo.apiLevel
}
}
}
diff --git a/src/routes/v3/control.js b/src/routes/v3/control.js
index da6eb78..6a3f6ee 100644
--- a/src/routes/v3/control.js
+++ b/src/routes/v3/control.js
@@ -12,64 +12,12 @@ const util = require("util")
util.inspect.defaultOptions = { depth: 1 }
router.get("/", root)
-router.get("/getinfo", getInfo)
router.get("/getnetworkinfo", getNetworkInfo)
function root(req, res, next) {
return res.json({ status: "control" })
}
-/**
- * @api {get} /control/getinfo Get full node info
- * @apiName GetInfo
- * @apiGroup Control
- * @apiDescription RPC call which gets basic full node information.
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/control/getinfo" -H "accept: application/json"
- *
- * @apiSuccess {Object} object Object containing data
- * @apiSuccess {Number} object.version Full node version
- * @apiSuccess {Number} object.protocolversion Protocol version
- * @apiSuccess {Number} object.blocks Current block
- * @apiSuccess {Number} object.timeoffset ?
- * @apiSuccess {Number} object.connections Number of connected peers
- * @apiSuccess {String} object.proxy ?
- * @apiSuccess {Number} object.difficulty Current difficulty setting
- * @apiSuccess {Boolean} object.testnet testnet = true, mainnet = false
- * @apiSuccess {Number} object.paytxfee ?
- * @apiSuccess {Number} object.relayfee ?
- * @apiSuccess {String} object.errors Recent errors
- */
-async function getInfo(req, res, next) {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getinfo"
- requestConfig.data.method = "getinfo"
- requestConfig.data.params = []
-
- try {
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (error) {
- wlogger.error(`Error in control.ts/getInfo().`, error)
-
- // Write out error to error log.
- //logger.error(`Error in control/getInfo: `, error)
-
- res.status(500)
- if (error.response && error.response.data && error.response.data.error)
- return res.json({ error: error.response.data.error })
- return res.json({ error: util.inspect(error) })
- }
-}
-
/**
* @api {get} /control/getnetworkinfo Get Network Info
* @apiName GetNetworkInfo
@@ -88,6 +36,8 @@ async function getNetworkInfo(req, res, next) {
requestConfig
} = routeUtils.setEnvVars()
+ console.log(`req.locals: ${JSON.stringify(req.locals, null, 2)}`)
+
requestConfig.data.id = "getnetworkinfo"
requestConfig.data.method = "getnetworkinfo"
requestConfig.data.params = []
@@ -150,7 +100,6 @@ module.exports = {
router,
testableComponents: {
root,
- getInfo,
getNetworkInfo
}
}
From 17525a40d5a4bede156cb85c15e6f44973d1c7fa Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Thu, 31 Oct 2019 14:15:53 -0700
Subject: [PATCH 05/49] feat(rate-limit tiers): Created finer-resolution rate
limits + unit tests
---
src/middleware/route-ratelimit.js | 18 +++++---
test/v3/rate-limits.js | 73 +++++++++++++++++++++++++------
2 files changed, 72 insertions(+), 19 deletions(-)
diff --git a/src/middleware/route-ratelimit.js b/src/middleware/route-ratelimit.js
index 5bc6886..2bb2c2b 100644
--- a/src/middleware/route-ratelimit.js
+++ b/src/middleware/route-ratelimit.js
@@ -1,10 +1,13 @@
/*
This file controls the request-per-minute (RPM) rate limits.
- It is assumed that this middleware is run AFTER the auth.js middleware which
- checks for Basic auth. If the user adds the correct Basic auth to the header
- of their API request, they will get pro-tier rate limits. By default, the
- freemium rate limits apply.
+ It is assumed that this middleware is run AFTER the jwt-auth.js and auth.js
+ middleware.
+
+ Current rate limiting rules in requests-per-minute:
+ - anonymous access: 3
+ - free access: 10
+ - any paid tier: 100
*/
"use strict"
@@ -16,10 +19,10 @@ const axios = require("axios")
// Set max requests per minute
const maxRequests = process.env.RATE_LIMIT_MAX_REQUESTS
? parseInt(process.env.RATE_LIMIT_MAX_REQUESTS)
- : 10
+ : 3
// Pro-tier rate limits are 10x the freemium limits.
-const PRO_RPM = 10 * maxRequests
+// const PRO_RPM = 10 * maxRequests
// Unique route mapped to its rate limit
const uniqueRateLimits = {}
@@ -87,6 +90,9 @@ const routeRateLimit = async function(req, res, next) {
// TODO: replace the console.logs with calls to our logging system.
//console.log(`applying pro-rate limits`)
+ let PRO_RPM = 10 // Default value for free tier
+ if (req.locals.apiLevel > 0) PRO_RPM = 100 // RPM for paid tiers.
+
// Create new RateLimit if none exists for this route
if (!uniqueRateLimits[route]) {
uniqueRateLimits[route] = new RateLimit({
diff --git a/test/v3/rate-limits.js b/test/v3/rate-limits.js
index 4459e4a..3b2db1f 100644
--- a/test/v3/rate-limits.js
+++ b/test/v3/rate-limits.js
@@ -62,12 +62,67 @@ describe("#route-ratelimits", () => {
assert.equal(next.called, true)
})
- it("should trigger rate-limit handler if rate limits exceeds 25 request per minute", async () => {
+ it("should trigger rate-limit handler if rate limits exceeds 5 request per minute", async () => {
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.method = "GET"
- for (let i = 0; i < 35; i++) {
+ for (let i = 0; i < 5; i++) {
+ next.reset() // reset the stubbed next() function.
+
+ await routeRateLimit(req, res, next)
+ //console.log(`next() called: ${next.called}`)
+ }
+
+ // Note: next() will be called unless the rate-limit kicks in.
+ assert.equal(
+ next.called,
+ false,
+ `next should not be called if rate limit was triggered.`
+ )
+ })
+
+ it("should NOT trigger rate-limit for free-tier at 5 RPM", async () => {
+ // Clear the require cache before running this test.
+ delete require.cache[
+ require.resolve("../../src/middleware/route-ratelimit")
+ ]
+ rateLimitMiddleware = require("../../src/middleware/route-ratelimit")
+ routeRateLimit = rateLimitMiddleware.routeRateLimit
+
+ req.baseUrl = "/v3"
+ req.path = "/control/getNetworkInfo"
+ req.method = "GET"
+
+ req.locals.proLimit = true
+ req.locals.apiLevel = 0
+
+ for (let i = 0; i < 5; i++) {
+ next.reset() // reset the stubbed next() function.
+
+ await routeRateLimit(req, res, next)
+ //console.log(`next() called: ${next.called}`)
+ }
+
+ //console.log(`req.locals after test: ${util.inspect(req.locals)}`)
+
+ // Note: next() will be called unless the rate-limit kicks in.
+ assert.equal(
+ next.called,
+ true,
+ `next should be called if rate limit was not triggered.`
+ )
+ })
+
+ it("should trigger rate-limit for free tier 10 RPM", async () => {
+ req.baseUrl = "/v3"
+ req.path = "/control/getNetworkInfo"
+ req.method = "GET"
+
+ req.locals.proLimit = true
+ req.locals.apiLevel = 0
+
+ for (let i = 0; i < 12; i++) {
next.reset() // reset the stubbed next() function.
await routeRateLimit(req, res, next)
@@ -95,11 +150,7 @@ describe("#route-ratelimits", () => {
req.method = "GET"
req.locals.proLimit = true
-
- //console.log(`req.locals before test: ${util.inspect(req.locals)}`)
-
- // Prepare the authorization header
- //req.headers.authorization = generateAuthHeader("BITBOX")
+ req.locals.apiLevel = 10
for (let i = 0; i < 25; i++) {
next.reset() // reset the stubbed next() function.
@@ -131,13 +182,9 @@ describe("#route-ratelimits", () => {
req.method = "GET"
req.locals.proLimit = true
+ req.locals.apiLevel = 10
- //console.log(`req.locals before test: ${util.inspect(req.locals)}`)
-
- // Prepare the authorization header
- //req.headers.authorization = generateAuthHeader("BITBOX")
-
- for (let i = 0; i < 400; i++) {
+ for (let i = 0; i < 150; i++) {
next.reset() // reset the stubbed next() function.
await routeRateLimit(req, res, next)
From f74b33cf9b3d0cb68635c659a8792fdb95a0e9ce Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Thu, 31 Oct 2019 14:19:22 -0700
Subject: [PATCH 06/49] feat(no v2): Removing v2 routes
---
src/app.js | 45 +-
src/routes/v2/address.js | 805 --------------
src/routes/v2/block.js | 280 -----
src/routes/v2/blockchain.js | 890 ---------------
src/routes/v2/control.js | 95 --
src/routes/v2/generating.js | 51 -
src/routes/v2/health-check.js | 11 -
src/routes/v2/index.js | 15 -
src/routes/v2/logging.js | 51 -
src/routes/v2/mining.js | 170 ---
src/routes/v2/network.js | 168 ---
src/routes/v2/rawtransactions.js | 609 -----------
src/routes/v2/route-utils.js | 139 ---
src/routes/v2/services/bitbox.js | 11 -
src/routes/v2/services/requestUtils.js | 20 -
src/routes/v2/slp.js | 1369 ------------------------
src/routes/v2/transaction.js | 188 ----
src/routes/v2/util.js | 173 ---
18 files changed, 2 insertions(+), 5088 deletions(-)
delete mode 100644 src/routes/v2/address.js
delete mode 100644 src/routes/v2/block.js
delete mode 100644 src/routes/v2/blockchain.js
delete mode 100644 src/routes/v2/control.js
delete mode 100644 src/routes/v2/generating.js
delete mode 100644 src/routes/v2/health-check.js
delete mode 100644 src/routes/v2/index.js
delete mode 100644 src/routes/v2/logging.js
delete mode 100644 src/routes/v2/mining.js
delete mode 100644 src/routes/v2/network.js
delete mode 100644 src/routes/v2/rawtransactions.js
delete mode 100644 src/routes/v2/route-utils.js
delete mode 100644 src/routes/v2/services/bitbox.js
delete mode 100644 src/routes/v2/services/requestUtils.js
delete mode 100644 src/routes/v2/slp.js
delete mode 100644 src/routes/v2/transaction.js
delete mode 100644 src/routes/v2/util.js
diff --git a/src/app.js b/src/app.js
index f487d8d..f9114df 100644
--- a/src/app.js
+++ b/src/app.js
@@ -20,21 +20,6 @@ const cors = require("cors")
const AuthMW = require("./middleware/auth")
const jwtAuth = require("./middleware/jwt-auth")
-// v2
-const indexV2 = require("./routes/v2/index")
-const healthCheckV2 = require("./routes/v2/health-check")
-const addressV2 = require("./routes/v2/address")
-const blockV2 = require("./routes/v2/block")
-const blockchainV2 = require("./routes/v2/blockchain")
-const controlV2 = require("./routes/v2/control")
-const generatingV2 = require("./routes/v2/generating")
-const miningV2 = require("./routes/v2/mining")
-const networkV2 = require("./routes/v2/network")
-const rawtransactionsV2 = require("./routes/v2/rawtransactions")
-const transactionV2 = require("./routes/v2/transaction")
-const utilV2 = require("./routes/v2/util")
-const slpV2 = require("./routes/v2/slp")
-
// v3
const healthCheckV3 = require("./routes/v3/health-check")
const blockchainV3 = require("./routes/v3/blockchain")
@@ -78,17 +63,7 @@ app.use(bodyParser.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(express.static(path.join(__dirname, "public")))
-//
-// let username = process.env.USERNAME;
-// let password = process.env.PASSWORD;
-//
-// app.use(basicAuth(
-// {
-// users: { username: password }
-// }
-// ));
-
-const v2prefix = "v2"
+// const v2prefix = "v2"
const v3prefix = "v3"
// Inspect the header for a JWT token.
@@ -96,25 +71,9 @@ app.use(`/${v3prefix}/`, jwtAuth.getTokenFromHeaders)
// Instantiate the authorization middleware, used to implement pro-tier rate limiting.
const auth = new AuthMW()
-app.use(`/${v2prefix}/`, auth.mw())
+// app.use(`/${v2prefix}/`, auth.mw())
app.use(`/${v3prefix}/`, auth.mw())
-// Rate limit on all v2 routes
-app.use(`/${v2prefix}/`, routeRateLimit)
-app.use("/", indexV2)
-app.use(`/${v2prefix}/` + `health-check`, healthCheckV2)
-app.use(`/${v2prefix}/` + `address`, addressV2.router)
-app.use(`/${v2prefix}/` + `blockchain`, blockchainV2.router)
-app.use(`/${v2prefix}/` + `block`, blockV2.router)
-app.use(`/${v2prefix}/` + `control`, controlV2.router)
-app.use(`/${v2prefix}/` + `generating`, generatingV2)
-app.use(`/${v2prefix}/` + `mining`, miningV2.router)
-app.use(`/${v2prefix}/` + `network`, networkV2)
-app.use(`/${v2prefix}/` + `rawtransactions`, rawtransactionsV2.router)
-app.use(`/${v2prefix}/` + `transaction`, transactionV2.router)
-app.use(`/${v2prefix}/` + `util`, utilV2.router)
-app.use(`/${v2prefix}/` + `slp`, slpV2.router)
-
// Rate limit on all v3 routes
app.use(`/${v3prefix}/`, routeRateLimit)
app.use(`/${v3prefix}/` + `health-check`, healthCheckV3)
diff --git a/src/routes/v2/address.js b/src/routes/v2/address.js
deleted file mode 100644
index 0ae8d9e..0000000
--- a/src/routes/v2/address.js
+++ /dev/null
@@ -1,805 +0,0 @@
-/*
- Address route
-*/
-
-"use strict"
-
-const express = require("express")
-const requestUtils = require("./services/requestUtils")
-const axios = require("axios")
-const logger = require("./logging.js")
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
-
-//const router = express.Router()
-const router = express.Router()
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BITBOXJS = require("@chris.troutner/bch-js")
-const BITBOX = new BITBOXJS()
-
-// Use the default (and max) page size of 1000
-// https://github.com/bitpay/insight-api#notes-on-upgrading-from-v03
-const PAGE_SIZE = 1000
-
-// Connect the route endpoints to their handler functions.
-router.get("/", root)
-router.get("/details/:address", detailsSingle)
-router.post("/details", detailsBulk)
-router.post("/utxo", utxoBulk)
-router.get("/utxo/:address", utxoSingle)
-router.post("/unconfirmed", unconfirmedBulk)
-router.get("/unconfirmed/:address", unconfirmedSingle)
-router.get("/transactions/:address", transactionsSingle)
-router.post("/transactions", transactionsBulk)
-router.get("/fromXPub/:xpub", fromXPubSingle)
-
-// Root API endpoint. Simply acknowledges that it exists.
-function root(req, res, next) {
- return res.json({ status: "address" })
-}
-
-// Query the Insight API for details on a single BCH address.
-// Returns a Promise.
-async function detailsFromInsight(thisAddress, currentPage = 0) {
- try {
- let addr
- if (
- process.env.BITCOINCOM_BASEURL === "https://bch-insight.bitpay.com/api/"
- )
- addr = BITBOX.Address.toCashAddress(thisAddress)
- else addr = BITBOX.Address.toLegacyAddress(thisAddress)
-
- let path = `${process.env.BITCOINCOM_BASEURL}addr/${addr}`
-
- // Set from and to params based on currentPage and pageSize
- // https://github.com/bitpay/insight-api/blob/master/README.md#notes-on-upgrading-from-v02
- const from = currentPage * PAGE_SIZE
- const to = from + PAGE_SIZE
- path = `${path}?from=${from}&to=${to}`
-
- // Query the Insight server.
- const axiosResponse = await axios.get(path)
- const retData = axiosResponse.data
- //console.log(`retData: ${util.inspect(retData)}`)
-
- // Calculate pagesTotal from response
- const pagesTotal = Math.ceil(retData.txApperances / PAGE_SIZE)
-
- // Append different address formats to the return data.
- retData.legacyAddress = BITBOX.Address.toLegacyAddress(retData.addrStr)
- retData.cashAddress = BITBOX.Address.toCashAddress(retData.addrStr)
- delete retData.addrStr
-
- // Append pagination information to the return data.
- retData.currentPage = currentPage
- retData.pagesTotal = pagesTotal
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-// POST handler for bulk queries on address details
-// curl -d '{"addresses": ["bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr", "bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"]}' -H "Content-Type: application/json" http://localhost:3000/v2/address/details
-// curl -d '{"addresses": ["bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr", "bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"], "from": 1, "to": 5}' -H "Content-Type: application/json" http://localhost:3000/v2/address/details
-async function detailsBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
- const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
-
- // Reject if addresses is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({
- error: "addresses needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- logger.debug(`Executing address/details with these addresses: `, addresses)
- wlogger.debug(`Executing address/details with these addresses: `, addresses)
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- BITBOX.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Loops through each address and creates an array of Promises, querying
- // Insight API in parallel.
- addresses = addresses.map(async (address, index) =>
- detailsFromInsight(address, currentPage)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- //logger.error(`Error in detailsBulk(): `, err)
- wlogger.error(`Error in address.ts/detailsBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler for single address details
-async function detailsSingle(req, res, next) {
- try {
- const address = req.params.address
- const currentPage = req.query.page ? parseInt(req.query.page, 10) : 0
-
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- logger.debug(`Executing address/detailsSingle with this address: `, address)
- wlogger.debug(
- `Executing address/detailsSingle with this address: `,
- address
- )
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = BITBOX.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await detailsFromInsight(address, currentPage)
-
- // Return the retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in address.ts/detailsSingle: `, err)
- wlogger.error(`Error in address.ts/detailsSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Retrieve UTXO data from the Insight API
-async function utxoFromInsight(thisAddress) {
- try {
- let addr
- if (
- process.env.BITCOINCOM_BASEURL === "https://bch-insight.bitpay.com/api/"
- )
- addr = BITBOX.Address.toCashAddress(thisAddress)
- else addr = BITBOX.Address.toLegacyAddress(thisAddress)
-
- const path = `${process.env.BITCOINCOM_BASEURL}addr/${addr}/utxo`
-
- // Query the Insight server.
- const response = await axios.get(path)
-
- // Append different address formats to the return data.
- const retData = {
- utxos: Array,
- legacyAddress: String,
- cashAddress: String,
- scriptPubKey: String
- }
- if (response.data.length && response.data[0].scriptPubKey) {
- const spk = response.data[0].scriptPubKey
- retData.scriptPubKey = spk
- }
- retData.legacyAddress = BITBOX.Address.toLegacyAddress(thisAddress)
- retData.cashAddress = BITBOX.Address.toCashAddress(thisAddress)
- retData.utxos = response.data.map(utxo => {
- delete utxo.address
- delete utxo.scriptPubKey
- return utxo
- })
- //console.log(`utxoFromInsight retData: ${util.inspect(retData)}`)
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-// Retrieve UTXO information for an address.
-async function utxoBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
-
- // Reject if address is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({ error: "addresses needs to be an array" })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- BITBOX.Address.toLegacyAddress(thisAddress)
- } catch (er) {
- //if (er.message.includes("Unsupported address format"))
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- logger.debug(`Executing address/utxoBulk with these addresses: `, addresses)
- wlogger.debug(
- `Executing address/utxoBulk with these addresses: `,
- addresses
- )
-
- // Loops through each address and creates an array of Promises, querying
- // Insight API in parallel.
- addresses = addresses.map(async (address, index) =>
- utxoFromInsight(address)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/utxoBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler for single address details
-async function utxoSingle(req, res, next) {
- try {
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- logger.debug(`Executing address/utxoSingle with this address: `, address)
- wlogger.debug(`Executing address/utxoSingle with this address: `, address)
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = BITBOX.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await utxoFromInsight(address)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/utxoSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Retrieve any unconfirmed TX information for a given address.
-async function unconfirmedBulk(req, res, next) {
- try {
- const addresses = req.body.addresses
-
- // Reject if address is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({ error: "addresses needs to be an array" })
- }
-
- logger.debug(`Executing address/utxo with these addresses: `, addresses)
- wlogger.debug(`Executing address/utxo with these addresses: `, addresses)
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- BITBOX.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Collect an array of promises.
- const promises = addresses.map(address => utxoFromInsight(address))
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(promises)
-
- // Loop through each result
- const finalResult = result.map(elem => {
- //console.log(`elem: ${util.inspect(elem)}`)
-
- // Filter out confirmed transactions.
- const unconfirmedUtxos = elem.utxos.filter(
- utxo => utxo.confirmations === 0
- )
-
- elem.utxos = unconfirmedUtxos
-
- return elem
- })
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(finalResult)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/unconfirmedBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler. Retrieve any unconfirmed TX information for a given address.
-async function unconfirmedSingle(req, res, next) {
- try {
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- logger.debug(`Executing address/utxoSingle with this address: `, address)
- wlogger.debug(`Executing address/utxoSingle with this address: `, address)
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = BITBOX.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await utxoFromInsight(address)
- //console.log(`retData: ${JSON.stringify(retData,null,2)}`)
-
- // Loop through each returned UTXO.
- const unconfirmedUTXOs = []
- for (let j = 0; j < retData.utxos.length; j++) {
- const thisUtxo = retData.utxos[j]
-
- // Only interested in UTXOs with no confirmations.
- if (thisUtxo.confirmations === 0) unconfirmedUTXOs.push(thisUtxo)
- }
-
- retData.utxos = unconfirmedUTXOs
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/unconfirmedSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Retrieve transaction data from the Insight API
-async function transactionsFromInsight(thisAddress, currentPage = 0) {
- try {
- const path = `${process.env.BITCOINCOM_BASEURL}txs/?address=${thisAddress}&pageNum=${currentPage}`
-
- // Query the Insight server.
- const response = await axios.get(path)
-
- // Append different address formats to the return data.
- const retData = response.data
- retData.legacyAddress = BITBOX.Address.toLegacyAddress(thisAddress)
- retData.cashAddress = BITBOX.Address.toCashAddress(thisAddress)
- retData.currentPage = currentPage
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-// Get an array of TX information for a given address.
-async function transactionsBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
- const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
-
- // Reject if address is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({ error: "addresses needs to be an array" })
- }
-
- logger.debug(`Executing address/utxo with these addresses: `, addresses)
- wlogger.debug(`Executing address/utxo with these addresses: `, addresses)
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- BITBOX.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Loop through each address and collect an array of promises.
- addresses = addresses.map(async (address, index) =>
- transactionsFromInsight(address, currentPage)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/transactionsBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler. Retrieve any unconfirmed TX information for a given address.
-async function transactionsSingle(req, res, next) {
- try {
- const address = req.params.address
- const currentPage = req.query.page ? parseInt(req.query.page, 10) : 0
-
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- logger.debug(
- `Executing address/transactionsSingle with this address: `,
- address
- )
- wlogger.debug(
- `Executing address/transactionsSingle with this address: `,
- address
- )
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = BITBOX.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await transactionsFromInsight(address, currentPage)
- //console.log(`retData: ${JSON.stringify(retData,null,2)}`)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/transactionsSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function fromXPubSingle(req, res, next) {
- try {
- const xpub = req.params.xpub
- const hdPath = req.query.hdPath ? req.query.hdPath : "0"
-
- if (!xpub || xpub === "") {
- res.status(400)
- return res.json({ error: "xpub can not be empty" })
- }
-
- // Reject if xpub is an array.
- if (Array.isArray(xpub)) {
- res.status(400)
- return res.json({
- error: "xpub can not be an array. Use POST for bulk upload."
- })
- }
-
- logger.debug(`Executing address/fromXPub with this xpub: `, xpub)
- wlogger.debug(`Executing address/fromXPub with this xpub: `, xpub)
-
- const cashAddr = BITBOX.Address.fromXPub(xpub, hdPath)
- const legacyAddr = BITBOX.Address.toLegacyAddress(cashAddr)
- res.status(200)
- return res.json({
- cashAddress: cashAddr,
- legacyAddress: legacyAddr
- })
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/fromXPubSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- detailsBulk,
- detailsSingle,
- utxoBulk,
- utxoSingle,
- unconfirmedBulk,
- unconfirmedSingle,
- transactionsBulk,
- transactionsSingle,
- fromXPubSingle
- }
-}
diff --git a/src/routes/v2/block.js b/src/routes/v2/block.js
deleted file mode 100644
index 500687f..0000000
--- a/src/routes/v2/block.js
+++ /dev/null
@@ -1,280 +0,0 @@
-"use strict"
-
-const express = require("express")
-const requestUtils = require("./services/requestUtils")
-const axios = require("axios")
-const bitbox = require("./services/bitbox")
-const logger = require("./logging.js")
-const wlogger = require("../../util/winston-logging")
-
-const routeUtils = require("./route-utils")
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 3 }
-
-const router = express.Router()
-//const BitboxHTTP = bitbox.getInstance()
-
-router.get("/", root)
-router.get("/detailsByHash/:hash", detailsByHashSingle)
-router.post("/detailsByHash", detailsByHashBulk)
-router.get("/detailsByHeight/:height", detailsByHeightSingle)
-router.post("/detailsByHeight", detailsByHeightBulk)
-
-function root(req, res, next) {
- return res.json({ status: "block" })
-}
-
-// Call the insight server to get block details based on the hash.
-async function detailsByHashSingle(req, res, next) {
- try {
- const hash = req.params.hash
-
- // Reject if hash is empty
- if (!hash || hash === "") {
- res.status(400)
- return res.json({ error: "hash must not be empty" })
- }
-
- const response = await axios.get(
- `${process.env.BITCOINCOM_BASEURL}block/${hash}`
- )
- //console.log(`response.data: ${JSON.stringify(response.data,null,2)}`)
-
- const parsed = response.data
- return res.json(parsed)
- } catch (error) {
- //console.log(`error object: ${util.inspect(error)}`)
-
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(error)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- if (error.response && error.response.status === 404) {
- res.status(404)
- return res.json({ error: "Not Found" })
- }
-
- // Write out error to error log.
- //logger.error(`Error in block/detailsByHash: `, error)
- wlogger.error(`Error in block.ts/detailsByHashSingle().`, error)
-
- res.status(500)
- return res.json({ error: util.inspect(error) })
- }
-}
-
-async function detailsByHashBulk(req, res, next) {
- try {
- const hashes = req.body.hashes
-
- // Reject if hashes is not an array.
- if (!Array.isArray(hashes)) {
- res.status(400)
- return res.json({
- error: "hashes needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, hashes)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each hash in the array.
- for (let i = 0; i < hashes.length; i++) {
- const thisHash = hashes[i]
-
- if (thisHash.length !== 64) {
- res.status(400)
- return res.json({
- error: `Invalid hash. Double check your hash is valid: ${thisHash}`
- })
- }
- }
-
- // Loop through each hash and creates an array of promises
- const axiosPromises = hashes.map(async hash =>
- axios.get(`${process.env.BITCOINCOM_BASEURL}block/${hash}`)
- )
-
- // Wait for all parallel promises to return.
- const axiosResult = await axios.all(axiosPromises)
-
- // Extract the data component from the axios response.
- const result = axiosResult.map(x => x.data)
- //console.log(`result: ${util.inspect(result)}`)
-
- res.status(200)
- return res.json(result)
- } catch (error) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(error)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- if (error.response && error.response.status === 404) {
- res.status(404)
- return res.json({ error: "Not Found" })
- }
-
- // Write out error to error log.
- //logger.error(`Error in block/detailsByHash: `, error)
- wlogger.error(`Error in block.ts/detailsByHashBulk().`, error)
-
- res.status(500)
- return res.json({ error: util.inspect(error) })
- }
-}
-
-// Call the Full Node to get block hash based on height, then call the Insight
-// server to get details from that hash.
-async function detailsByHeightSingle(req, res, next) {
- try {
- const height = req.params.height
-
- // Reject if id is empty
- if (!height || height === "") {
- res.status(400)
- return res.json({ error: "height must not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getblockhash"
- requestConfig.data.method = "getblockhash"
- requestConfig.data.params = [parseInt(height)]
-
- const response = await BitboxHTTP(requestConfig)
-
- const hash = response.data.result
- //console.log(`response.data: ${util.inspect(response.data)}`)
-
- // Call detailsByHashSingle now that the hash has been retrieved.
- req.params.hash = hash
- return detailsByHashSingle(req, res, next)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in control/getInfo: `, error)
- wlogger.error(`Error in block.ts/detailsByHeightSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function detailsByHeightBulk(req, res, next) {
- try {
- const heights = req.body.heights
-
- // Reject if heights is not an array.
- if (!Array.isArray(heights)) {
- res.status(400)
- return res.json({
- error: "heights needs to be an array. Use GET for single height."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, heights)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- logger.debug(`Executing detailsByHeight with these heights: `, heights)
-
- // Validate each element in the address array.
- for (let i = 0; i < heights.length; i++) {
- const thisHeight = heights[i]
-
- // Reject if id is empty
- if (!thisHeight || thisHeight === "") {
- res.status(400)
- return res.json({ error: "height must not be empty" })
- }
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each height and creates an array of requests to call in parallel
- const promises = heights.map(async height => {
- requestConfig.data.id = "getblockhash"
- requestConfig.data.method = "getblockhash"
- requestConfig.data.params = [parseInt(height)]
-
- const response = await BitboxHTTP(requestConfig)
-
- const hash = response.data.result
-
- const axiosResult = await axios.get(
- `${process.env.BITCOINCOM_BASEURL}block/${hash}`
- )
-
- return axiosResult.data
- })
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(promises)
-
- res.status(200)
- return res.json(result)
- } catch (error) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(error)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- if (error.response && error.response.status === 404) {
- res.status(404)
- return res.json({ error: "Not Found" })
- }
-
- // Write out error to error log.
- //logger.error(`Error in block/detailsByHash: `, error)
- wlogger.error(`Error in block.ts/detailsByHeightBulk().`, error)
-
- res.status(500)
- return res.json({ error: util.inspect(error) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- detailsByHashSingle,
- detailsByHashBulk,
- detailsByHeightSingle,
- detailsByHeightBulk
- }
-}
diff --git a/src/routes/v2/blockchain.js b/src/routes/v2/blockchain.js
deleted file mode 100644
index 65d772d..0000000
--- a/src/routes/v2/blockchain.js
+++ /dev/null
@@ -1,890 +0,0 @@
-/*
- TODO
- - Add blockhash functionality back into getTxOutProof
-*/
-
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("./route-utils")
-const logger = require("./logging.js")
-const wlogger = require("../../util/winston-logging")
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-// Define routes.
-router.get("/", root)
-router.get("/getBestBlockHash", getBestBlockHash)
-// Dev Note: getBlock/:hash ommited because its the same as block/detailsByHash
-//router.get("/getBlock/:hash", getBlock)
-router.get("/getBlockchainInfo", getBlockchainInfo)
-router.get("/getBlockCount", getBlockCount)
-router.get("/getBlockHeader/:hash", getBlockHeaderSingle)
-router.post("/getBlockHeader", getBlockHeaderBulk)
-
-router.get("/getChainTips", getChainTips)
-router.get("/getDifficulty", getDifficulty)
-router.get("/getMempoolEntry/:txid", getMempoolEntrySingle)
-router.post("/getMempoolEntry", getMempoolEntryBulk)
-router.get("/getMempoolInfo", getMempoolInfo)
-router.get("/getRawMempool", getRawMempool)
-router.get("/getTxOut/:txid/:n", getTxOut)
-router.get("/getTxOutProof/:txid", getTxOutProofSingle)
-router.post("/getTxOutProof", getTxOutProofBulk)
-router.get("/verifyTxOutProof/:proof", verifyTxOutProofSingle)
-router.post("/verifyTxOutProof", verifyTxOutProofBulk)
-
-function root(req, res, next) {
- return res.json({ status: "blockchain" })
-}
-
-// Returns the hash of the best (tip) block in the longest block chain.
-async function getBestBlockHash(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getbestblockhash"
- requestConfig.data.method = "getbestblockhash"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getBestBlockHash().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getBlockchainInfo(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getblockchaininfo"
- requestConfig.data.method = "getblockchaininfo"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getBlockchainInfo().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getBlockCount(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getblockcount"
- requestConfig.data.method = "getblockcount"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getBlockCount().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getBlockHeaderSingle(req, res, next) {
- try {
- let verbose = false
- if (req.query.verbose && req.query.verbose.toString() === "true")
- verbose = true
-
- const hash = req.params.hash
- if (!hash || hash === "") {
- res.status(400)
- return res.json({ error: "hash can not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getblockheader"
- requestConfig.data.method = "getblockheader"
- requestConfig.data.params = [hash, verbose]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getBlockHeaderSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getBlockHeaderBulk(req, res, next) {
- try {
- const hashes = req.body.hashes
- const verbose = req.body.verbose ? req.body.verbose : false
-
- if (!Array.isArray(hashes)) {
- res.status(400)
- return res.json({
- error: "hashes needs to be an array. Use GET for single hash."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, hashes)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- logger.debug(
- `Executing blockchain/getBlockHeaderBulk with these hashes: `,
- hashes
- )
-
- // Validate each hash in the array.
- for (let i = 0; i < hashes.length; i++) {
- const hash = hashes[i]
-
- if (hash.length !== 64) {
- res.status(400)
- return res.json({ error: `This is not a hash: ${hash}` })
- }
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each hash and creates an array of requests to call in parallel
- const promises = hashes.map(async hash => {
- requestConfig.data.id = "getblockheader"
- requestConfig.data.method = "getblockheader"
- requestConfig.data.params = [hash, verbose]
-
- return await BitboxHTTP(requestConfig)
- })
-
- const axiosResult = await axios.all(promises)
-
- // Extract the data component from the axios response.
- const result = axiosResult.map(x => x.data.result)
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getBlockHeaderBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getChainTips(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getchaintips"
- requestConfig.data.method = "getchaintips"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getChainTips().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Get the current difficulty value, used to regulate mining power on the network.
-async function getDifficulty(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getdifficulty"
- requestConfig.data.method = "getdifficulty"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getDifficulty().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Returns mempool data for given transaction. TXID must be in mempool (unconfirmed)
-async function getMempoolEntrySingle(req, res, next) {
- try {
- // Validate input parameter
- const txid = req.params.txid
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: "txid can not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getmempoolentry"
- requestConfig.data.method = "getmempoolentry"
- requestConfig.data.params = [txid]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getMempoolEntrySingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getMempoolEntryBulk(req, res, next) {
- try {
- const txids = req.body.txids
-
- if (!Array.isArray(txids)) {
- res.status(400)
- return res.json({
- error: "txids needs to be an array. Use GET for single txid."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, txids)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- logger.debug(
- `Executing blockchain/getMempoolEntry with these txids: `,
- txids
- )
-
- // Validate each element in the array
- for (let i = 0; i < txids.length; i++) {
- const txid = txids[i]
-
- if (txid.length !== 64) {
- res.status(400)
- return res.json({ error: "This is not a txid" })
- }
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each txid and creates an array of requests to call in parallel
- const promises = txids.map(async txid => {
- requestConfig.data.id = "getmempoolentry"
- requestConfig.data.method = "getmempoolentry"
- requestConfig.data.params = [txid]
-
- return await BitboxHTTP(requestConfig)
- })
-
- const axiosResult = await axios.all(promises)
-
- // Extract the data component from the axios response.
- const result = axiosResult.map(x => x.data.result)
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getMempoolEntryBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getMempoolInfo(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getmempoolinfo"
- requestConfig.data.method = "getmempoolinfo"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getMempoolInfo().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getRawMempool(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- let verbose = false
- if (req.query.verbose && req.query.verbose === "true") verbose = true
-
- requestConfig.data.id = "getrawmempool"
- requestConfig.data.method = "getrawmempool"
- requestConfig.data.params = [verbose]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getRawMempool().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Returns details about an unspent transaction output.
-async function getTxOut(req, res, next) {
- try {
- // Validate input parameter
- const txid = req.params.txid
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: "txid can not be empty" })
- }
-
- let n = req.params.n
- if (n === undefined || n === "") {
- res.status(400)
- return res.json({ error: "n can not be empty" })
- }
- n = parseInt(n)
-
- let include_mempool = false
- if (req.query.include_mempool && req.query.include_mempool === "true")
- include_mempool = true
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "gettxout"
- requestConfig.data.method = "gettxout"
- requestConfig.data.params = [txid, n, include_mempool]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getTxOut().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Returns a hex-encoded proof that 'txid' was included in a block.
-async function getTxOutProofSingle(req, res, next) {
- try {
- // Validate input parameter
- const txid = req.params.txid
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: "txid can not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "gettxoutproof"
- requestConfig.data.method = "gettxoutproof"
- requestConfig.data.params = [[txid]]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getTxOutProofSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Returns a hex-encoded proof that 'txid' was included in a block.
-async function getTxOutProofBulk(req, res, next) {
- try {
- const txids = req.body.txids
-
- // Reject if txids is not an array.
- if (!Array.isArray(txids)) {
- res.status(400)
- return res.json({
- error: "txids needs to be an array. Use GET for single txid."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, txids)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Validate each element in the array.
- for (let i = 0; i < txids.length; i++) {
- const txid = txids[i]
-
- if (txid.length !== 64) {
- res.status(400)
- return res.json({
- error: `Invalid txid. Double check your txid is valid: ${txid}`
- })
- }
- }
-
- logger.debug(`Executing blockchain/getTxOutProof with these txids: `, txids)
-
- // Loop through each txid and creates an array of requests to call in parallel
- const promises = txids.map(async txid => {
- requestConfig.data.id = "gettxoutproof"
- requestConfig.data.method = "gettxoutproof"
- requestConfig.data.params = [[txid]]
-
- return await BitboxHTTP(requestConfig)
- })
-
- // Wait for all parallel promisses to resolve.
- const axiosResult = await axios.all(promises)
-
- // Extract the data component from the axios response.
- const result = axiosResult.map(x => x.data.result)
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getTxOutProofBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-/*
-//
-// router.get('/preciousBlock/:hash', async (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"preciousblock",
-// method: "preciousblock",
-// params: [
-// req.params.hash
-// ]
-// }
-// })
-// .then((response) => {
-// res.json(JSON.stringify(response.data.result));
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.post('/pruneBlockchain/:height', async (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"pruneblockchain",
-// method: "pruneblockchain",
-// params: [
-// req.params.height
-// ]
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.get('/verifyChain', async (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"verifychain",
-// method: "verifychain"
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-*/
-
-async function verifyTxOutProofSingle(req, res, next) {
- try {
- // Validate input parameter
- const proof = req.params.proof
- if (!proof || proof === "") {
- res.status(400)
- return res.json({ error: "proof can not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "verifytxoutproof"
- requestConfig.data.method = "verifytxoutproof"
- requestConfig.data.params = [req.params.proof]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/verifyTxOutProofSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function verifyTxOutProofBulk(req, res, next) {
- try {
- const proofs = req.body.proofs
-
- // Reject if proofs is not an array.
- if (!Array.isArray(proofs)) {
- res.status(400)
- return res.json({
- error: "proofs needs to be an array. Use GET for single proof."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, proofs)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Validate each element in the array.
- for (let i = 0; i < proofs.length; i++) {
- const proof = proofs[i]
-
- if (!proof || proof === "") {
- res.status(400)
- return res.json({ error: `proof can not be empty: ${proof}` })
- }
- }
-
- logger.debug(
- `Executing blockchain/verifyTxOutProof with these proofs: `,
- proofs
- )
-
- // Loop through each proof and creates an array of requests to call in parallel
- const promises = proofs.map(async proof => {
- requestConfig.data.id = "verifytxoutproof"
- requestConfig.data.method = "verifytxoutproof"
- requestConfig.data.params = [proof]
-
- return await BitboxHTTP(requestConfig)
- })
-
- // Wait for all parallel promisses to resolve.
- const axiosResult = await axios.all(promises)
-
- // Extract the data component from the axios response.
- const result = axiosResult.map(x => x.data.result[0])
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/verifyTxOutProofBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- getBestBlockHash,
- //getBlock,
- getBlockchainInfo,
- getBlockCount,
- getBlockHeaderSingle,
- getBlockHeaderBulk,
- getChainTips,
- getDifficulty,
- getMempoolInfo,
- getRawMempool,
- getMempoolEntrySingle,
- getMempoolEntryBulk,
- getTxOut,
- getTxOutProofSingle,
- getTxOutProofBulk,
- verifyTxOutProofSingle,
- verifyTxOutProofBulk
- }
-}
diff --git a/src/routes/v2/control.js b/src/routes/v2/control.js
deleted file mode 100644
index fabc233..0000000
--- a/src/routes/v2/control.js
+++ /dev/null
@@ -1,95 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const logger = require("./logging.js")
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-router.get("/", root)
-router.get("/getInfo", getInfo)
-
-function root(req, res, next) {
- return res.json({ status: "control" })
-}
-
-// Execute the RPC getinfo call.
-async function getInfo(req, res, next) {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getinfo"
- requestConfig.data.method = "getinfo"
- requestConfig.data.params = []
-
- try {
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (error) {
- wlogger.error(`Error in control.ts/getInfo().`, error)
-
- // Write out error to error log.
- //logger.error(`Error in control/getInfo: `, error)
-
- res.status(500)
- if (error.response && error.response.data && error.response.data.error)
- return res.json({ error: error.response.data.error })
- return res.json({ error: util.inspect(error) })
- }
-}
-
-// router.get('/getMemoryInfo', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"getmemoryinfo",
-// method: "getmemoryinfo"
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.get('/help', (req, res, next) => {
-// BITBOX.Control.help()
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-//
-// router.post('/stop', (req, res, next) => {
-// BITBOX.Control.stop()
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-
-module.exports = {
- router,
- testableComponents: {
- root,
- getInfo
- }
-}
diff --git a/src/routes/v2/generating.js b/src/routes/v2/generating.js
deleted file mode 100644
index ec0c601..0000000
--- a/src/routes/v2/generating.js
+++ /dev/null
@@ -1,51 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-//const axios = require("axios");
-
-//const BITBOXCli = require("bitbox-sdk/lib/bitbox-sdk").default;
-//const BITBOX = new BITBOXCli();
-
-//const BitboxHTTP = axios.create({
-// baseURL: process.env.RPC_BASEURL,
-//});
-//const username = process.env.RPC_USERNAME;
-//const password = process.env.RPC_PASSWORD;
-
-router.get("/", (req, res, next) => {
- res.json({ status: "generating" })
-})
-//
-// router.post('/generateToAddress/:nblocks/:address', (req, res, next) => {
-// let maxtries = 1000000;
-// if(req.query.maxtries) {
-// maxtries = parseInt(req.query.maxtries);
-// }
-//
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"generatetoaddress",
-// method: "generatetoaddress",
-// params: [
-// req.params.nblocks,
-// req.params.address,
-// maxtries
-// ]
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-
-module.exports = router
diff --git a/src/routes/v2/health-check.js b/src/routes/v2/health-check.js
deleted file mode 100644
index 8c05030..0000000
--- a/src/routes/v2/health-check.js
+++ /dev/null
@@ -1,11 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-
-/* GET home page. */
-router.get("/", (req, res, next) => {
- res.json({ status: "winning v2" })
-})
-
-module.exports = router
diff --git a/src/routes/v2/index.js b/src/routes/v2/index.js
deleted file mode 100644
index 33c175f..0000000
--- a/src/routes/v2/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-
-/* GET home page. */
-router.get("/", (req, res, next) => {
- res.render("swagger-v2")
-})
-
-router.get("/v2", (req, res, next) => {
- res.render("swagger-v2")
-})
-
-module.exports = router
diff --git a/src/routes/v2/logging.js b/src/routes/v2/logging.js
deleted file mode 100644
index 07fd9be..0000000
--- a/src/routes/v2/logging.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- A utility library for setting up greylog2 logging.
-*/
-
-"use strict"
-
-// This will be uncommented and correct once we have our logging server functioning.
-/*
-var graylog2 = require("graylog2");
-var logger = new graylog2.graylog({
- servers: [
- { 'host': '127.0.0.1', port: 12201 },
- { 'host': '127.0.0.2', port: 12201 }
- ],
- hostname: 'server.name', // the name of this host
- // (optional, default: os.hostname())
- facility: 'Node.js', // the facility for these log messages
- // (optional, default: "Node.js")
- bufferSize: 1350 // max UDP packet size, should never exceed the
- // MTU of your system (optional, default: 1400)
-});
-
-logger.on('error', function (error) {
- console.error('Error while trying to write to graylog2:', error);
-});
-*/
-
-// This is just a placeholder function that will be replaced once we get the
-// greylog server working.
-function log(msg, obj) {
- //console.log(msg, obj)
-}
-
-// This is just a placeholder function that will be replaced once we get the
-// greylog server working.
-function error(msg, obj) {
- if (!obj) console.error(msg)
- else console.error(msg, obj)
-}
-
-// This is just a placeholder function that will be replaced once we get the
-// greylog server working.
-function debug(msg, obj) {
- //console.log(msg, obj)
-}
-
-module.exports = {
- log,
- error,
- debug
-}
diff --git a/src/routes/v2/mining.js b/src/routes/v2/mining.js
deleted file mode 100644
index 243b75a..0000000
--- a/src/routes/v2/mining.js
+++ /dev/null
@@ -1,170 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("./route-utils")
-const logger = require("./logging.js")
-const wlogger = require("../../util/winston-logging")
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
-})
-const username = process.env.RPC_USERNAME
-const password = process.env.RPC_PASSWORD
-
-const requestConfig = {
- method: "post",
- auth: {
- username: username,
- password: password
- },
- data: {
- jsonrpc: "1.0"
- }
-}
-
-router.get("/", root)
-router.get("/getMiningInfo", getMiningInfo)
-router.get("/getNetworkHashps", getNetworkHashPS)
-
-function root(req, res, next) {
- return res.json({ status: "mining" })
-}
-
-//
-// router.get('/getBlockTemplate/:templateRequest', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"getblocktemplate",
-// method: "getblocktemplate",
-// params: [
-// req.params.templateRequest
-// ]
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-
-async function getMiningInfo(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getmininginfo"
- requestConfig.data.method = "getmininginfo"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in mining.ts/getMiningInfo().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getNetworkHashPS(req, res, next) {
- try {
- let nblocks = 120 // Default
- let height = -1 // Default
- if (req.query.nblocks) nblocks = parseInt(req.query.nblocks)
- if (req.query.height) height = parseInt(req.query.height)
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getnetworkhashps"
- requestConfig.data.method = "getnetworkhashps"
- requestConfig.data.params = [nblocks, height]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in mining.ts/getNetworkHashPS().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-//
-// router.post('/submitBlock/:hex', (req, res, next) => {
-// let parameters = '';
-// if(req.query.parameters && req.query.parameters !== '') {
-// parameters = true;
-// }
-//
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"submitblock",
-// method: "submitblock",
-// params: [
-// req.params.hex,
-// parameters
-// ]
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-
-module.exports = {
- router,
- testableComponents: {
- root,
- getMiningInfo,
- getNetworkHashPS
- }
-}
diff --git a/src/routes/v2/network.js b/src/routes/v2/network.js
deleted file mode 100644
index 0af2366..0000000
--- a/src/routes/v2/network.js
+++ /dev/null
@@ -1,168 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-
-router.get("/", async (req, res, next) => {
- res.json({ status: "network" })
-})
-
-// router.post('/addNode/:node/:command', (req, res, next) => {
-// BITBOX.Network.addNode(req.params.node, req.params.command)
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-//
-// router.post('/clearBanned', (req, res, next) => {
-// BITBOX.Network.clearBanned()
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-//
-// router.post('/disconnectNode/:address/:nodeid', (req, res, next) => {
-// BITBOX.Network.disconnectNode(req.params.address, req.params.nodeid)
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-//
-// router.get('/getAddedNodeInfo/:node', (req, res, next) => {
-// BITBOX.Network.getAddedNodeInfo(req.params.node)
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-//
-// router.get('/getConnectionCount', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"getconnectioncount",
-// method: "getconnectioncount"
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.get('/getNetTotals', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"getnettotals",
-// method: "getnettotals"
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.get('/getNetworkInfo', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"getnetworkinfo",
-// method: "getnetworkinfo"
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.get('/getPeerInfo', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"getpeerinfo",
-// method: "getpeerinfo"
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.get('/ping', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"ping",
-// method: "ping"
-// }
-// })
-// .then((response) => {
-// res.json(JSON.stringify(response.data.result));
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.post('/setBan/:subnet/:command', (req, res, next) => {
-// // TODO finish this
-// BITBOX.Network.getConnectionCount(req.params.subnet, req.params.command)
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-//
-// router.post('/setNetworkActive/:state', (req, res, next) => {
-// let state = true;
-// if(req.params.state && req.params.state === 'false') {
-// state = false;
-// }
-// BITBOX.Network.getConnectionCount(state)
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-
-module.exports = router
diff --git a/src/routes/v2/rawtransactions.js b/src/routes/v2/rawtransactions.js
deleted file mode 100644
index 99104c7..0000000
--- a/src/routes/v2/rawtransactions.js
+++ /dev/null
@@ -1,609 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("./route-utils")
-const logger = require("./logging.js")
-const wlogger = require("../../util/winston-logging")
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
-})
-const username = process.env.RPC_USERNAME
-const password = process.env.RPC_PASSWORD
-
-const requestConfig = {
- method: "post",
- auth: {
- username: username,
- password: password
- },
- data: {
- jsonrpc: "1.0"
- }
-}
-
-router.get("/", root)
-router.get("/decodeRawTransaction/:hex", decodeRawTransactionSingle)
-router.post("/decodeRawTransaction", decodeRawTransactionBulk)
-router.get("/decodeScript/:hex", decodeScriptSingle)
-router.post("/decodeScript", decodeScriptBulk)
-router.post("/getRawTransaction", getRawTransactionBulk)
-router.get("/getRawTransaction/:txid", getRawTransactionSingle)
-router.post("/sendRawTransaction", sendRawTransactionBulk)
-router.get("/sendRawTransaction/:hex", sendRawTransactionSingle)
-
-function root(req, res, next) {
- return res.json({ status: "rawtransactions" })
-}
-
-// Decode transaction hex into a JSON object.
-// GET
-async function decodeRawTransactionSingle(req, res, next) {
- try {
- const hex = req.params.hex
-
- // Throw an error if hex is empty.
- if (!hex || hex === "") {
- res.status(400)
- return res.json({ error: "hex can not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "decoderawtransaction"
- requestConfig.data.method = "decoderawtransaction"
- requestConfig.data.params = [hex]
-
- const response = await BitboxHTTP(requestConfig)
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(
- `Error in rawtransactions.ts/decodeRawTransactionSingle().`,
- err
- )
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function decodeRawTransactionBulk(req, res, next) {
- try {
- const hexes = req.body.hexes
-
- if (!Array.isArray(hexes)) {
- res.status(400)
- return res.json({ error: "hexes must be an array" })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, hexes)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- const results = []
-
- // Validate each element in the address array.
- for (let i = 0; i < hexes.length; i++) {
- const thisHex = hexes[i]
-
- // Reject if id is empty
- if (!thisHex || thisHex === "") {
- res.status(400)
- return res.json({ error: "Encountered empty hex" })
- }
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each height and creates an array of requests to call in parallel
- const promises = hexes.map(async hex => {
- requestConfig.data.id = "decoderawtransaction"
- requestConfig.data.method = "decoderawtransaction"
- requestConfig.data.params = [hex]
-
- return await BitboxHTTP(requestConfig)
- })
-
- // Wait for all parallel Insight requests to return.
- const axiosResult = await axios.all(promises)
-
- // Retrieve the data part of the result.
- const result = axiosResult.map(x => x.data.result)
-
- res.status(200)
- return res.json(result)
-
- /*
- // Loop through each hex and creates an array of requests to call in parallel
- hexes = hexes.map(async (hex: any) => {
- if (!hex || hex === "") {
- res.status(400)
- return res.json({ error: "Encountered empty hex" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "decoderawtransaction"
- requestConfig.data.method = "decoderawtransaction"
- requestConfig.data.params = [hex]
-
- return await BitboxHTTP(requestConfig)
- })
-
- const result: Array = []
- return axios.all(hexes).then(
- axios.spread((...args) => {
- args.forEach((arg: any) => {
- if (arg) {
- result.push(arg.data.result)
- }
- })
- res.status(200)
- return res.json(result)
- })
- )
-*/
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/getRawTransaction: `, err)
- wlogger.error(
- `Error in rawtransactions.ts/decodeRawTransactionBulk().`,
- err
- )
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Decode a raw transaction from hex to assembly.
-// GET single
-async function decodeScriptSingle(req, res, next) {
- try {
- const hex = req.params.hex
-
- // Throw an error if hex is empty.
- if (!hex || hex === "") {
- res.status(400)
- return res.json({ error: "hex can not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "decodescript"
- requestConfig.data.method = "decodescript"
- requestConfig.data.params = [hex]
-
- const response = await BitboxHTTP(requestConfig)
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeScript: `, err)
- wlogger.error(`Error in rawtransactions.ts/decodeScriptSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Decode a raw transaction from hex to assembly.
-// POST bulk
-async function decodeScriptBulk(req, res, next) {
- try {
- const hexes = req.body.hexes
-
- // Validation
- if (!Array.isArray(hexes)) {
- res.status(400)
- return res.json({ error: "hexes must be an array" })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, hexes)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each hex in the array
- for (let i = 0; i < hexes.length; i++) {
- const hex = hexes[i]
-
- // Throw an error if hex is empty.
- if (!hex || hex === "") {
- res.status(400)
- return res.json({ error: "Encountered empty hex" })
- }
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each hex and create an array of promises
- const promises = hexes.map(async hex => {
- requestConfig.data.id = "decodescript"
- requestConfig.data.method = "decodescript"
- requestConfig.data.params = [hex]
-
- const response = await BitboxHTTP(requestConfig)
- return response
- })
-
- // Wait for all parallel promises to return.
- const resolved = await Promise.all(promises)
-
- // Retrieve the data from each resolved promise.
- const result = resolved.map(x => x.data.result)
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeScript: `, err)
- wlogger.error(`Error in rawtransactions.ts/decodeScriptBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Retrieve raw transactions details from the full node.
-async function getRawTransactionsFromNode(txid, verbose) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getrawtransaction"
- requestConfig.data.method = "getrawtransaction"
- requestConfig.data.params = [txid, verbose]
-
- const response = await BitboxHTTP(requestConfig)
-
- return response.data.result
- } catch (err) {
- wlogger.error(`Error in rawtransactions.ts/getRawTransactionsFromNode().`)
- throw err
- }
-}
-
-// Get a JSON object breakdown of transaction details.
-// POST
-async function getRawTransactionBulk(req, res, next) {
- try {
- let verbose = 0
- if (req.body.verbose) verbose = 1
-
- const txids = req.body.txids
- if (!Array.isArray(txids)) {
- res.status(400)
- return res.json({ error: "txids must be an array" })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, txids)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // stub response object
- const returnResponse = {
- status: 100,
- json: {
- error: ""
- }
- }
-
- // Validate each txid in the array.
- for (let i = 0; i < txids.length; i++) {
- const txid = txids[i]
-
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: `Encountered empty TXID` })
- }
-
- if (txid.length !== 64) {
- res.status(400)
- return res.json({
- error: `parameter 1 must be of length 64 (not ${txid.length})`
- })
- }
- }
-
- // Loop through each txid and create an array of promises
- const promises = txids.map(async txid =>
- getRawTransactionsFromNode(txid, verbose)
- )
-
- // Wait for all parallel promises to return.
- const axiosResult = await axios.all(promises)
-
- res.status(200)
- return res.json(axiosResult)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/getRawTransaction: `, err)
- wlogger.error(`Error in rawtransactions.ts/getRawTransactionBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Get a JSON object breakdown of transaction details.
-// GET
-async function getRawTransactionSingle(req, res, next) {
- try {
- let verbose = 0
- if (req.query.verbose === "true") verbose = 1
-
- const txid = req.params.txid
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: "txid can not be empty" })
- }
-
- const data = await getRawTransactionsFromNode(txid, verbose)
-
- return res.json(data)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/getRawTransaction: `, err)
- wlogger.error(`Error in rawtransactions.ts/getRawTransactionSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Transmit a raw transaction to the BCH network.
-async function sendRawTransactionBulk(req, res, next) {
- try {
- // Validation
- const hexes = req.body.hexes
-
- // Reject if input is not an array
- if (!Array.isArray(hexes)) {
- res.status(400)
- return res.json({ error: "hex must be an array" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, hexes)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element
- for (let i = 0; i < hexes.length; i++) {
- const hex = hexes[i]
-
- if (hex === "") {
- res.status(400)
- return res.json({
- error: `Encountered empty hex`
- })
- }
- }
-
- // Dev Note CT 1/31/2019:
- // Sending the 'sendrawtrnasaction' RPC call to a full node in parallel will
- // not work. Testing showed that the full node will return the same TXID for
- // different TX hexes. I believe this is by design, to prevent double spends.
- // In parallel, we are essentially asking the node to broadcast a new TX before
- // it's finished broadcast the previous one. Serial execution is required.
-
- // How to send TX hexes in parallel the WRONG WAY:
- /*
- // Collect an array of promises.
- const promises = hexes.map(async (hex: any) => {
- requestConfig.data.id = "sendrawtransaction"
- requestConfig.data.method = "sendrawtransaction"
- requestConfig.data.params = [hex]
-
- return await BitboxHTTP(requestConfig)
- })
-
- // Wait for all parallel Insight requests to return.
- const axiosResult: Array = await axios.all(promises)
-
- // Retrieve the data part of the result.
- const result = axiosResult.map(x => x.data.result)
- */
-
- // Sending them serially.
- const result = []
- for (let i = 0; i < hexes.length; i++) {
- const hex = hexes[i]
-
- requestConfig.data.id = "sendrawtransaction"
- requestConfig.data.method = "sendrawtransaction"
- requestConfig.data.params = [hex]
-
- const rpcResult = await BitboxHTTP(requestConfig)
-
- result.push(rpcResult.data.result)
- }
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in rawtransactions.ts/sendRawTransactionBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Transmit a raw transaction to the BCH network.
-async function sendRawTransactionSingle(req, res, next) {
- try {
- const hex = req.params.hex // URL parameter
-
- // Reject if input is not an array or a string
- if (typeof hex !== "string") {
- res.status(400)
- return res.json({ error: "hex must be a string" })
- }
-
- // Validation
- if (hex === "") {
- res.status(400)
- return res.json({
- error: `Encountered empty hex`
- })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // RPC call
- requestConfig.data.id = "sendrawtransaction"
- requestConfig.data.method = "sendrawtransaction"
- requestConfig.data.params = [hex]
-
- const rpcResult = await BitboxHTTP(requestConfig)
-
- const result = rpcResult.data.result
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(
- `Error in rawtransactions.ts/sendRawTransactionSingle().`,
- err
- )
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- getRawTransactionsFromNode,
- testableComponents: {
- root,
- decodeRawTransactionSingle,
- decodeRawTransactionBulk,
- decodeScriptSingle,
- decodeScriptBulk,
- getRawTransactionBulk,
- getRawTransactionSingle,
- sendRawTransactionBulk,
- sendRawTransactionSingle
- }
-}
diff --git a/src/routes/v2/route-utils.js b/src/routes/v2/route-utils.js
deleted file mode 100644
index 4b462c6..0000000
--- a/src/routes/v2/route-utils.js
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- A private library of utility functions used by several different routes.
-*/
-
-"use strict"
-
-const axios = require("axios")
-const wlogger = require("../../util/winston-logging")
-
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BITBOXJS = require("@chris.troutner/bch-js")
-const BITBOX = new BITBOXJS()
-
-module.exports = {
- validateNetwork, // Prevents a common user error
- setEnvVars, // Allows RPC variables to be set dynamically based on changing env vars.
- decodeError, // Extract and interpret error messages.
- validateArraySize // Ensure the passed array meets rate limiting requirements.
-}
-
-// This function expects the Request Express.js object and an array as input.
-// The array is then validated against freemium and pro-tier rate limiting
-// requirements. A boolean is returned to indicate if the array size if valid
-// or not.
-function validateArraySize(req, array) {
- const FREEMIUM_INPUT_SIZE = 20
- const PRO_INPUT_SIZE = 100
-
- if (req.locals && req.locals.proLimit) {
- if (array.length <= PRO_INPUT_SIZE) return true
- } else if (array.length <= FREEMIUM_INPUT_SIZE) {
- return true
- }
-
- return false
-}
-
-// Returns true if user-provided cash address matches the correct network,
-// mainnet or testnet. If NETWORK env var is not defined, it returns false.
-// This prevent a common user-error issue that is easy to make: passing a
-// testnet address into rest.bitcoin.com or passing a mainnet address into
-// trest.bitcoin.com.
-function validateNetwork(addr) {
- try {
- const network = process.env.NETWORK
-
- // Return false if NETWORK is not defined.
- if (!network || network === "") {
- console.log(`Warning: NETWORK environment variable is not defined!`)
- return false
- }
-
- // Convert the user-provided address to a cashaddress, for easy detection
- // of the intended network.
- const cashAddr = BITBOX.Address.toCashAddress(addr)
-
- // Return true if the network and address both match testnet
- const addrIsTest = BITBOX.Address.isTestnetAddress(cashAddr)
- if (network === "testnet" && addrIsTest) return true
-
- // Return true if the network and address both match mainnet
- const addrIsMain = BITBOX.Address.isMainnetAddress(cashAddr)
- if (network === "mainnet" && addrIsMain) return true
-
- return false
- } catch (err) {
- logger.error(`Error in validateNetwork()`)
- return false
- }
-}
-
-// Dynamically set these based on env vars. Allows unit testing.
-function setEnvVars() {
- const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
- })
- const username = process.env.RPC_USERNAME
- const password = process.env.RPC_PASSWORD
-
- const requestConfig = {
- method: "post",
- auth: {
- username: username,
- password: password
- },
- data: {
- jsonrpc: "1.0"
- }
- }
-
- return { BitboxHTTP, username, password, requestConfig }
-}
-
-// Error messages returned by a full node can be burried pretty deep inside the
-// error object returned by Axios. This function attempts to extract and interpret
-// error messages.
-// Returns an object. If successful, obj.msg is a string.
-// If there is a failure, obj.msg is false.
-function decodeError(err) {
- try {
- // Attempt to extract the full node error message.
- if (
- err.response &&
- err.response.data &&
- err.response.data.error &&
- err.response.data.error.message
- )
- return { msg: err.response.data.error.message, status: 400 }
-
- // Attempt to extract the Insight error message
- if (err.response && err.response.data)
- return { msg: err.response.data, status: err.response.status }
-
- // Attempt to detect a network connection error.
- if (err.message && err.message.indexOf("ENOTFOUND") > -1) {
- return {
- msg:
- "Network error: Could not communicate with full node or other external service.",
- status: 503
- }
- }
-
- // Different kind of network error
- if (err.message && err.message.indexOf("ENETUNREACH") > -1) {
- return {
- msg:
- "Network error: Could not communicate with full node or other external service.",
- status: 503
- }
- }
-
- return { msg: false, status: 500 }
- } catch (err) {
- wlogger.error(`unhandled error in route-utils.js/decodeError(): `, err)
- return { msg: false, status: 500 }
- }
-}
diff --git a/src/routes/v2/services/bitbox.js b/src/routes/v2/services/bitbox.js
deleted file mode 100644
index 8fb0414..0000000
--- a/src/routes/v2/services/bitbox.js
+++ /dev/null
@@ -1,11 +0,0 @@
-"use strict"
-
-const axios = require("axios")
-
-const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
-})
-
-const getInstance = () => BitboxHTTP
-
-module.exports = getInstance
diff --git a/src/routes/v2/services/requestUtils.js b/src/routes/v2/services/requestUtils.js
deleted file mode 100644
index 7f64965..0000000
--- a/src/routes/v2/services/requestUtils.js
+++ /dev/null
@@ -1,20 +0,0 @@
-"use strict"
-
-const username = process.env.RPC_USERNAME
-const password = process.env.RPC_PASSWORD
-
-const getRequestConfig = (method, params) => ({
- method: "post",
- auth: {
- username,
- password
- },
- data: {
- jsonrpc: "1.0",
- id: method,
- method,
- params
- }
-})
-
-module.exports = getRequestConfig
diff --git a/src/routes/v2/slp.js b/src/routes/v2/slp.js
deleted file mode 100644
index af9cdb0..0000000
--- a/src/routes/v2/slp.js
+++ /dev/null
@@ -1,1369 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("./route-utils")
-const logger = require("./logging.js")
-const strftime = require("strftime")
-const wlogger = require("../../util/winston-logging")
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 5 }
-
-const SLPSDK = require("slp-sdk")
-const SLP = new SLPSDK()
-
-// Instantiate SLPJS.
-const slp = require("slpjs")
-const slpjs = new slp.Slp(SLP)
-const utils = slp.Utils
-
-// SLP tx db (LevelDB for caching)
-const level = require("level")
-const slpTxDb = level("./slp-tx-db")
-
-// Setup JSON RPC
-const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
-})
-const username = process.env.RPC_USERNAME
-const password = process.env.RPC_PASSWORD
-
-// Setup REST and TREST URLs used by slpjs
-// Dev note: this allows for unit tests to mock the URL.
-if (!process.env.REST_URL) process.env.REST_URL = `https://rest.bitcoin.com/v2/`
-if (!process.env.TREST_URL)
- process.env.TREST_URL = `https://trest.bitcoin.com/v2/`
-
-router.get("/", root)
-router.get("/list", list)
-router.get("/list/:tokenId", listSingleToken)
-router.post("/list", listBulkToken)
-router.get("/balancesForAddress/:address", balancesForAddress)
-router.get("/balancesForToken/:tokenId", balancesForTokenSingle)
-router.get("/balance/:address/:tokenId", balancesForAddressByTokenID)
-router.get("/convert/:address", convertAddressSingle)
-router.post("/convert", convertAddressBulk)
-router.post("/validateTxid", validateBulk)
-router.get("/validateTxid/:txid", validateSingle)
-router.get("/txDetails/:txid", txDetails)
-router.get("/tokenStats/:tokenId", tokenStats)
-router.get("/transactions/:tokenId/:address", txsTokenIdAddressSingle)
-
-if (process.env.NON_JS_FRAMEWORK && process.env.NON_JS_FRAMEWORK === "true") {
- router.get(
- "/createTokenType1/:fundingAddress/:fundingWif/:tokenReceiverAddress/:batonReceiverAddress/:bchChangeReceiverAddress/:decimals/:name/:symbol/:documentUri/:documentHash/:initialTokenQty",
- createTokenType1
- )
- router.get(
- "/mintTokenType1/:fundingAddress/:fundingWif/:tokenReceiverAddress/:batonReceiverAddress/:bchChangeReceiverAddress/:tokenId/:additionalTokenQty",
- mintTokenType1
- )
- router.get(
- "/sendTokenType1/:fundingAddress/:fundingWif/:tokenReceiverAddress/:bchChangeReceiverAddress/:tokenId/:amount",
- sendTokenType1
- )
- router.get(
- "/burnTokenType1/:fundingAddress/:fundingWif/:bchChangeReceiverAddress/:tokenId/:amount",
- burnTokenType1
- )
- router.get(
- "/burnAllTokenType1/:fundingAddress/:fundingWif/:bchChangeReceiverAddress/:tokenId",
- burnAllTokenType1
- )
-}
-
-// Retrieve raw transactions details from the full node.
-// TODO: move this function to a separate support library.
-// TODO: Add unit tests for this function.
-async function getRawTransactionsFromNode(txids) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- const txPromises = txids.map(async txid => {
- // Check slpTxDb
- try {
- if (slpTxDb.isOpen()) {
- const rawTx = await slpTxDb.get(txid)
- return rawTx
- }
- } catch (err) {}
-
- requestConfig.data.id = "getrawtransaction"
- requestConfig.data.method = "getrawtransaction"
- requestConfig.data.params = [txid, 0]
-
- const response = await BitboxHTTP(requestConfig)
- const result = response.data.result
-
- // Insert to slpTxDb
- try {
- if (slpTxDb.isOpen()) await slpTxDb.put(txid, result)
- } catch (err) {
- // console.log("Error inserting to slpTxDb", err)
- }
-
- return result
- })
-
- const results = await axios.all(txPromises)
- return results
- } catch (err) {
- wlogger.error(`Error in slp.ts/getRawTransactionsFromNode().`, err)
- throw err
- }
-}
-
-// Create a validator for validating SLP transactions.
-function createValidator(network, getRawTransactions = null) {
- let tmpSLP
-
- if (network === "mainnet")
- tmpSLP = new SLPSDK({ restURL: process.env.REST_URL })
- else tmpSLP = new SLPSDK({ restURL: process.env.TREST_URL })
-
- const slpValidator = new slp.LocalValidator(
- tmpSLP,
- getRawTransactions
- ? getRawTransactions
- : tmpSLP.RawTransactions.getRawTransaction.bind(this)
- )
-
- return slpValidator
-}
-
-// Instantiate the local SLP validator.
-const slpValidator = createValidator(
- process.env.NETWORK,
- getRawTransactionsFromNode
-)
-
-// Instantiate the bitboxproxy class in SLPJS.
-const bitboxproxy = new slp.BitboxNetwork(SLP, slpValidator)
-
-const requestConfig = {
- method: "post",
- auth: {
- username: username,
- password: password
- },
- data: {
- jsonrpc: "1.0"
- }
-}
-
-function formatTokenOutput(token) {
- token.tokenDetails.id = token.tokenDetails.tokenIdHex
- delete token.tokenDetails.tokenIdHex
- token.tokenDetails.documentHash = token.tokenDetails.documentSha256Hex
- delete token.tokenDetails.documentSha256Hex
- token.tokenDetails.initialTokenQty = parseFloat(
- token.tokenDetails.genesisOrMintQuantity
- )
- delete token.tokenDetails.genesisOrMintQuantity
- delete token.tokenDetails.transactionType
- delete token.tokenDetails.batonVout
- delete token.tokenDetails.sendOutputs
-
- token.tokenDetails.blockCreated = token.tokenStats.block_created
- token.tokenDetails.blockLastActiveSend =
- token.tokenStats.block_last_active_send
- token.tokenDetails.blockLastActiveMint =
- token.tokenStats.block_last_active_mint
- token.tokenDetails.txnsSinceGenesis =
- token.tokenStats.qty_valid_txns_since_genesis
- token.tokenDetails.validAddresses = token.tokenStats.qty_valid_token_addresses
- token.tokenDetails.totalMinted = parseFloat(token.tokenStats.qty_token_minted)
- token.tokenDetails.totalBurned = parseFloat(token.tokenStats.qty_token_burned)
- token.tokenDetails.circulatingSupply = parseFloat(
- token.tokenStats.qty_token_circulating_supply
- )
- token.tokenDetails.mintingBatonStatus = token.tokenStats.minting_baton_status
-
- delete token.tokenStats.block_last_active_send
- delete token.tokenStats.block_last_active_mint
- delete token.tokenStats.qty_valid_txns_since_genesis
- delete token.tokenStats.qty_valid_token_addresses
- return token
-}
-
-function root(req, res, next) {
- return res.json({ status: "slp" })
-}
-
-async function list(req, res, next) {
- try {
- const query = {
- v: 3,
- q: {
- db: ["t"],
- find: {
- $query: {}
- },
- project: { tokenDetails: 1, tokenStats: 1, _id: 0 },
- sort: { "tokenStats.block_created": -1 },
- limit: 10000
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- // Get data from SLPDB.
- const tokenRes = await axios.get(url)
-
- const formattedTokens = []
-
- if (tokenRes.data.t.length) {
- tokenRes.data.t.forEach(token => {
- token = formatTokenOutput(token)
- formattedTokens.push(token.tokenDetails)
- })
- }
-
- res.status(200)
- return res.json(formattedTokens)
- } catch (err) {
- wlogger.error(`Error in slp.ts/list().`, err)
-
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
- res.status(500)
- return res.json({ error: `Error in /list: ${err.message}` })
- }
-}
-
-async function listSingleToken(req, res, next) {
- try {
- const tokenId = req.params.tokenId
-
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const t = await lookupToken(tokenId)
-
- res.status(200)
- return res.json(t)
- } catch (err) {
- wlogger.error(`Error in slp.ts/listSingleToken().`, err)
-
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
- res.status(500)
- return res.json({ error: `Error in /list/:tokenId: ${err.message}` })
- }
-}
-
-async function listBulkToken(req, res, next) {
- try {
- const tokenIds = req.body.tokenIds
-
- // Reject if tokenIds is not an array.
- if (!Array.isArray(tokenIds)) {
- res.status(400)
- return res.json({
- error: "tokenIds needs to be an array. Use GET for single tokenId."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, tokenIds)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- const query = {
- v: 3,
- q: {
- db: ["t"],
- find: {
- "tokenDetails.tokenIdHex": {
- $in: tokenIds
- }
- },
- project: { tokenDetails: 1, tokenStats: 1, _id: 0 },
- sort: { "tokenStats.block_created": -1 },
- limit: 10000
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- const tokenRes = await axios.get(url)
-
- const formattedTokens = []
- const txids = []
-
- if (tokenRes.data.t.length) {
- tokenRes.data.t.forEach(token => {
- txids.push(token.tokenDetails.tokenIdHex)
- token = formatTokenOutput(token)
- formattedTokens.push(token.tokenDetails)
- })
- }
-
- tokenIds.forEach(tokenId => {
- if (!txids.includes(tokenId)) {
- formattedTokens.push({
- id: tokenId,
- valid: false
- })
- }
- })
-
- res.status(200)
- return res.json(formattedTokens)
- } catch (err) {
- wlogger.error(`Error in slp.ts/listBulkToken().`, err)
-
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
- res.status(500)
- return res.json({ error: `Error in /list/:tokenId: ${err.message}` })
- }
-}
-
-async function lookupToken(tokenId) {
- try {
- const query = {
- v: 3,
- q: {
- db: ["t"],
- find: {
- $query: {
- "tokenDetails.tokenIdHex": tokenId
- }
- },
- project: { tokenDetails: 1, tokenStats: 1, _id: 0 },
- limit: 1000
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- const tokenRes = await axios.get(url)
- //console.log(`tokenRes.data: ${util.inspect(tokenRes.data,null,2)}`)
- //console.log(`tokenRes.data.t[0]: ${util.inspect(tokenRes.data.t[0],null,2)}`)
-
- const formattedTokens = []
-
- if (tokenRes.data.t.length) {
- tokenRes.data.t.forEach(token => {
- token = formatTokenOutput(token)
- formattedTokens.push(token.tokenDetails)
- })
- }
-
- let t
- formattedTokens.forEach(token => {
- if (token.id === tokenId) t = token
- })
-
- // If token could not be found.
- if (t === undefined) {
- t = {
- id: "not found"
- }
- }
-
- return t
- } catch (err) {
- wlogger.error(`Error in slp.ts/lookupToken().`, err)
- //console.log(`Error in slp.ts/lookupToken()`)
- throw err
- }
-}
-
-// Retrieve token balances for all tokens for a single address.
-async function balancesForAddress(req, res, next) {
- try {
- // Validate the input data.
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Ensure the input is a valid BCH address.
- try {
- const cash = utils.toCashAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const cashAddr = utils.toCashAddress(address)
- const networkIsValid = routeUtils.validateNetwork(cashAddr)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- const query = {
- v: 3,
- q: {
- db: ["a"],
- find: {
- address: SLP.Address.toSLPAddress(address),
- token_balance: { $gte: 0 }
- },
- limit: 10000
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- const tokenRes = await axios.get(url)
-
- const tokenIds = []
- if (tokenRes.data.a.length > 0) {
- tokenRes.data.a = tokenRes.data.a.map(token => {
- token.tokenId = token.tokenDetails.tokenIdHex
- tokenIds.push(token.tokenId)
- token.balance = parseFloat(token.token_balance)
- token.slpAddress = token.address
- delete token.tokenDetails
- delete token.satoshis_balance
- delete token.token_balance
- delete token._id
- delete token.address
- return token
- })
-
- const promises = tokenIds.map(async tokenId => {
- try {
- const query2 = {
- v: 3,
- q: {
- db: ["t"],
- find: {
- $query: {
- "tokenDetails.tokenIdHex": tokenId
- }
- },
- project: {
- "tokenDetails.decimals": 1,
- "tokenDetails.tokenIdHex": 1,
- _id: 0
- },
- limit: 1000
- }
- }
-
- const s2 = JSON.stringify(query2)
- const b642 = Buffer.from(s2).toString("base64")
- const url2 = `${process.env.SLPDB_URL}q/${b642}`
-
- const tokenRes2 = await axios.get(url2)
- return tokenRes2.data
- } catch (err) {
- throw err
- }
- })
-
- const details = await axios.all(promises)
- tokenRes.data.a = tokenRes.data.a.map(token => {
- details.forEach(detail => {
- if (detail.t[0].tokenDetails.tokenIdHex === token.tokenId)
- token.decimalCount = detail.t[0].tokenDetails.decimals
- })
- return token
- })
-
- return res.json(tokenRes.data.a)
- }
- return res.json("No balance for this address")
- } catch (err) {
- wlogger.error(`Error in slp.ts/balancesForAddress().`, err)
-
- // Decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- res.status(500)
- return res.json({
- error: `Error in /ddress/:address: ${err.message}`
- })
- }
-}
-
-// Retrieve token balances for all addresses by single tokenId.
-async function balancesForTokenSingle(req, res, next) {
- try {
- // Validate the input data.
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const query = {
- v: 3,
- q: {
- find: {
- "tokenDetails.tokenIdHex": tokenId,
- token_balance: { $gte: 0 }
- },
- limit: 10000,
- project: { address: 1, satoshis_balance: 1, token_balance: 1, _id: 0 }
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- // Get data from SLPDB.
- const tokenRes = await axios.get(url)
- const resBalances = tokenRes.data.a.map((addy, index) => {
- delete addy.satoshis_balance
- addy.tokenBalance = parseFloat(addy.token_balance)
- addy.slpAddress = addy.address
- addy.tokenId = tokenId
- delete addy.address
- delete addy.token_balance
- return addy
- })
- return res.json(resBalances)
- } catch (err) {
- wlogger.error(`Error in slp.ts/balancesForTokenSingle().`, err)
-
- // Decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- res.status(500)
- return res.json({
- error: `Error in /balancesForToken/:tokenId: ${err.message}`
- })
- }
-}
-
-// Retrieve token balances for a single token class, for a single address.
-async function balancesForAddressByTokenID(req, res, next) {
- try {
- // Validate input data.
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- // Ensure the input is a valid BCH address.
- try {
- const cash = utils.toCashAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const cashAddr = utils.toCashAddress(address)
- const networkIsValid = routeUtils.validateNetwork(cashAddr)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Convert input to an simpleledger: address.
- const slpAddr = utils.toSlpAddress(req.params.address)
-
- const query = {
- v: 3,
- q: {
- db: ["a"],
- find: {
- address: slpAddr,
- token_balance: { $gte: 0 }
- },
- limit: 10
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- // Get data from SLPDB.
- const tokenRes = await axios.get(url)
- let resVal
- res.status(200)
- if (tokenRes.data.a.length > 0) {
- tokenRes.data.a.forEach(async token => {
- if (token.tokenDetails.tokenIdHex === tokenId) {
- resVal = {
- tokenId: tokenRes.data.a[0].tokenDetails.tokenIdHex,
- balance: parseFloat(tokenRes.data.a[0].token_balance)
- }
- // const query2 = {
- // v: 3,
- // q: {
- // db: ["t"],
- // find: {
- // $query: {
- // "tokenDetails.tokenIdHex": tokenId
- // }
- // },
- // project: {
- // "tokenDetails.decimals": 1,
- // "tokenDetails.tokenIdHex": 1,
- // _id: 0
- // },
- // limit: 1000
- // }
- // }
- //
- // const s2 = JSON.stringify(query2)
- // const b642 = Buffer.from(s2).toString("base64")
- // const url2 = `${process.env.SLPDB_URL}q/${b642}`
- //
- // const tokenRes2 = await axios.get(url2)
- // console.log("hello world", tokenRes2.data.t)
- // resVal = {
- // tokenId: token.tokenDetails.tokenIdHex,
- // balance: parseFloat(token.token_balance),
- // decimalCount: tokenRes2.data.t[0].tokenDetails.decimals
- // }
- // console.log("resVal", resVal)
- // return res.json(resVal)
- } else {
- resVal = {
- tokenId: tokenId,
- balance: 0
- }
- }
- })
- } else {
- resVal = {
- tokenId: tokenId,
- balance: 0
- }
- }
- return res.json(resVal)
- } catch (err) {
- wlogger.error(`Error in slp.ts/balancesForAddressByTokenID().`, err)
-
- // Decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- res.status(500)
- return res.json({
- error: `Error in /balance/:address/:tokenId: ${err.message}`
- })
- }
-}
-
-async function convertAddressSingle(req, res, next) {
- try {
- const address = req.params.address
-
- // Validate input
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- const slpAddr = SLP.Address.toSLPAddress(address)
-
- const obj = {
- slpAddress: "",
- cashAddress: "",
- legacyAddress: ""
- }
- obj.slpAddress = slpAddr
- obj.cashAddress = SLP.Address.toCashAddress(slpAddr)
- obj.legacyAddress = SLP.Address.toLegacyAddress(obj.cashAddress)
-
- res.status(200)
- return res.json(obj)
- } catch (err) {
- wlogger.error(`Error in slp.ts/convertAddressSingle().`, err)
-
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
- res.status(500)
- return res.json({
- error: `Error in /address/convert/:address: ${err.message}`
- })
- }
-}
-
-async function convertAddressBulk(req, res, next) {
- const addresses = req.body.addresses
-
- // Reject if hashes is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({
- error: "addresses needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Convert each address in the array.
- const convertedAddresses = []
- for (let i = 0; i < addresses.length; i++) {
- const address = addresses[i]
-
- // Validate input
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- const slpAddr = SLP.Address.toSLPAddress(address)
-
- const obj = {
- slpAddress: "",
- cashAddress: "",
- legacyAddress: ""
- }
- obj.slpAddress = slpAddr
- obj.cashAddress = SLP.Address.toCashAddress(slpAddr)
- obj.legacyAddress = SLP.Address.toLegacyAddress(obj.cashAddress)
-
- convertedAddresses.push(obj)
- }
-
- res.status(200)
- return res.json(convertedAddresses)
-}
-
-async function validateBulk(req, res, next) {
- try {
- const txids = req.body.txids
-
- // Reject if txids is not an array.
- if (!Array.isArray(txids)) {
- res.status(400)
- return res.json({ error: "txids needs to be an array" })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, txids)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- logger.debug(`Executing slp/validate with these txids: `, txids)
-
- // Validate each txid
- const validatePromises = txids.map(async txid => {
- try {
- // Dev note: must call module.exports to allow stubs in unit tests.
- const isValid = await module.exports.testableComponents.isValidSlpTxid(
- txid
- )
-
- const tmp = {
- txid: txid,
- valid: isValid ? true : false
- }
- return tmp
- } catch (err) {
- //console.log(`err obj: ${util.inspect(err)}`)
- //console.log(`err.response.data: ${util.inspect(err.response.data)}`)
- throw err
- }
- })
-
- // Filter array to only valid txid results
- const validateResults = await axios.all(validatePromises)
- const validTxids = validateResults.filter(result => result)
-
- res.status(200)
- return res.json(validTxids)
- } catch (err) {
- wlogger.error(`Error in slp.ts/validateBulk().`, err)
-
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function validateSingle(req, res, next) {
- try {
- const txid = req.params.txid
-
- // Validate input
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: "txid can not be empty" })
- }
-
- logger.debug(`Executing slp/validate/:txid with this txid: `, txid)
-
- // Validate txid
- // Dev note: must call module.exports to allow stubs in unit tests.
- const isValid = await module.exports.testableComponents.isValidSlpTxid(txid)
-
- const tmp = {
- txid: txid,
- valid: isValid ? true : false
- }
-
- res.status(200)
- return res.json(tmp)
- } catch (err) {
- wlogger.error(`Error in slp.ts/validateSingle().`, err)
-
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Returns a Boolean if the input TXID is a valid SLP TXID.
-async function isValidSlpTxid(txid) {
- const isValid = await slpValidator.isValidSlpTxid(txid)
- return isValid
-}
-
-// Below are functions which are enabled for teams not using our javascript SDKs which still need to create txs
-// These should never be enabled on our public REST API
-
-async function createTokenType1(req, res, next) {
- const fundingAddress = req.params.fundingAddress
- if (!fundingAddress || fundingAddress === "") {
- res.status(400)
- return res.json({ error: "fundingAddress can not be empty" })
- }
-
- const fundingWif = req.params.fundingWif
- if (!fundingWif || fundingWif === "") {
- res.status(400)
- return res.json({ error: "fundingWif can not be empty" })
- }
-
- const tokenReceiverAddress = req.params.tokenReceiverAddress
- if (!tokenReceiverAddress || tokenReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "tokenReceiverAddress can not be empty" })
- }
-
- const batonReceiverAddress = req.params.batonReceiverAddress
- if (!batonReceiverAddress || batonReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "batonReceiverAddress can not be empty" })
- }
-
- const bchChangeReceiverAddress = req.params.bchChangeReceiverAddress
- if (!bchChangeReceiverAddress || bchChangeReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "bchChangeReceiverAddress can not be empty" })
- }
-
- const decimals = req.params.decimals
- if (!decimals || decimals === "") {
- res.status(400)
- return res.json({ error: "decimals can not be empty" })
- }
-
- const name = req.params.name
- if (!name || name === "") {
- res.status(400)
- return res.json({ error: "name can not be empty" })
- }
-
- const symbol = req.params.symbol
- if (!symbol || symbol === "") {
- res.status(400)
- return res.json({ error: "symbol can not be empty" })
- }
-
- const documentUri = req.params.documentUri
- if (!documentUri || documentUri === "") {
- res.status(400)
- return res.json({ error: "documentUri can not be empty" })
- }
-
- const documentHash = req.params.documentHash
- if (!documentHash || documentHash === "") {
- res.status(400)
- return res.json({ error: "documentHash can not be empty" })
- }
-
- const initialTokenQty = req.params.initialTokenQty
- if (!initialTokenQty || initialTokenQty === "") {
- res.status(400)
- return res.json({ error: "initialTokenQty can not be empty" })
- }
-
- const token = await SLP.TokenType1.create({
- fundingAddress: fundingAddress,
- fundingWif: fundingWif,
- tokenReceiverAddress: tokenReceiverAddress,
- batonReceiverAddress: batonReceiverAddress,
- bchChangeReceiverAddress: bchChangeReceiverAddress,
- decimals: decimals,
- name: name,
- symbol: symbol,
- documentUri: documentUri,
- documentHash: documentHash,
- initialTokenQty: initialTokenQty
- })
-
- res.status(200)
- return res.json(token)
-}
-
-async function mintTokenType1(req, res, next) {
- const fundingAddress = req.params.fundingAddress
- if (!fundingAddress || fundingAddress === "") {
- res.status(400)
- return res.json({ error: "fundingAddress can not be empty" })
- }
-
- const fundingWif = req.params.fundingWif
- if (!fundingWif || fundingWif === "") {
- res.status(400)
- return res.json({ error: "fundingWif can not be empty" })
- }
-
- const tokenReceiverAddress = req.params.tokenReceiverAddress
- if (!tokenReceiverAddress || tokenReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "tokenReceiverAddress can not be empty" })
- }
-
- const batonReceiverAddress = req.params.batonReceiverAddress
- if (!batonReceiverAddress || batonReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "batonReceiverAddress can not be empty" })
- }
-
- const bchChangeReceiverAddress = req.params.bchChangeReceiverAddress
- if (!bchChangeReceiverAddress || bchChangeReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "bchChangeReceiverAddress can not be empty" })
- }
-
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const additionalTokenQty = req.params.additionalTokenQty
- if (!additionalTokenQty || additionalTokenQty === "") {
- res.status(400)
- return res.json({ error: "additionalTokenQty can not be empty" })
- }
-
- const mint = await SLP.TokenType1.mint({
- fundingAddress: fundingAddress,
- fundingWif: fundingWif,
- tokenReceiverAddress: tokenReceiverAddress,
- batonReceiverAddress: batonReceiverAddress,
- bchChangeReceiverAddress: bchChangeReceiverAddress,
- tokenId: tokenId,
- additionalTokenQty: additionalTokenQty
- })
-
- res.status(200)
- return res.json(mint)
-}
-
-async function sendTokenType1(req, res, next) {
- const fundingAddress = req.params.fundingAddress
- if (!fundingAddress || fundingAddress === "") {
- res.status(400)
- return res.json({ error: "fundingAddress can not be empty" })
- }
-
- const fundingWif = req.params.fundingWif
- if (!fundingWif || fundingWif === "") {
- res.status(400)
- return res.json({ error: "fundingWif can not be empty" })
- }
-
- const tokenReceiverAddress = req.params.tokenReceiverAddress
- if (!tokenReceiverAddress || tokenReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "tokenReceiverAddress can not be empty" })
- }
-
- const bchChangeReceiverAddress = req.params.bchChangeReceiverAddress
- if (!bchChangeReceiverAddress || bchChangeReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "bchChangeReceiverAddress can not be empty" })
- }
-
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const amount = req.params.amount
- if (!amount || amount === "") {
- res.status(400)
- return res.json({ error: "amount can not be empty" })
- }
- const send = await SLP.TokenType1.send({
- fundingAddress: fundingAddress,
- fundingWif: fundingWif,
- tokenReceiverAddress: tokenReceiverAddress,
- bchChangeReceiverAddress: bchChangeReceiverAddress,
- tokenId: tokenId,
- amount: amount
- })
-
- res.status(200)
- return res.json(send)
-}
-
-async function burnTokenType1(req, res, next) {
- const fundingAddress = req.params.fundingAddress
- if (!fundingAddress || fundingAddress === "") {
- res.status(400)
- return res.json({ error: "fundingAddress can not be empty" })
- }
-
- const fundingWif = req.params.fundingWif
- if (!fundingWif || fundingWif === "") {
- res.status(400)
- return res.json({ error: "fundingWif can not be empty" })
- }
-
- const bchChangeReceiverAddress = req.params.bchChangeReceiverAddress
- if (!bchChangeReceiverAddress || bchChangeReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "bchChangeReceiverAddress can not be empty" })
- }
-
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const amount = req.params.amount
- if (!amount || amount === "") {
- res.status(400)
- return res.json({ error: "amount can not be empty" })
- }
-
- const burn = await SLP.TokenType1.burn({
- fundingAddress: fundingAddress,
- fundingWif: fundingWif,
- tokenId: tokenId,
- amount: amount,
- bchChangeReceiverAddress: bchChangeReceiverAddress
- })
-
- res.status(200)
- return res.json(burn)
-}
-
-async function burnAllTokenType1(req, res, next) {
- const fundingAddress = req.params.fundingAddress
- if (!fundingAddress || fundingAddress === "") {
- res.status(400)
- return res.json({ error: "fundingAddress can not be empty" })
- }
-
- const fundingWif = req.params.fundingWif
- if (!fundingWif || fundingWif === "") {
- res.status(400)
- return res.json({ error: "fundingWif can not be empty" })
- }
-
- const bchChangeReceiverAddress = req.params.bchChangeReceiverAddress
- if (!bchChangeReceiverAddress || bchChangeReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "bchChangeReceiverAddress can not be empty" })
- }
-
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const burnAll = await SLP.TokenType1.burnAll({
- fundingAddress: fundingAddress,
- fundingWif: fundingWif,
- tokenId: tokenId,
- bchChangeReceiverAddress: bchChangeReceiverAddress
- })
-
- res.status(200)
- return res.json(burnAll)
-}
-
-async function txDetails(req, res, next) {
- try {
- // Validate input parameter
- const txid = req.params.txid
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: "txid can not be empty" })
- }
-
- if (txid.length !== 64) {
- res.status(400)
- return res.json({ error: "This is not a txid" })
- }
-
- let tmpSLP
- if (process.env.NETWORK === "testnet")
- tmpSLP = new SLPSDK({ restURL: process.env.TREST_URL })
- else tmpSLP = new SLPSDK({ restURL: process.env.REST_URL })
-
- const tmpbitboxNetwork = new slp.BitboxNetwork(tmpSLP, slpValidator)
- //console.log(
- // `tmpbitboxNetwork: ${JSON.stringify(tmpbitboxNetwork, null, 2)}`
- //)
-
- // Get TX info + token info
- const result = await tmpbitboxNetwork.getTransactionDetails(txid)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- wlogger.error(`Error in slp.ts/txDetails().`, err)
-
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Handle corner case of mis-typted txid
- if (err.error.indexOf("Not found") > -1) {
- res.status(400)
- return res.json({ error: "TXID not found" })
- }
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function tokenStats(req, res, next) {
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- try {
- const query = {
- v: 3,
- q: {
- db: ["t"],
- find: {
- $query: {
- "tokenDetails.tokenIdHex": tokenId
- }
- },
- project: { tokenDetails: 1, tokenStats: 1, _id: 0 },
- limit: 10
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- // Get data from BitDB.
- const tokenRes = await axios.get(url)
-
- const formattedTokens = []
-
- if (tokenRes.data.t.length) {
- tokenRes.data.t.forEach(token => {
- token = formatTokenOutput(token)
- formattedTokens.push(token.tokenDetails)
- })
- }
-
- res.status(200)
- return res.json(formattedTokens[0])
- } catch (err) {
- wlogger.error(`Error in slp.ts/tokenStats().`, err)
-
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
- res.status(500)
- return res.json({ error: `Error in /tokenStats: ${err.message}` })
- }
-}
-
-// Retrieve transactions by tokenId and address.
-async function txsTokenIdAddressSingle(req, res, next) {
- try {
- // Validate the input data.
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- const query = {
- v: 3,
- q: {
- find: {
- db: ["c", "u"],
- $query: {
- $or: [
- {
- "in.e.a": address
- },
- {
- "out.e.a": address
- }
- ],
- "slp.detail.tokenIdHex": tokenId
- },
- $orderby: {
- "blk.i": -1
- }
- },
- limit: 100
- },
- r: {
- f: "[.[] | { txid: .tx.h, tokenDetails: .slp } ]"
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- // Get data from SLPDB.
- const tokenRes = await axios.get(url)
- //console.log(`tokenRes.data: ${JSON.stringify(tokenRes.data,null,2)}`)
-
- return res.json(tokenRes.data.c)
- } catch (err) {
- wlogger.error(`Error in slp.ts/txsTokenIdAddressSingle().`, err)
-
- // Decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- res.status(500)
- return res.json({
- error: `Error in /transactions/:tokenId/:address: ${err.message}`
- })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- list,
- listSingleToken,
- listBulkToken,
- balancesForAddress,
- balancesForAddressByTokenID,
- convertAddressSingle,
- convertAddressBulk,
- validateBulk,
- isValidSlpTxid,
- createTokenType1,
- mintTokenType1,
- sendTokenType1,
- burnTokenType1,
- burnAllTokenType1,
- txDetails,
- tokenStats,
- balancesForTokenSingle,
- txsTokenIdAddressSingle
- }
-}
diff --git a/src/routes/v2/transaction.js b/src/routes/v2/transaction.js
deleted file mode 100644
index 3f8e8eb..0000000
--- a/src/routes/v2/transaction.js
+++ /dev/null
@@ -1,188 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("./route-utils")
-const logger = require("./logging.js")
-const wlogger = require("../../util/winston-logging")
-
-const BITBOXJS = require("@chris.troutner/bch-js")
-const BITBOX = new BITBOXJS()
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 3 }
-
-// Manipulates and formats the raw data comming from Insight API.
-const processInputs = tx => {
- // Add legacy and cashaddr to tx vin
- if (tx.vin) {
- tx.vin.forEach(vin => {
- if (!vin.coinbase) {
- vin.value = vin.valueSat
- const address = vin.addr
- if (address) {
- vin.legacyAddress = BITBOX.Address.toLegacyAddress(address)
- vin.cashAddress = BITBOX.Address.toCashAddress(address)
- delete vin.addr
- }
- delete vin.valueSat
- delete vin.doubleSpentTxID
- }
- })
- }
-
- // Add legacy and cashaddr to tx vout
- if (tx.vout) {
- tx.vout.forEach(vout => {
- // Overwrite value string with value in satoshis
- //vout.value = parseFloat(vout.value) * 100000000
-
- if (vout.scriptPubKey) {
- if (vout.scriptPubKey.addresses) {
- const cashAddrs = []
- vout.scriptPubKey.addresses.forEach(addr => {
- const cashAddr = BITBOX.Address.toCashAddress(addr)
- cashAddrs.push(cashAddr)
- })
- vout.scriptPubKey.cashAddrs = cashAddrs
- }
- }
- })
- }
-}
-
-router.get("/", root)
-router.post("/details", detailsBulk)
-router.get("/details/:txid", detailsSingle)
-
-function root(req, res, next) {
- return res.json({ status: "transaction" })
-}
-
-// Retrieve transaction data from the Insight API
-// This function is also used by the SLP route library.
-async function transactionsFromInsight(txid) {
- try {
- const path = `${process.env.BITCOINCOM_BASEURL}tx/${txid}`
-
- // Query the Insight server.
- const response = await axios.get(path)
- //console.log(`Insight output: ${JSON.stringify(response.data, null, 2)}`)
-
- // Parse the data.
- const parsed = response.data
- if (parsed) processInputs(parsed)
-
- return parsed
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-async function detailsBulk(req, res, next) {
- try {
- const txids = req.body.txids
-
- // Reject if address is not an array.
- if (!Array.isArray(txids)) {
- res.status(400)
- return res.json({ error: "txids needs to be an array" })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, txids)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- logger.debug(`Executing transaction/details with these txids: `, txids)
-
- // Collect an array of promises
- const promises = txids.map(
- async txid => await transactionsFromInsight(txid)
- )
-
- // Wait for all parallel promises to return.
- const result = await Promise.all(promises)
-
- // Return the array of retrieved transaction information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in transactions.ts/detailsBulk().`, err)
-
- //console.log(`Error in transaction details: `, err)
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler. Retrieve any unconfirmed TX information for a given address.
-async function detailsSingle(req, res, next) {
- try {
- const txid = req.params.txid
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: "txid can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(txid)) {
- res.status(400)
- return res.json({
- error: "txid can not be an array. Use POST for bulk upload."
- })
- }
-
- logger.debug(
- `Executing transaction.ts/detailsSingle with this txid: `,
- txid
- )
-
- // Query the Insight API.
- const retData = await transactionsFromInsight(txid)
- //console.log(`retData: ${JSON.stringify(retData,null,2)}`)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in transactions.ts/detailsSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- transactionsFromInsight,
- testableComponents: {
- root,
- detailsBulk,
- detailsSingle
- }
-}
diff --git a/src/routes/v2/util.js b/src/routes/v2/util.js
deleted file mode 100644
index fed94cc..0000000
--- a/src/routes/v2/util.js
+++ /dev/null
@@ -1,173 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("./route-utils")
-const logger = require("./logging.js")
-const wlogger = require("../../util/winston-logging")
-
-const BITBOXJS = require("@chris.troutner/bch-js")
-const BITBOX = new BITBOXJS()
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
-})
-
-const username = process.env.RPC_USERNAME
-const password = process.env.RPC_PASSWORD
-
-const requestConfig = {
- method: "post",
- auth: {
- username: username,
- password: password
- },
- data: {
- jsonrpc: "1.0"
- }
-}
-
-router.get("/", root)
-router.get("/validateAddress/:address", validateAddressSingle)
-router.post("/validateAddress", validateAddressBulk)
-
-function root(req, res, next) {
- return res.json({ status: "util" })
-}
-
-async function validateAddressSingle(req, res, next) {
- try {
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "validateaddress"
- requestConfig.data.method = "validateaddress"
- requestConfig.data.params = [address]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in util.ts/validateAddressSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function validateAddressBulk(req, res, next) {
- try {
- const addresses = req.body.addresses
-
- // Reject if addresses is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({
- error: "addresses needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the array.
- for (let i = 0; i < addresses.length; i++) {
- const address = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = BITBOX.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- logger.debug(`Executing util/validate with these addresses: `, addresses)
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each address and creates an array of requests to call in parallel
- const promises = addresses.map(async address => {
- requestConfig.data.id = "validateaddress"
- requestConfig.data.method = "validateaddress"
- requestConfig.data.params = [address]
-
- return await BitboxHTTP(requestConfig)
- })
-
- // Wait for all parallel Insight requests to return.
- const axiosResult = await axios.all(promises)
-
- // Retrieve the data part of the result.
- const result = axiosResult.map(x => x.data.result)
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in util.ts/validateAddressSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- validateAddressSingle,
- validateAddressBulk
- }
-}
From 9b5827752eaa3965b61f31789cb030e464b6a252 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Thu, 31 Oct 2019 14:37:54 -0700
Subject: [PATCH 07/49] feat(full-node): moved full node routes to their own
subdir
---
package.json | 1 -
src/app.js | 10 +-
src/routes/v3/{ => full-node}/blockchain.js | 4 +-
src/routes/v3/{ => full-node}/control.js | 4 +-
src/routes/v3/{ => full-node}/mining.js | 4 +-
src/routes/v3/{ => full-node}/network.js | 0
.../v3/{ => full-node}/rawtransactions.js | 4 +-
test/v2/address.js | 1373 -----------------
test/v2/block.js | 610 --------
test/v2/blockchain.js | 1148 --------------
test/v2/control.js | 140 --
test/v2/e2e/address.js | 60 -
test/v2/helpers/panda.js | 29 -
test/v2/integration/README.md | 7 -
test/v2/integration/rate-limits.js | 94 --
test/v2/integration/raw-transactions.js | 191 ---
test/v2/mining.js | 176 ---
test/v2/mocks/address-mock.js | 160 --
test/v2/mocks/block-mock.js | 42 -
test/v2/mocks/blockchain-mock.js | 271 ----
test/v2/mocks/control-mock.js | 27 -
test/v2/mocks/express-mocks.js | 88 --
test/v2/mocks/mining-mocks.js | 22 -
test/v2/mocks/raw-transactions-mocks.js | 157 --
test/v2/mocks/slp-mocks.js | 327 ----
test/v2/mocks/slpjs-mocks.js | 71 -
test/v2/mocks/transaction-mocks.js | 74 -
test/v2/mocks/util-mocks.js | 18 -
test/v2/rate-limits.js | 166 --
test/v2/raw-transactions.js | 807 ----------
test/v2/slp.js | 971 ------------
test/v2/transaction.js | 333 ----
test/v2/util.js | 300 ----
test/v3/blockchain.js | 2 +-
test/v3/control.js | 2 +-
test/v3/mining.js | 2 +-
test/v3/rate-limits.js | 2 +-
test/v3/raw-transactions.js | 2 +-
38 files changed, 18 insertions(+), 7681 deletions(-)
rename src/routes/v3/{ => full-node}/blockchain.js (99%)
rename src/routes/v3/{ => full-node}/control.js (96%)
rename src/routes/v3/{ => full-node}/mining.js (97%)
rename src/routes/v3/{ => full-node}/network.js (100%)
rename src/routes/v3/{ => full-node}/rawtransactions.js (99%)
delete mode 100644 test/v2/address.js
delete mode 100644 test/v2/block.js
delete mode 100644 test/v2/blockchain.js
delete mode 100644 test/v2/control.js
delete mode 100644 test/v2/e2e/address.js
delete mode 100644 test/v2/helpers/panda.js
delete mode 100644 test/v2/integration/README.md
delete mode 100644 test/v2/integration/rate-limits.js
delete mode 100644 test/v2/integration/raw-transactions.js
delete mode 100644 test/v2/mining.js
delete mode 100644 test/v2/mocks/address-mock.js
delete mode 100644 test/v2/mocks/block-mock.js
delete mode 100644 test/v2/mocks/blockchain-mock.js
delete mode 100644 test/v2/mocks/control-mock.js
delete mode 100644 test/v2/mocks/express-mocks.js
delete mode 100644 test/v2/mocks/mining-mocks.js
delete mode 100644 test/v2/mocks/raw-transactions-mocks.js
delete mode 100644 test/v2/mocks/slp-mocks.js
delete mode 100644 test/v2/mocks/slpjs-mocks.js
delete mode 100644 test/v2/mocks/transaction-mocks.js
delete mode 100644 test/v2/mocks/util-mocks.js
delete mode 100644 test/v2/rate-limits.js
delete mode 100644 test/v2/raw-transactions.js
delete mode 100644 test/v2/slp.js
delete mode 100644 test/v2/transaction.js
delete mode 100644 test/v2/util.js
diff --git a/package.json b/package.json
index 36617f3..cd1070c 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,6 @@
"start": "node ./src/app.js",
"dev": "nodemon ./dist/app.js",
"test": "npm run test-v3",
- "test-v2": "export NETWORK=testnet && nyc --reporter=text mocha --timeout 25000 test/v2/",
"test-v3": "export NETWORK=mainnet && nyc --reporter=text mocha --timeout 25000 test/v3/",
"test:integration": "mocha test/v3/integration",
"coverage": "nyc report --reporter=text-lcov | coveralls",
diff --git a/src/app.js b/src/app.js
index f9114df..99a8a29 100644
--- a/src/app.js
+++ b/src/app.js
@@ -22,11 +22,11 @@ const jwtAuth = require("./middleware/jwt-auth")
// v3
const healthCheckV3 = require("./routes/v3/health-check")
-const blockchainV3 = require("./routes/v3/blockchain")
-const controlV3 = require("./routes/v3/control")
-const miningV3 = require("./routes/v3/mining")
-const networkV3 = require("./routes/v3/network")
-const rawtransactionsV3 = require("./routes/v3/rawtransactions")
+const blockchainV3 = require("./routes/v3/full-node/blockchain")
+const controlV3 = require("./routes/v3/full-node/control")
+const miningV3 = require("./routes/v3/full-node/mining")
+const networkV3 = require("./routes/v3/full-node/network")
+const rawtransactionsV3 = require("./routes/v3/full-node/rawtransactions")
const utilV3 = require("./routes/v3/util")
const slpV3 = require("./routes/v3/slp")
const xpubV3 = require("./routes/v3/xpub")
diff --git a/src/routes/v3/blockchain.js b/src/routes/v3/full-node/blockchain.js
similarity index 99%
rename from src/routes/v3/blockchain.js
rename to src/routes/v3/full-node/blockchain.js
index 092e8bf..8e2403b 100644
--- a/src/routes/v3/blockchain.js
+++ b/src/routes/v3/full-node/blockchain.js
@@ -9,8 +9,8 @@ const express = require("express")
const router = express.Router()
const axios = require("axios")
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
+const routeUtils = require("../route-utils")
+const wlogger = require("../../../util/winston-logging")
// Used to convert error messages to strings, to safely pass to users.
const util = require("util")
diff --git a/src/routes/v3/control.js b/src/routes/v3/full-node/control.js
similarity index 96%
rename from src/routes/v3/control.js
rename to src/routes/v3/full-node/control.js
index 6a3f6ee..e2e6374 100644
--- a/src/routes/v3/control.js
+++ b/src/routes/v3/full-node/control.js
@@ -4,8 +4,8 @@ const express = require("express")
const router = express.Router()
const axios = require("axios")
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
+const routeUtils = require("../route-utils")
+const wlogger = require("../../../util/winston-logging")
// Used for processing error messages before sending them to the user.
const util = require("util")
diff --git a/src/routes/v3/mining.js b/src/routes/v3/full-node/mining.js
similarity index 97%
rename from src/routes/v3/mining.js
rename to src/routes/v3/full-node/mining.js
index 60f48d6..daa6c10 100644
--- a/src/routes/v3/mining.js
+++ b/src/routes/v3/full-node/mining.js
@@ -4,8 +4,8 @@ const express = require("express")
const router = express.Router()
const axios = require("axios")
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
+const routeUtils = require("../route-utils")
+const wlogger = require("../../../util/winston-logging")
// Used to convert error messages to strings, to safely pass to users.
const util = require("util")
diff --git a/src/routes/v3/network.js b/src/routes/v3/full-node/network.js
similarity index 100%
rename from src/routes/v3/network.js
rename to src/routes/v3/full-node/network.js
diff --git a/src/routes/v3/rawtransactions.js b/src/routes/v3/full-node/rawtransactions.js
similarity index 99%
rename from src/routes/v3/rawtransactions.js
rename to src/routes/v3/full-node/rawtransactions.js
index d72beb9..7ae5998 100644
--- a/src/routes/v3/rawtransactions.js
+++ b/src/routes/v3/full-node/rawtransactions.js
@@ -4,8 +4,8 @@ const express = require("express")
const router = express.Router()
const axios = require("axios")
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
+const routeUtils = require("../route-utils")
+const wlogger = require("../../../util/winston-logging")
// Used to convert error messages to strings, to safely pass to users.
const util = require("util")
diff --git a/test/v2/address.js b/test/v2/address.js
deleted file mode 100644
index 070c5d9..0000000
--- a/test/v2/address.js
+++ /dev/null
@@ -1,1373 +0,0 @@
-/*
- TESTS FOR THE ADDRESS.JS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- To-Do:
- -/details/:address
- --Verify to/from query options work correctly.
- -GET /unconfirmed/:address & POST /unconfirmed
- --Should initiate a transfer of BCH to verify unconfirmed TX.
- ---This would be more of an e2e test.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const addressRoute = require("../../src/routes/v2/address")
-const nock = require("nock") // HTTP mocking
-
-let originalUrl // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/address-mock")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#AddressRouter", () => {
- let req, res
-
- before(() => {
- originalUrl = process.env.BITCOINCOM_BASEURL
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit")
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- // console.log(`Testing type is: ${process.env.TEST}`)
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- process.env.BITCOINCOM_BASEURL = originalUrl
- })
-
- describe("#root", () => {
- // root route handler.
- const root = addressRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
-
- assert.equal(result.status, "address", "Returns static string")
- })
- })
-
- describe("#AddressDetailsBulk", () => {
- // details route handler.
- const detailsBulk = addressRoute.testableComponents.detailsBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsBulk(req, res)
- //console.log(`network issue result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(res.statusCode, 499, "HTTP status code 500 expected.")
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- assert.include(
- result.error,
- "Network error: Could not communicate",
- "Error message expected"
- )
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert current page defaults to 0
- assert.equal(result[0].currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`],
- page: 5
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=5000&to=6000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert current page is same as requested
- assert.equal(result[0].currentPage, 5)
- })
-
- it("should calculate the total number of pages", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result[0].pagesTotal, 1)
- })
-
- it("should get details for a single address", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.equal(result.length, 1, "Array with one entry")
- assert.hasAllKeys(result[0], [
- "balance",
- "balanceSat",
- "totalReceived",
- "totalReceivedSat",
- "totalSent",
- "totalSentSat",
- "unconfirmedBalance",
- "unconfirmedBalanceSat",
- "unconfirmedTxApperances",
- "txApperances",
- "transactions",
- "legacyAddress",
- "cashAddress",
- "currentPage",
- "pagesTotal"
- ])
- })
-
- it("should get details for multiple addresses", async () => {
- req.body = {
- addresses: [
- `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`,
- `bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mwJnEzXzKkveF2q5Af9jxi9j1zrtWAnPU8?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
- })
-
- describe("#AddressDetailsSingle", () => {
- // details route handler.
- const detailsSingle = addressRoute.testableComponents.detailsSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert current page defaults to 0
- assert.equal(result.currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
- req.query.page = 5
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=5000&to=6000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
-
- // Assert current page is same as requested
- assert.equal(result.currentPage, 5)
- })
-
- it("should calculate the total number of pages", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
-
- assert.equal(result.pagesTotal, 1)
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.hasAllKeys(result, [
- "balance",
- "balanceSat",
- "totalReceived",
- "totalReceivedSat",
- "totalSent",
- "totalSentSat",
- "unconfirmedBalance",
- "unconfirmedBalanceSat",
- "unconfirmedTxApperances",
- "txApperances",
- "transactions",
- "legacyAddress",
- "cashAddress",
- "currentPage",
- "pagesTotal"
- ])
- })
- })
-
- describe("#AddressUtxoBulk", () => {
- // utxo route handler.
- const utxoBulk = addressRoute.testableComponents.utxoBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`]
- }
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api"
-
- const result = await utxoBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get utxos for a single address", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz/utxo`)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await utxoBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result, "result should be an array")
-
- // Each element should have these primary properties.
- assert.hasAllKeys(result[0], [
- "utxos",
- "legacyAddress",
- "cashAddress",
- "scriptPubKey"
- ])
-
- // Validate the UTXO data structure.
- assert.hasAnyKeys(result[0].utxos[0], [
- "txid",
- "vout",
- "amount",
- "satoshis",
- "height",
- "confirmations"
- ])
- })
-
- it("should get utxos for mulitple addresses", async () => {
- req.body = {
- addresses: [
- `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`,
- `bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz/utxo`)
- .reply(200, mockData.mockUtxoDetails)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mwJnEzXzKkveF2q5Af9jxi9j1zrtWAnPU8/utxo`)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await utxoBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await utxoBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
- })
-
- describe("#AddressUtxoSingle", () => {
- // details route handler.
- const utxoSingle = addressRoute.testableComponents.utxoSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await utxoSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await utxoSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await utxoSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`
-
- const result = await utxoSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await utxoSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz/utxo`)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await utxoSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Each element should have these primary properties.
- assert.hasAllKeys(result, [
- "utxos",
- "legacyAddress",
- "cashAddress",
- "scriptPubKey"
- ])
-
- // Validate the UTXO data structure.
- assert.hasAnyKeys(result.utxos[0], [
- "txid",
- "vout",
- "amount",
- "satoshis",
- "height",
- "confirmations"
- ])
- })
- })
-
- describe("#AddressUnconfirmedBulk", () => {
- // unconfirmed route handler.
- const unconfirmedBulk = addressRoute.testableComponents.unconfirmedBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
- }
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await unconfirmedBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`]
- }
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api"
-
- const result = await unconfirmedBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get unconfirmed data for a single address", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz/utxo`)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await unconfirmedBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
- //console.log(`result[0].utxos: ${util.inspect(result[0].utxos)}`)
-
- assert.isArray(result, "result should be an array")
-
- // Dev note: Unconfirmed TXs are hard to test in an integration test because
- // the nature of an unconfirmed transation is transient. It quickly becomes
- // confirmed and thus should not show up.
- })
-
- it("should get unconfirmed data for an array of addresses", async () => {
- req.body = {
- addresses: [
- `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`,
- `bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz/utxo`)
- .reply(200, mockData.mockUtxoDetails)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mwJnEzXzKkveF2q5Af9jxi9j1zrtWAnPU8/utxo`)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await unconfirmedBulk(req, res)
-
- assert.isArray(result)
- })
- })
-
- describe("#AddressUnconfirmedSingle", () => {
- // details route handler.
- const unconfirmedSingle = addressRoute.testableComponents.unconfirmedSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await unconfirmedSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await unconfirmedSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await unconfirmedSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`
-
- const result = await unconfirmedSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await unconfirmedSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz/utxo`)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await unconfirmedSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Each element should have these primary properties.
- assert.hasAllKeys(result, [
- "utxos",
- "legacyAddress",
- "cashAddress",
- "scriptPubKey"
- ])
-
- assert.isArray(result.utxos)
- })
- })
-
- describe("#AddressTransactionsBulk", () => {
- // unconfirmed route handler.
- const transactionsBulk = addressRoute.testableComponents.transactionsBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await transactionsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`]
- }
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api"
-
- const result = await transactionsBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsBulk(req, res)
-
- // Assert current page defaults to 0
- assert.equal(result[0].currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`],
- page: 5
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=5`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsBulk(req, res)
-
- // Assert current page is same as requested
- assert.equal(result[0].currentPage, 5)
- })
-
- it("should get transactions for a single address", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the details API.
- const result = await transactionsBulk(req, res)
-
- assert.isArray(result, "result should be an array")
-
- assert.exists(result[0].pagesTotal)
- assert.exists(result[0].currentPage)
- assert.exists(result[0].txs)
- assert.isArray(result[0].txs)
- assert.exists(result[0].legacyAddress)
- assert.exists(result[0].cashAddress)
- })
-
- it("should get transactions for an array of addresses", async () => {
- req.body = {
- addresses: [
- `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`,
- `bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- )
- .reply(200, mockData.mockTransactions)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr&pageNum=0`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the details API.
- const result = await transactionsBulk(req, res)
-
- assert.isArray(result, "result should be an array")
-
- assert.equal(result.length, 2, "Array should have 2 elements")
- })
- })
-
- describe("#AddressTransactionsSingle", () => {
- // details route handler.
- const transactionsSingle =
- addressRoute.testableComponents.transactionsSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await transactionsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await transactionsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await transactionsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`
-
- const result = await transactionsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await transactionsSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsSingle(req, res)
-
- // Assert current page defaults to 0
- assert.equal(result.currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
- req.query.page = 5
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=5`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsSingle(req, res)
-
- // Assert current page is same as requested
- assert.equal(result.currentPage, 5)
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the details API.
- const result = await transactionsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.exists(result.pagesTotal)
- assert.exists(result.currentPage)
- assert.exists(result.txs)
- assert.isArray(result.txs)
- assert.exists(result.legacyAddress)
- assert.exists(result.cashAddress)
- })
- })
-
- describe("#AddressFromXPubSingle", () => {
- // details route handler.
- const fromXPubSingle = addressRoute.testableComponents.fromXPubSingle
-
- it("should throw 400 if xpub is empty", async () => {
- const result = await fromXPubSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "xpub can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.xpub = [
- `tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
- ]
-
- const result = await fromXPubSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "xpub can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.xpub = `tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await fromXPubSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should create an address from xpub", async () => {
- req.params.xpub = `tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
-
- // Mock the Insight URL for unit tests.
- // TODO add unit test
- // if (process.env.TEST === "unit") {
- // nock(`${process.env.BITCOINCOM_BASEURL}`)
- // .get(
- // `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- // )
- // .reply(200, mockData.mockTransactions)
- // }
-
- // Call the details API.
- const result = await fromXPubSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.exists(result.legacyAddress)
- assert.exists(result.cashAddress)
- })
- })
-})
diff --git a/test/v2/block.js b/test/v2/block.js
deleted file mode 100644
index 3817e62..0000000
--- a/test/v2/block.js
+++ /dev/null
@@ -1,610 +0,0 @@
-"use strict"
-
-const blockRoute = require("../../src/routes/v2/block")
-const chai = require("chai")
-const assert = chai.assert
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/block-mock")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Block", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", () => {
- // root route handler.
- const root = blockRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
-
- assert.equal(result.status, "block", "Returns static string")
- })
- })
-
- describe("#detailsByHashSingle", () => {
- const detailsByHash = blockRoute.testableComponents.detailsByHashSingle
-
- it("should throw an error for an empty hash", async () => {
- req.params.hash = ""
-
- const result = await detailsByHash(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hash must not be empty",
- "Proper error message"
- )
- })
-
- it("should throw 50X when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- req.params.hash = "abc123"
- const result = await detailsByHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(res.statusCode, 499, "HTTP status code 50X expected.")
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- })
-
- it("should throw an error for invalid hash", async () => {
- req.params.hash = "abc123"
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.params.hash}`)
- .reply(404, "Not found")
- }
-
- const result = await detailsByHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.include(result.error, "Not found", "Proper error message")
- })
-
- it("should GET /detailsByHash/:hash", async () => {
- req.params.hash =
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.params.hash}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- const result = await detailsByHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "hash",
- "size",
- "height",
- "version",
- "merkleroot",
- "tx",
- "time",
- "nonce",
- "bits",
- "difficulty",
- "chainwork",
- "confirmations",
- "previousblockhash",
- "nextblockhash",
- "reward",
- "isMainChain",
- "poolInfo"
- ])
- assert.isArray(result.tx)
- })
- })
-
- describe("#detailsByHashBulk", () => {
- // details route handler.
- const detailsByHashBulk = blockRoute.testableComponents.detailsByHashBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsByHashBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hashes needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- hashes:
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
- }
-
- const result = await detailsByHashBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hashes needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.hashes = testArray
-
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw an error for an invalid hash", async () => {
- req.body = {
- hashes: [`abc123`]
- }
-
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid hash", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- hashes: [
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
- ]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsByHashBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single hash", async () => {
- req.body = {
- hashes: [
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[0]}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.equal(result.length, 1, "Array with one entry")
- assert.hasAllKeys(result[0], [
- "bits",
- "chainwork",
- "confirmations",
- "difficulty",
- "hash",
- "height",
- "isMainChain",
- "merkleroot",
- "nextblockhash",
- "nonce",
- "poolInfo",
- "previousblockhash",
- "reward",
- "size",
- "time",
- "tx",
- "version"
- ])
- })
-
- it("should get details for multiple hashes", async () => {
- req.body = {
- hashes: [
- `00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79`,
- `00000000c2b2c19cf499f57d5b0f724c6df753330d7acc7d4a8ebe412d427bd0`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[0]}`)
- .reply(200, mockData.mockBlockDetails)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[1]}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
-
- it("should throw an error if hash not found", async () => {
- req.body = {
- hashes: [
- `00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44abcdef`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[0]}`)
- //.reply(404, { error: { message: "Not Found" } })
- .reply(404, "Not found")
- }
-
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 404, "HTTP status code 404 expected.")
- assert.include(result.error, "Not found", "Proper error message")
- })
- })
-
- describe("Block Details By Height", () => {
- // block route handler.
- const detailsByHeight = blockRoute.testableComponents.detailsByHeightSingle
-
- it("should throw an error for an empty height", async () => {
- req.params.height = ""
-
- const result = await detailsByHeight(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "height must not be empty",
- "Proper error message"
- )
- })
-
- it("should throw 500 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl = process.env.BITCOINCOM_BASEURL
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.height = "abc123"
- const result = await detailsByHeight(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or great expected."
- )
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- })
-
- it("should throw an error for invalid height", async () => {
- req.params.height = "abc123"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(500, {
- error: {
- code: -1,
- message: "JSON value is not an integer as expected"
- }
- })
- }
-
- const result = await detailsByHeight(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "JSON value is not an integer as expected",
- "Proper error message"
- )
- })
-
- it("should GET /detailsByHeight/:height", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockHash })
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/block/00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79`
- )
- .reply(200, mockData.mockBlockDetails)
- }
-
- req.params.height = 500000
-
- const result = await detailsByHeight(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "hash",
- "size",
- "height",
- "version",
- "merkleroot",
- "tx",
- "time",
- "nonce",
- "bits",
- "difficulty",
- "chainwork",
- "confirmations",
- "previousblockhash",
- "nextblockhash",
- "reward",
- "isMainChain",
- "poolInfo"
- ])
- assert.isArray(result.tx)
- })
- })
-
- describe("#detailsByHeightBulk", () => {
- // details route handler.
- const detailsByHeightBulk =
- blockRoute.testableComponents.detailsByHeightBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsByHeightBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "heights needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single height", async () => {
- req.body = {
- heights: 500000
- }
-
- const result = await detailsByHeightBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "heights needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.heights = testArray
-
- const result = await detailsByHeightBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw error for an invalid height", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(500, {
- error: {
- code: -1,
- message: "JSON value is not an integer as expected"
- }
- })
- }
-
- req.body.heights = [`abc123`]
-
- const result = await detailsByHeightBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body.heights = [`500000`]
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsByHeightBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single height", async () => {
- req.body.heights = [`500000`]
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockHash })
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${mockData.mockBlockHash}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHeightBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.equal(result.length, 1, "Array with one entry")
- assert.hasAllKeys(result[0], [
- "bits",
- "chainwork",
- "confirmations",
- "difficulty",
- "hash",
- "height",
- "isMainChain",
- "merkleroot",
- "nextblockhash",
- "nonce",
- "poolInfo",
- "previousblockhash",
- "reward",
- "size",
- "time",
- "tx",
- "version"
- ])
- })
-
- it("should get details for multiple block heights", async () => {
- req.body = {
- heights: [`500000`, `500001`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: mockData.mockBlockHash })
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${mockData.mockBlockHash}`)
- .times(2)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHeightBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
- })
-})
diff --git a/test/v2/blockchain.js b/test/v2/blockchain.js
deleted file mode 100644
index a2b4458..0000000
--- a/test/v2/blockchain.js
+++ /dev/null
@@ -1,1148 +0,0 @@
-/*
- TODO:
- -getRawMempool
- --Add tests for 'verbose' input values
- -getMempoolEntry & getMempoolEntryBulk
- --Needs e2e test to create unconfirmed tx, for real-world test.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const nock = require("nock") // HTTP mocking
-const blockchainRoute = require("../../src/routes/v2/blockchain")
-
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-if (!process.env.TEST) process.env.TEST = "unit"
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/blockchain-mock")
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-describe("#BlockchainRouter", () => {
- let req, res
-
- // local node will be started in regtest mode on the port 48332
- //before(panda.runLocalNode)
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // otherwise the panda will run forever
- //process.exit()
-
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", () => {
- // root route handler.
- const root = blockchainRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
-
- assert.equal(result.status, "blockchain", "Returns static string")
- })
- })
-
- describe("getBestBlockHash()", () => {
- // block route handler.
- const getBestBlockHash = blockchainRoute.testableComponents.getBestBlockHash
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getBestBlockHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getBestBlockHash", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockHash })
- }
-
- const result = await getBestBlockHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isString(result)
- assert.equal(result.length, 64, "Hash string is fixed length")
- })
- })
-
- describe("getBlockchainInfo()", () => {
- // block route handler.
- const getBlockchainInfo =
- blockchainRoute.testableComponents.getBlockchainInfo
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getBlockchainInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getBlockchainInfo", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockchainInfo })
- }
-
- const result = await getBlockchainInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "chain",
- "blocks",
- "headers",
- "bestblockhash",
- "difficulty",
- "mediantime",
- "verificationprogress",
- "chainwork",
- "pruned",
- "softforks",
- "bip9_softforks"
- ])
- })
- })
-
- describe("getBlockCount()", () => {
- // block route handler.
- const getBlockCount = blockchainRoute.testableComponents.getBlockCount
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getBlockCount(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getBlockCount", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: 126769 })
- }
-
- const result = await getBlockCount(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isNumber(result)
- })
- })
-
- describe("getBlockHeaderSingle()", async () => {
- const getBlockHeader =
- blockchainRoute.testableComponents.getBlockHeaderSingle
-
- it("should throw 400 error if hash is missing", async () => {
- const result = await getBlockHeader(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "hash can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.hash =
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
-
- const result = await getBlockHeader(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Network error: Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET block header", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, {
- result:
- "0000ff7f7d217c9b7845ea8b50d620c59a1bf7c276566406e9b7bc7e463e0000000000006d70322c0b697c1c81d2744f87f09f1e9780ba5d30338952e2cdc64e60456f8423bb0a5ceafa091a3e843526"
- })
- }
-
- req.params.hash =
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
-
- const result = await getBlockHeader(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isString(result)
- assert.equal(
- result,
- "0000ff7f7d217c9b7845ea8b50d620c59a1bf7c276566406e9b7bc7e463e0000000000006d70322c0b697c1c81d2744f87f09f1e9780ba5d30338952e2cdc64e60456f8423bb0a5ceafa091a3e843526"
- )
- })
-
- it("should GET verbose block header", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockHeader })
- }
-
- req.query.verbose = true
- req.params.hash =
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
-
- const result = await getBlockHeader(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, [
- "hash",
- "confirmations",
- "height",
- "version",
- "versionHex",
- "merkleroot",
- "time",
- "mediantime",
- "nonce",
- "bits",
- "difficulty",
- "chainwork",
- "previousblockhash",
- "nextblockhash"
- ])
- })
- })
-
- describe("#getBlockHeaderBulk", () => {
- // route handler.
- const getBlockHeaderBulk =
- blockchainRoute.testableComponents.getBlockHeaderBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await getBlockHeaderBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hashes needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single hash", async () => {
- req.body.hashes =
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
-
- const result = await getBlockHeaderBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hashes needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.hashes = testArray
-
- const result = await getBlockHeaderBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw a 400 error for an invalid hash", async () => {
- req.body.hashes = ["badHash"]
-
- await getBlockHeaderBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body.hashes = [
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
- ]
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await getBlockHeaderBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get concise block header for a single hash", async () => {
- req.body.hashes = [
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
- ]
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockHeaderConcise })
- }
-
- // Call the details API.
- const result = await getBlockHeaderBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.isArray(result)
- assert.equal(
- result[0],
- "0000ff7f7d217c9b7845ea8b50d620c59a1bf7c276566406e9b7bc7e463e0000000000006d70322c0b697c1c81d2744f87f09f1e9780ba5d30338952e2cdc64e60456f8423bb0a5ceafa091a3e843526"
- )
- })
-
- it("should get verbose block header for a single hash", async () => {
- req.body = {
- hashes: [
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
- ],
- verbose: true
- }
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockHeader })
- }
-
- // Call the details API.
- const result = await getBlockHeaderBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "hash",
- "confirmations",
- "height",
- "version",
- "versionHex",
- "merkleroot",
- "time",
- "mediantime",
- "nonce",
- "bits",
- "difficulty",
- "chainwork",
- "previousblockhash",
- "nextblockhash"
- ])
- })
-
- it("should get details for multiple block heights", async () => {
- req.body.hashes = [
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900",
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
- ]
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: mockData.mockBlockHeaderConcise })
- }
-
- // Call the details API.
- const result = await getBlockHeaderBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
- })
-
- describe("getChainTips()", () => {
- // block route handler.
- const getChainTips = blockchainRoute.testableComponents.getChainTips
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getChainTips(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getChainTips", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockChainTips })
- }
-
- const result = await getChainTips(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], ["height", "hash", "branchlen", "status"])
- })
- })
-
- describe("getDifficulty()", () => {
- // block route handler.
- const getDifficulty = blockchainRoute.testableComponents.getDifficulty
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getDifficulty(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getDifficulty", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: 4049809.205246544 })
- }
-
- const result = await getDifficulty(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isNumber(result)
- })
- })
-
- describe("getMempoolInfo()", () => {
- // block route handler.
- const getMempoolInfo = blockchainRoute.testableComponents.getMempoolInfo
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getMempoolInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getMempoolInfo", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockMempoolInfo })
- }
-
- const result = await getMempoolInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "result",
- "bytes",
- "usage",
- "maxmempool",
- "mempoolminfree"
- ])
- })
- })
-
- describe("getRawMempool()", () => {
- // block route handler.
- const getRawMempool = blockchainRoute.testableComponents.getRawMempool
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getRawMempool(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getMempoolInfo", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockRawMempool })
- }
-
- const result = await getRawMempool(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- // Not sure what other assertions should be made here.
- })
- })
-
- describe("getMempoolEntry()", () => {
- // block route handler.
- const getMempoolEntry =
- blockchainRoute.testableComponents.getMempoolEntrySingle
-
- it("should throw 400 if txid is empty", async () => {
- const result = await getMempoolEntry(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.txid = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
-
- const result = await getMempoolEntry(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getMempoolEntry", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: { error: "Transaction not in mempool" } })
- }
-
- req.params.txid = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
-
- const result = await getMempoolEntry(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.isString(result.error)
- assert.equal(result.error, "Transaction not in mempool")
- })
- })
-
- describe("#getMempoolEntryBulk", () => {
- // route handler.
- const getMempoolEntryBulk =
- blockchainRoute.testableComponents.getMempoolEntryBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await getMempoolEntryBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single txid", async () => {
- req.body.txids = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
-
- const result = await getMempoolEntryBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.txids = testArray
-
- const result = await getMempoolEntryBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- // Only execute on integration tests.
- if (process.env.TEST !== "unit") {
- // Dev-note: This test passes because it expects an error. TXIDs do not
- // stay in the mempool for long, so it does not work well for a unit or
- // integration test.
- it("should retrieve single mempool entry", async () => {
- req.body.txids = [
- `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
- ]
-
- const result = await getMempoolEntryBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.isString(result.error)
- assert.equal(result.error, "Transaction not in mempool")
- })
-
- // Dev-note: This test passes because it expects an error. TXIDs do not
- // stay in the mempool for long, so it does not work well for a unit or
- // integration test.
- it("should retrieve multiple mempool entries", async () => {
- req.body.txids = [
- `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`,
- `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
- ]
-
- const result = await getMempoolEntryBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.isString(result.error)
- assert.equal(result.error, "Transaction not in mempool")
- })
- }
- })
-
- describe("getTxOut()", () => {
- // block route handler.
- const getTxOut = blockchainRoute.testableComponents.getTxOut
-
- it("should throw 400 if txid is empty", async () => {
- const result = await getTxOut(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should throw 400 if n is empty", async () => {
- req.params.txid = `sometxid`
- const result = await getTxOut(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "n can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.txid = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
- req.params.n = 0
-
- const result = await getTxOut(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- // This test can only run for unit tests. See TODO at the top of this file.
- it("should GET /getTxOut", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockTxOut })
- }
-
- req.params.txid = `5747e6462e2c452a5d583fd6a5f82866cd8e4a86826c86d9a1842b7d023e0c0c`
- req.params.n = 1
-
- const result = await getTxOut(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.hasAllKeys(result, [
- "bestblock",
- "confirmations",
- "value",
- "scriptPubKey",
- "coinbase"
- ])
- assert.hasAllKeys(result.scriptPubKey, [
- "asm",
- "hex",
- "reqSigs",
- "type",
- "addresses"
- ])
- assert.isArray(result.scriptPubKey.addresses)
- })
- })
-
- describe("getTxOutProof()", () => {
- const getTxOutProof = blockchainRoute.testableComponents.getTxOutProofSingle
-
- it("should throw 400 if txid is empty", async () => {
- const result = await getTxOutProof(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.txid = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
-
- const result = await getTxOutProof(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getTxOutProof", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockTxOutProof })
- }
-
- req.params.txid = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
-
- const result = await getTxOutProof(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.isString(result)
- })
- })
-
- describe("#getTxOutProofBulk", () => {
- // route handler.
- const getTxOutProofBulk =
- blockchainRoute.testableComponents.getTxOutProofBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await getTxOutProofBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single txid", async () => {
- req.body.txids = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
-
- const result = await getTxOutProofBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.txids = testArray
-
- const result = await getTxOutProofBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should GET proof for single txid", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockTxOutProof })
- }
-
- req.body.txids = [
- `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
- ]
-
- const result = await getTxOutProofBulk(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.isArray(result)
- assert.isString(result[0])
- })
-
- it("should GET proof for multiple txids", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: mockData.mockTxOutProof })
- }
-
- req.body.txids = [
- `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`,
- `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
- ]
-
- const result = await getTxOutProofBulk(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "Correct length of returned array")
- })
- })
-
- describe("verifyTxOutProof()", () => {
- const verifyTxOutProof =
- blockchainRoute.testableComponents.verifyTxOutProofSingle
-
- it("should throw 400 if proof is empty", async () => {
- const result = await verifyTxOutProof(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "proof can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.proof = mockData.mockTxOutProof
-
- const result = await verifyTxOutProof(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /verifyTxOutProof", async () => {
- const expected =
- "d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: [expected] })
- }
-
- req.params.proof = mockData.mockTxOutProof
-
- const result = await verifyTxOutProof(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.isArray(result)
- assert.isString(result[0])
- assert.equal(result[0], expected)
- })
- })
-
- describe("#verifyTxOutProofBulk", () => {
- // route handler.
- const verifyTxOutProofBulk =
- blockchainRoute.testableComponents.verifyTxOutProofBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await verifyTxOutProofBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "proofs needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single txid", async () => {
- req.body.proofs = mockData.mockTxOutProof
-
- const result = await verifyTxOutProofBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "proofs needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.proofs = testArray
-
- const result = await verifyTxOutProofBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should get single proof", async () => {
- const expected =
- "d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: [expected] })
- }
-
- req.body.proofs = [mockData.mockTxOutProof]
-
- const result = await verifyTxOutProofBulk(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.isArray(result)
- assert.isString(result[0])
- assert.equal(result[0], expected)
- })
-
- it("should get multiple proofs", async () => {
- const expected =
- "d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: [expected] })
- }
-
- req.body.proofs = [mockData.mockTxOutProof, mockData.mockTxOutProof]
-
- const result = await verifyTxOutProofBulk(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.isArray(result)
- assert.isString(result[0])
- assert.equal(result[0], expected)
- assert.equal(result.length, 2)
- })
- })
-})
diff --git a/test/v2/control.js b/test/v2/control.js
deleted file mode 100644
index e5deaa9..0000000
--- a/test/v2/control.js
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- TESTS FOR THE CONTROL.JS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const controlRoute = require("../../src/routes/v2/control")
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/control-mock")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#ControlRouter", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = controlRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "control", "Returns static string")
- })
- })
-
- describe("#GetInfo", () => {
- const getInfo = controlRoute.testableComponents.getInfo
-
- it("should throw 500 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- })
-
- it("should get info on the full node", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockGetInfo })
- }
-
- const result = await getInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "version",
- "protocolversion",
- "blocks",
- "timeoffset",
- "connections",
- "proxy",
- "difficulty",
- "testnet",
- "paytxfee",
- "relayfee",
- "errors"
- ])
- })
- })
-})
diff --git a/test/v2/e2e/address.js b/test/v2/e2e/address.js
deleted file mode 100644
index 878ad9e..0000000
--- a/test/v2/e2e/address.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- End-to-end tests for the Address endpoint.
- These tests assume that the repo is running locally and pointed at TESTNET
-*/
-
-"use strict"
-
-const rp = require("request-promise")
-
-const rawtransactions = require("../../../dist/routes/v2/address")
-
-/*
- This unconfirmed utxo test needs to be expanded in the future to automatically
- create a transaction. For now, that is done manually and the address provided
- as a constant.
-
- 1. Start rest running locally, pointed at TESTNET.
- 2. Fund each address with a small amount of tBCH
- 3. Run this program with `node address.js`
- 4. If successful, it will return the unconfirmed UTXOs.
-*/
-const addr1 = "bchtest:qpdcp5pv7qphu5tsjfgwezld9n9aq9ue6swgqpf45c"
-const addr2 = "bchtest:qzpvx999fagau0xqmvu3xvll9evapge7u5hcgeknzv"
-
-async function testSingleUnconfirmed() {
- try {
- const options = {
- method: "GET",
- uri: `http://localhost:3000/v2/address/unconfirmed/${addr1}`,
- resolveWithFullResponse: true,
- json: true
- }
-
- const result = await rp(options)
- // console.log(`result.body: ${JSON.stringify(result.body, null, 2)}`)
- } catch (err) {
- // console.log(`Error: `, err)
- }
-}
-testSingleUnconfirmed()
-
-async function testDoubleUnconfirmed() {
- try {
- const options = {
- method: "POST",
- uri: `http://localhost:3000/v2/address/unconfirmed`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- addresses: [addr1, addr2]
- }
- }
-
- const result = await rp(options)
- // console.log(`result.body: ${JSON.stringify(result.body, null, 2)}`)
- } catch (err) {
- // console.log(`Error: `, err)
- }
-}
-testDoubleUnconfirmed()
diff --git a/test/v2/helpers/panda.js b/test/v2/helpers/panda.js
deleted file mode 100644
index 48a7d7f..0000000
--- a/test/v2/helpers/panda.js
+++ /dev/null
@@ -1,29 +0,0 @@
-"use strict"
-
-/**
- * Read more about panda here: https://panda-suite.github.io/
- */
-const panda = require("pandacash-core")
-
-const runLocalNode = done => {
- const server = panda.server({
- // always the same mnemonic
- // mnemonic: "cigar magnet ocean purchase travel damp snack alone theme budget wagon wrong",
- seedAccounts: true,
- enableLogs: false,
- debug: false
- })
-
- server.listen({
- port: 48332,
- walletPort: 48333,
- }, (err, pandaCashCore) => {
- if (err) return console.error(err)
-
- done()
- })
-}
-
-module.exports = {
- runLocalNode
-}
diff --git a/test/v2/integration/README.md b/test/v2/integration/README.md
deleted file mode 100644
index 3bd22f8..0000000
--- a/test/v2/integration/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-This directory contains integration tests. To run them requires that
-a local copy of rest.bitcoin.com is running. The tests in this directory are
-exactly the same calls that end users would use for their app to interact
-directly with rest.bitcoin.com.
-
-At present, this directory focuses on raw-transations. But more integration tests
-will be added.
diff --git a/test/v2/integration/rate-limits.js b/test/v2/integration/rate-limits.js
deleted file mode 100644
index b61c25e..0000000
--- a/test/v2/integration/rate-limits.js
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- */
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const axios = require("axios")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const SERVER = `https://rest.btctest.net/v2/`
-//const SERVER = `http://localhost:3000/v2/`
-
-describe("#rate limits", () => {
- it("should get control/getInfo() with no auth", async () => {
- const options = {
- method: "GET",
- url: `${SERVER}control/getInfo`
- }
-
- const result = await axios(options)
- //console.log(`result.status: ${result.status}`)
- //console.log(`result.data: ${util.inspect(result.data)}`)
-
- assert.equal(result.status, 200)
- assert.hasAnyKeys(result.data, ["version"])
- })
-
- it("should trigger rate-limit handler if rate limits exceeds 60 request per minute", async () => {
- try {
- // Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
- const options = {
- method: "GET",
- url: `${SERVER}control/getInfo`
- }
-
- const promises = []
- for (let i = 0; i < 250; i++) {
- const promise = axios(options)
- promises.push(promise)
- }
-
- await Promise.all(promises)
-
- assert.equal(true, false, "Unexpected result!")
- } catch (err) {
- //console.log(`err.response: ${util.inspect(err.response)}`)
-
- assert.equal(err.response.status, 429)
- assert.include(err.response.data.error, "Too many requests")
- }
- })
-
- it("should not trigger rate-limit handler if correct pro-tier password is used", async () => {
- try {
- const username = "BITBOX"
-
- // Pro-tier is accessed by using the right password.
- const password = "BITBOX"
- //const password = "something"
-
- const combined = `${username}:${password}`
- const base64Credential = Buffer.from(combined).toString("base64")
- const readyCredential = `Basic ${base64Credential}`
-
- const options = {
- method: "GET",
- url: `${SERVER}control/getInfo`,
- headers: { Authorization: readyCredential }
- }
-
- const promises = []
- for (let i = 0; i < 250; i++) {
- const promise = axios(options)
- promises.push(promise)
- }
-
- await Promise.all(promises)
-
- assert.equal(true, true, "Not throwing an error is a pass!")
- } catch (err) {
- // console.log(`err.response: ${util.inspect(err.response)}`)
-
- assert.equal(
- true,
- false,
- "This error handler should not have been triggered. Is the password correct?"
- )
- }
- })
-})
diff --git a/test/v2/integration/raw-transactions.js b/test/v2/integration/raw-transactions.js
deleted file mode 100644
index 7c17347..0000000
--- a/test/v2/integration/raw-transactions.js
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- These integration tests are intended to be run against a live local copy of
- rest.bitcoin.com. They exercise the endpoints in the same way the SDK or
- end-user application would. These tests were created to replace the parts
- removed from the swagger UI, that otherwise would have excersiced these endpoints.
-
- TODO:
- -/rawtransactions/sendRawTransaction is more appropropriate for an e2e test,
- so it is omitted here.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const rawtransactions = require("../../../dist/routes/v2/rawtransactions")
-const rp = require("request-promise")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const mockData = require("../mocks/raw-transactions-mocks")
-
-describe("#Raw-Transactions", () => {
- describe("#root", () => {
- it(`should return root`, async () => {
- const options = {
- method: "GET",
- uri: `http://localhost:3000/v2/rawtransactions/`,
- resolveWithFullResponse: true,
- json: true
- }
-
- const result = await rp(options)
- //console.log(`result: ${JSON.stringify(result, null, 0)}`)
-
- assert.equal(result.body.status, "rawtransactions")
- })
- })
-
- describe("#whCreateTx", () => {
- it(`should return tx hex`, async () => {
- const minIn = {
- txid:
- "f7ed9cf23dee85910f6269c9a101a75fcfd2f3c6fc81f17fad824ff7aaf99ab2",
- vout: 1
- }
-
- const options = {
- method: "PUT",
- uri: `http://localhost:3000/v2/rawtransactions/create`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- //inputs: [mockData.mockWHCreateInput],
- inputs: [minIn],
- outputs: {}
- }
- }
-
- const result = await rp(options)
- //console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
-
- assert.equal(
- result.body,
- "0200000001b29af9aaf74f82ad7ff181fcc6f3d2cf5fa701a1c969620f9185ee3df29cedf70100000000ffffffff0000000000"
- )
- })
- })
-
- describe("#whOpReturn", () => {
- it(`should return tx hex`, async () => {
- const options = {
- method: "PUT",
- uri: `http://localhost:3000/v2/rawtransactions/opreturn`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- rawtx: "01000000000000000000",
- payload: "00000000000000020000000006dac2c0"
- }
- }
-
- const result = await rp(options)
- //console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
-
- assert.equal(
- result.body,
- "0100000000010000000000000000166a140877686300000000000000020000000006dac2c000000000"
- )
- })
- })
-
- describe("#whReference", () => {
- it(`should return tx hex`, async () => {
- const options = {
- method: "PUT",
- uri: `http://localhost:3000/v2/rawtransactions/reference`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- rawtx:
- "0100000001a7a9402ecd77f3c9f745793c9ec805bfa2e14b89877581c734c774864247e6f50400000000ffffffff03aa0a0000000000001976a9146d18edfe073d53f84dd491dae1379f8fb0dfe5d488ac5c0d0000000000004751210252ce4bdd3ce38b4ebbc5a6e1343608230da508ff12d23d85b58c964204c4cef3210294cc195fc096f87d0f813a337ae7e5f961b1c8a18f1f8604a909b3a5121f065b52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000",
- destination: "bitcoincash:qrn60nerx5zug4u4hal06atep3lzhtecvy4pxk75lf",
- amount: 0.005
- }
- }
-
- const result = await rp(options)
- //console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
-
- assert.isString(result.body)
- })
- })
-
- describe("#whChangeOutput", () => {
- it(`should return tx hex`, async () => {
- const options = {
- method: "PUT",
- uri: `http://localhost:3000/v2/rawtransactions/change`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- rawtx:
- "0100000001b15ee60431ef57ec682790dec5a3c0d83a0c360633ea8308fbf6d5fc10a779670400000000ffffffff025c0d00000000000047512102f3e471222bb57a7d416c82bf81c627bfcd2bdc47f36e763ae69935bba4601ece21021580b888ff56feb27f17f08802ebed26258c23697d6a462d43fc13b565fda2dd52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000",
- destination: "bitcoincash:qrn60nerx5zug4u4hal06atep3lzhtecvy4pxk75lf",
- prevtxs: [
- {
- txid:
- "6779a710fcd5f6fb0883ea3306360c3ad8c0a3c5de902768ec57ef3104e65eb1",
- vout: 4,
- scriptPubKey:
- "76a9147b25205fd98d462880a3e5b0541235831ae959e588ac",
- value: 0.00068257
- }
- ],
- fee: 0.000035
- }
- }
-
- const result = await rp(options)
- //console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
-
- assert.isString(result.body)
- })
- })
-
- describe("#whInput", () => {
- it(`should return tx hex`, async () => {
- const options = {
- method: "PUT",
- uri: `http://localhost:3000/v2/rawtransactions/input`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- txid:
- "b006729017df05eda586df9ad3f8ccfee5be340aadf88155b784d1fc0e8342ee",
- n: 0
- }
- }
-
- const result = await rp(options)
- //console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
-
- assert.isString(result.body)
- })
- })
-
- describe("#getRawTransaction", () => {
- it(`should return tx hex`, async () => {
- const options = {
- method: "POST",
- uri: `http://localhost:3000/v2/rawtransactions/getRawTransaction`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- txids: [
- "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098"
- ],
- verbose: true
- }
- }
-
- const result = await rp(options)
- // console.log(`result.body: ${util.inspect(result.body)}`)
-
- assert.isArray(result.body)
- })
- })
-})
diff --git a/test/v2/mining.js b/test/v2/mining.js
deleted file mode 100644
index 14e1163..0000000
--- a/test/v2/mining.js
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- TESTS FOR THE MINING.TS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const miningRoute = require("../../src/routes/v2/mining")
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/mining-mocks")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Mining", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = miningRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "mining", "Returns static string")
- })
- })
-
- describe("#getMiningInfo", async () => {
- const getMiningInfo = miningRoute.testableComponents.getMiningInfo
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getMiningInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should GET mining information", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockMiningInfo })
- }
-
- const result = await getMiningInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, [
- "blocks",
- "currentblocksize",
- "currentblocktx",
- "difficulty",
- "blockprioritypercentage",
- "errors",
- "networkhashps",
- "pooledtx",
- "chain"
- ])
- })
- })
-
- describe("#getNetworkHashPS", async () => {
- const getNetworkHashPS = miningRoute.testableComponents.getNetworkHashPS
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getNetworkHashPS(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should GET Network Hash per second", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: 517604755.6648782 })
- }
-
- const result = await getNetworkHashPS(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isNumber(result)
- })
- })
-})
diff --git a/test/v2/mocks/address-mock.js b/test/v2/mocks/address-mock.js
deleted file mode 100644
index 7d4e3b9..0000000
--- a/test/v2/mocks/address-mock.js
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-const mockAddressDetails = {
- addrStr: "1Fg4r9iDrEkCcDmHTy2T79EusNfhyQpu7W",
- balance: 0.00126419,
- balanceSat: 126419,
- totalReceived: 0.02175868,
- totalReceivedSat: 2175868,
- totalSent: 0.02049449,
- totalSentSat: 2049449,
- unconfirmedBalance: 0,
- unconfirmedBalanceSat: 0,
- unconfirmedTxApperances: 0,
- txApperances: 3,
- transactions: [
- "2dc053f55a666a3d2a08b1c680b704d62a55506d14ad884add87edcc56b9277d",
- "544c15ce35c0f2e808d28f29d6587f1ec9276233e29856b7f2938cf0daef0026",
- "81039b1d7b855b133f359f9dc65f776bd105650153a941675fedc504228ddbd3"
- ],
- legacyAddress: "1Fg4r9iDrEkCcDmHTy2T79EusNfhyQpu7W",
- cashAddress: "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"
-}
-
-const mockUtxoDetails = [
- {
- txid: "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
- vout: 286,
- amount: 0.00001,
- satoshis: 1000,
- height: 546083,
- confirmations: 3490
- },
- {
- txid: "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
- vout: 287,
- amount: 0.00001,
- satoshis: 1000,
- height: 546083,
- confirmations: 3490
- },
- {
- txid: "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
- vout: 288,
- amount: 0.00001,
- satoshis: 1000,
- height: 546083,
- confirmations: 3490
- }
-]
-
-const mockUnconfirmed = [
- {
- address: "1EzdL6TBbkNhnB2fYiBaKmcs5fxaoqwdAp",
- txid: "000c00a90fb5031da6e02f7625df2f8b35a4c16e6feb9fc72293e67e5ff75786",
- vout: 0,
- scriptPubKey: "76a914997fabcd94a1e2aaa13a7664362e5e7b96c169a988ac",
- amount: 0.00999626,
- satoshis: 999626,
- confirmations: 0,
- ts: 1537989425
- }
-]
-
-const mockTransactions = {
- pagesTotal: 1,
- txs: [
- {
- txid: "000c00a90fb5031da6e02f7625df2f8b35a4c16e6feb9fc72293e67e5ff75786",
- version: 2,
- locktime: 549565,
- vin: [
- {
- txid:
- "45c891c6d44619fc85716ba1b593aa83ebc1e500fe611b1ab98531ea203a0f21",
- vout: 209,
- sequence: 4294967294,
- n: 0,
- scriptSig: {
- hex:
- "47304402205b136f348bedae61a87c0500979d47ab02c76f0e4aba866b94c4931fccb5d7dc0220757a141660475b0cd4cb8b1f54b1ace95105f5bea775e817b115fb589fe4477541210246daec651c506f353daa7468714399c773df42ac4d663022d0e446a3331ac64a",
- asm:
- "304402205b136f348bedae61a87c0500979d47ab02c76f0e4aba866b94c4931fccb5d7dc0220757a141660475b0cd4cb8b1f54b1ace95105f5bea775e817b115fb589fe44775[ALL|FORKID] 0246daec651c506f353daa7468714399c773df42ac4d663022d0e446a3331ac64a"
- },
- addr: "14TdovsQUL69xL5g3zSzhLpmDb93d9rU9m",
- valueSat: 1979534,
- value: 0.01979534,
- doubleSpentTxID: null
- },
- {
- txid:
- "6e5fa79547112a912adf6082c975dc80e282045193512ea369adb6bac7420674",
- vout: 147,
- sequence: 4294967294,
- n: 1,
- scriptSig: {
- hex:
- "473044022056674ac83a37d54ffec2c6d33cfc2ae2256f821b8bd818e1b6783356b49f3d28022046d3dd147c8fc51f2da5d16996a3cea1d7314e327aa1ae1017418737ed20136a4121038f23af565f68d8455e07e5c33c5cfc5114de2f478f035db23eb02f8ff5fe7f6e",
- asm:
- "3044022056674ac83a37d54ffec2c6d33cfc2ae2256f821b8bd818e1b6783356b49f3d28022046d3dd147c8fc51f2da5d16996a3cea1d7314e327aa1ae1017418737ed20136a[ALL|FORKID] 038f23af565f68d8455e07e5c33c5cfc5114de2f478f035db23eb02f8ff5fe7f6e"
- },
- addr: "1CEtC2fjELvmAzTd6MWuHb1gvuSq8x3Xpb",
- valueSat: 10466,
- value: 0.00010466,
- doubleSpentTxID: null
- }
- ],
- vout: [
- {
- value: "0.00999626",
- n: 0,
- scriptPubKey: {
- hex: "76a914997fabcd94a1e2aaa13a7664362e5e7b96c169a988ac",
- asm:
- "OP_DUP OP_HASH160 997fabcd94a1e2aaa13a7664362e5e7b96c169a9 OP_EQUALVERIFY OP_CHECKSIG",
- addresses: ["1EzdL6TBbkNhnB2fYiBaKmcs5fxaoqwdAp"],
- type: "pubkeyhash"
- },
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- },
- {
- value: "0.00990000",
- n: 1,
- scriptPubKey: {
- hex: "76a914e3335e4d6babe61ea58311293c1c6bfe802801cb88ac",
- asm:
- "OP_DUP OP_HASH160 e3335e4d6babe61ea58311293c1c6bfe802801cb OP_EQUALVERIFY OP_CHECKSIG",
- addresses: ["1MiKvgaQTFCTEZbSDMZgw9ahaB52Cr4ofb"],
- type: "pubkeyhash"
- },
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- }
- ],
- blockhash:
- "00000000000000000158b1a2883688873ec5ea076e3b0f576bcdfe1fd277880f",
- blockheight: 549601,
- confirmations: 5,
- time: 1537990026,
- blocktime: 1537990026,
- valueOut: 0.01989626,
- size: 372,
- valueIn: 0.0199,
- fees: 0.00000374
- }
- ]
-}
-
-module.exports = {
- mockAddressDetails,
- mockUtxoDetails,
- mockUnconfirmed,
- mockTransactions
-}
diff --git a/test/v2/mocks/block-mock.js b/test/v2/mocks/block-mock.js
deleted file mode 100644
index 069b90d..0000000
--- a/test/v2/mocks/block-mock.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-const mockBlockDetails = {
- hash: "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79",
- size: 1319,
- height: 1267544,
- version: 536870912,
- merkleroot:
- "c2cd01ec2cf149acc7631385f89ae103d1a2ad212ab810c862d9680a811618ce",
- tx: [
- "52bfa89d449fef8070ec33e7a61f5ec8b5417ff62b050cd6a144ebce9557e0fa",
- "8988e8742d2523f667c2d1374861919e3a82903e059fec75c10795da2303b93b",
- "41def004f22b196d675566a6983ecf97611e72c48375b8ba779983d5ccd369d7",
- "8ca8efb06abb94395f8331f87e101504dcf66aee828f2111922f056971fa7502",
- "9ab409cbb203be7cf22bd6598d787fcdd5b417d885b72207ecc7253470770649"
- ],
- time: 1542048973,
- nonce: 3936284753,
- bits: "1a03c148",
- difficulty: 4467892.99177529,
- chainwork: "00000000000000000000000000000000000000000000003ee27b503a064045bd",
- confirmations: 3,
- previousblockhash:
- "00000000000001891202cbe18729a02a8763cf04da0ca7aded6e6c7d9b500785",
- nextblockhash:
- "000000000000039b93b3f3403a0eb21150904b15229d998cf3788fd8bf192cc2",
- reward: 0.78125,
- isMainChain: true,
- poolInfo: {}
-}
-
-const mockBlockHash =
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
-
-module.exports = {
- mockBlockDetails,
- mockBlockHash
-}
diff --git a/test/v2/mocks/blockchain-mock.js b/test/v2/mocks/blockchain-mock.js
deleted file mode 100644
index 6025583..0000000
--- a/test/v2/mocks/blockchain-mock.js
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-const mockBlockHash =
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
-
-const mockBlockchainInfo = {
- chain: "test",
- blocks: 1267694,
- headers: 1267694,
- bestblockhash:
- "000000000000013eaf80d1e157e32804c36a58ad0bb26ca59833880c80298780",
- difficulty: 4105763.969035785,
- mediantime: 1542131305,
- verificationprogress: 0.9999968911571566,
- chainwork: "00000000000000000000000000000000000000000000003f0443b0b5f02ce255",
- pruned: false,
- softforks: [
- { id: "bip34", version: 2, reject: { status: true } },
- { id: "bip66", version: 3, reject: { status: true } },
- { id: "bip65", version: 4, reject: { status: true } }
- ],
- bip9_softforks: {
- csv: {
- status: "active",
- startTime: 1456790400,
- timeout: 1493596800,
- since: 770112
- }
- }
-}
-
-const mockChainTips = [
- {
- height: 1267696,
- hash: "000000000000035bfc43a642ebbff8cfc1e88b1d564de8b0a6c7e2797eeafb21",
- branchlen: 0,
- status: "active"
- },
- {
- height: 1267581,
- hash: "000000000001bd12e4124207682563135b21353ca3087bc6b0c409f7f9e1da91",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1267375,
- hash: "00000000702036979df70236bcc45dfc72d43d5d0e6834007afa1fa627e49587",
- branchlen: 1036,
- status: "headers-only"
- },
- {
- height: 1266979,
- hash: "00000000e851abbde2174ccdc5c2508b909f81f23c4b7abeac864eee1a4891c7",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266973,
- hash: "000000007e1324d2900ed70947f89ab8fd4a267e87c9244c333215659a7370d5",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266967,
- hash: "000000000f37f12843d4800f50ec4de44dce0432e4d448242d43ff04a7a2948d",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266963,
- hash: "00000000ae11ec99e88898cbd72567cb4cb79e7fc13243357bef79632769deb4",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266962,
- hash: "000000004f97851259b4460a049e44fa5bd4beadee04a85bf81bd2e90c4f24f9",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266950,
- hash: "00000000d12a0e4a827f73ecaadb563df7e99817294939f2be8e943079dc60b2",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266944,
- hash: "00000000612d16af273217818e8e7ac5014a19f68ed04e1bc897b1be0a9c744f",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266941,
- hash: "0000000000002b91cdb15cacf3368da2c9ffce511d64092193b507dad75f4a27",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266896,
- hash: "000000000002745f67a66617b1f9f65c2dfb4c4b8a9ed9b1320b98d3ca46cbe5",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266481,
- hash: "0000000000036babee3ba7654cddb29a9fe5e85c9fbeb44bb53d5ffb694b9670",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266452,
- hash: "00000000502c3ab1490e0839780a4b441bbe21507c454545941e6adcde73c2ff",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266336,
- hash: "000000001c9a0b7cd9eb2210f69d5a9a3f4546ba3707deb40993d729190582d7",
- branchlen: 10,
- status: "headers-only"
- },
- {
- height: 1266097,
- hash: "000000000028ac0fbd18afe6f001f70cb7549bd2b3082d754dde88ee236368a2",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1265522,
- hash: "00000000000000c6df7a2063030e6ce51399e470cc46e4bf6d67aa3f0feca98d",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1265470,
- hash: "0000000000168e6442a595a02340fccf8dc2b0e8912c632d39e1f870685f6d7c",
- branchlen: 2,
- status: "valid-fork"
- },
- {
- height: 1265275,
- hash: "000000008bc2b37ae6af1b886b52e7e1c1122c12badc4ae6c13df64f789267cf",
- branchlen: 11027,
- status: "headers-only"
- },
- {
- height: 1265257,
- hash: "00000000005bc3e9973d7273211eab02ae02549c7ebae48764c0bd648d4d7bbe",
- branchlen: 114,
- status: "valid-fork"
- },
- {
- height: 1265254,
- hash: "0000000000e5b909d3541857315e9ee103b042d9ba661f25cc3e8fb25a96c8ce",
- branchlen: 111,
- status: "valid-fork"
- },
- {
- height: 1265245,
- hash: "000000000066eb8832f6f990baceb379536f437216e22475a6c1b9133d250cb8",
- branchlen: 102,
- status: "valid-fork"
- },
- {
- height: 1264455,
- hash: "00000000000001befc1bb17a23208d0b77b2449e37093ce8fbb5e346b19cafcc",
- branchlen: 1,
- status: "valid-headers"
- },
- {
- height: 1264373,
- hash: "00000000000001ed3747e04fb95054cac0358fb4d8009d1999fc3ea34413e84a",
- branchlen: 175,
- status: "valid-fork"
- },
- {
- height: 1263912,
- hash: "00000000000004635aecbcb97edcd6f5396483338838cb40da804eb354c68bde",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1262906,
- hash: "00000000b31643d92a3e7c38e9755844fc8607e3f1055580a8ff28854e8a8ece",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1255749,
- hash: "000000001dde5b015a99137f4cba87871370f4b6fcfbcc8b126547e6c33177da",
- branchlen: 129,
- status: "headers-only"
- },
- {
- height: 1188789,
- hash: "00000000af942ce4eb60b3213cbcb7c98a7330f1f8f1adb4b6376f5e822e15b2",
- branchlen: 92,
- status: "headers-only"
- }
-]
-
-const mockMempoolInfo = {
- size: 87,
- bytes: 16816,
- usage: 66408,
- maxmempool: 300000000,
- mempoolminfee: 0
-}
-
-const mockRawMempool = [
- "db045bc3bd1088fa91f5ebb05c35cb9e2a91a22377f79b465cc6920b9893123c",
- "6b3df7febf2b9834f1409155f88b866dd516b36376eae00e2b455df82e290405"
-]
-
-const mockBlockHeaderConcise =
- "0000ff7f7d217c9b7845ea8b50d620c59a1bf7c276566406e9b7bc7e463e0000000000006d70322c0b697c1c81d2744f87f09f1e9780ba5d30338952e2cdc64e60456f8423bb0a5ceafa091a3e843526"
-
-const mockBlockHeader = {
- hash: "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900",
- confirmations: 7,
- height: 1272859,
- version: 2147418112,
- versionHex: "7fff0000",
- merkleroot:
- "846f45604ec6cde2528933305dba80971e9ff0874f74d2811c7c690b2c32706d",
- time: 1544207139,
- mediantime: 1544202884,
- nonce: 641041470,
- bits: "1a09faea",
- difficulty: 1681035.704111868,
- chainwork: "00000000000000000000000000000000000000000000003fc4752e608403be04",
- previousblockhash:
- "0000000000003e467ebcb7e906645676c2f71b9ac520d6508bea45789b7c217d",
- nextblockhash:
- "00000000000006899041cdfd6c0b73a97730c362346dde479b77414ad7f25ace"
-}
-
-const mockTxOut = {
- bestblock: "00000000003a7f19730dd9f172d7466658a5c8833dd03ed8f4ba36e3d857b5e7",
- confirmations: 10,
- value: 0.0001,
- scriptPubKey: {
- asm:
- "OP_DUP OP_HASH160 0ee020c07f39526ac5505c54fa1ab98490979b83 OP_EQUALVERIFY OP_CHECKSIG",
- hex: "76a9140ee020c07f39526ac5505c54fa1ab98490979b8388ac",
- reqSigs: 1,
- type: "pubkeyhash",
- addresses: ["bchtest:qq8wqgxq0uu4y6k92pw9f7s6hxzfp9umsvtg39pzqf"]
- },
- coinbase: false
-}
-
-const mockTxOutProof =
- "000000200798039affceb7a381e15dc62443c286efe7cae852393b656807000000000000cf9a7d6c654fd1c4558229a619a550ff749b373fa0f0027eed68b1abf6175d5c07c50f5cffff001d0452403b34000000070d0765da76980d542b5670d27ccda9e717073270f8921ad017deb7ee83fe6c4c22830a48cc8392197f1742a3d81805bd2aa4eb7469f38c74f674429d682cb87efcff1713fd0c388a50f0d11adf05363397ef79d16cdb786d47c941c2cb89f2588f42aced9c05f4203b4440616a9e4266ec47909b9580a643f402b5d4e82cc3cddd73df05a33abf6af3975d973d3033d10c4168a73d58d01f685a96d5a2519cd0de9c77faf3f8725ddf155cbdc8ab8102f173e2d0a0d74767f3bff22f588158d6d5bc71c079c7659cc864819c43877635007650502eb4060fcc9feec3280a41d602ad0a"
-
-module.exports = {
- mockBlockHash,
- mockBlockchainInfo,
- mockChainTips,
- mockMempoolInfo,
- mockRawMempool,
- mockBlockHeaderConcise,
- mockBlockHeader,
- mockTxOut,
- mockTxOutProof
-}
diff --git a/test/v2/mocks/control-mock.js b/test/v2/mocks/control-mock.js
deleted file mode 100644
index cca9338..0000000
--- a/test/v2/mocks/control-mock.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-const mockGetInfo = {
- version: 170200,
- protocolversion: 70015,
- walletversion: 160300,
- balance: 0,
- blocks: 1266726,
- timeoffset: 0,
- connections: 8,
- proxy: "",
- difficulty: 1,
- testnet: true,
- keypoololdest: 1536331195,
- keypoolsize: 2000,
- paytxfee: 0,
- relayfee: 0.00001,
- errors: "Warning: unknown new rules activated (versionbit 28)"
-}
-
-module.exports = {
- mockGetInfo
-}
diff --git a/test/v2/mocks/express-mocks.js b/test/v2/mocks/express-mocks.js
deleted file mode 100644
index fcb545f..0000000
--- a/test/v2/mocks/express-mocks.js
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- Contains mocks of Express req and res objects.
-*/
-
-"use strict"
-
-const sinon = require("sinon")
-
-// Inspect JS Objects.
-const util = require("util")
-util.inspect.defaultOptions = {
- showHidden: true,
- colors: true
-}
-
-// mock for res.send()
-function fakeSend(arg) {
- //console.log(`res.send: ${util.inspect(arg)}`);
- mockRes.output = arg
- return arg
-}
-
-// mock for res.json()
-function fakeJson(arg) {
- //console.log(`res.json: ${util.inspect(arg)}`);
- mockRes.output = arg
- return arg
-}
-
-// mock for res.setStatus(num)
-const setStatusCode = arg => {
- mockRes.statusCode = arg
-}
-
-const mockReq = {
- accepts: sinon.stub().returns({}),
- acceptsCharsets: sinon.stub().returns({}),
- acceptsEncodings: sinon.stub().returns({}),
- acceptsLanguages: sinon.stub().returns({}),
- body: {},
- flash: sinon.stub().returns({}),
- get: sinon.stub().returns({}),
- is: sinon.stub().returns({}),
- params: {},
- query: {},
- session: {},
- locals: {},
- headers: {}
-}
-
-const mockRes = {
- append: sinon.stub().returns({}),
- attachement: sinon.stub().returns({}),
- clearCookie: sinon.stub().returns({}),
- cookie: sinon.stub().returns({}),
- download: sinon.stub().returns({}),
- end: sinon.stub().returns({}),
- format: {},
- get: sinon.stub().returns({}),
- headersSent: sinon.stub().returns({}),
- json: sinon.stub().callsFake(fakeJson),
- jsonp: sinon.stub().returns({}),
- links: sinon.stub().returns({}),
- locals: {},
- location: sinon.stub().returns({}),
- output: null, // Used for retrieving output data.
- redirect: sinon.stub().returns({}),
- render: sinon.stub().returns({}),
- send: sinon.stub().callsFake(fakeSend),
- sendFile: sinon.stub().returns({}),
- sendStatus: sinon.stub().returns({}),
- set: sinon.stub().returns({}),
- status: sinon.stub().callsFake(setStatusCode),
- statusCode: null, // Default value before calling stats();
- type: sinon.stub().returns({}),
- vary: sinon.stub().returns({}),
- write: sinon.stub().returns({}),
- setHeader: sinon.stub().returns({}),
- format: sinon.stub().returns({})
-}
-
-const mockNext = sinon.stub().returns()
-
-module.exports = {
- mockReq,
- mockRes,
- mockNext
-}
diff --git a/test/v2/mocks/mining-mocks.js b/test/v2/mocks/mining-mocks.js
deleted file mode 100644
index 8ef8ada..0000000
--- a/test/v2/mocks/mining-mocks.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-const mockMiningInfo = {
- blocks: 1270185,
- currentblocksize: 0,
- currentblocktx: 0,
- difficulty: 1,
- blockprioritypercentage: 5,
- errors:
- "Warning: Unknown block versions being mined! It's possible unknown rules are in effect",
- networkhashps: 517410290.9365583,
- pooledtx: 5,
- chain: "test"
-}
-
-module.exports = {
- mockMiningInfo
-}
diff --git a/test/v2/mocks/raw-transactions-mocks.js b/test/v2/mocks/raw-transactions-mocks.js
deleted file mode 100644
index 08620a3..0000000
--- a/test/v2/mocks/raw-transactions-mocks.js
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- This library contains mocking data for running unit tests.
-*/
-
-"use strict"
-
-const mockDecodeRawTransaction = {
- txid: "a332237d82a2543af1b0e1ae3c8cea1610c290ebcaf084a7e9894a61de0be988",
- hash: "a332237d82a2543af1b0e1ae3c8cea1610c290ebcaf084a7e9894a61de0be988",
- size: 226,
- version: 2,
- locktime: 0,
- vin: [
- {
- txid: "21cced645eab150585ed7ca7c96edebab5793cc0a3b3b286c42fd7d6d798b5b9",
- vout: 1,
- scriptSig: {
- asm:
- "3045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd41390[ALL|FORKID] 0360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413d",
- hex:
- "483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413d"
- },
- sequence: 4294967295
- }
- ],
- vout: [
- {
- value: 0.0001,
- n: 0,
- scriptPubKey: {
- asm:
- "OP_DUP OP_HASH160 eb4b180def88e3f5625b2d8ae2c098ff7d85f664 OP_EQUALVERIFY OP_CHECKSIG",
- hex: "76a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac",
- reqSigs: 1,
- type: "pubkeyhash",
- addresses: [Array]
- }
- },
- {
- value: 0.09989752,
- n: 1,
- scriptPubKey: {
- asm:
- "OP_DUP OP_HASH160 eb4b180def88e3f5625b2d8ae2c098ff7d85f664 OP_EQUALVERIFY OP_CHECKSIG",
- hex: "76a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac",
- reqSigs: 1,
- type: "pubkeyhash",
- addresses: [Array]
- }
- }
- ]
-}
-
-const mockDecodeScript = {
- asm:
- "0 0 -57 OP_NOP6 OP_LSHIFT OP_UNKNOWN OP_UNKNOWN OP_UNKNOWN c486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa OP_2OVER OP_NUMEQUALVERIFY OP_OR OP_INVERT OP_UNKNOWN OP_UNKNOWN 2ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab 67c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b [error]",
- type: "nonstandard",
- p2sh: "bchtest:pzy6dwfy6yf373w0dr05a6flfqksurjhwcl3awhdvm"
-}
-
-const mockRawTransactionConcise =
- "02000000014e6b52500110b1c30315b85805fb274f0f4afceffc1589f889b27709e59e987d000000006a473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792ffffffff02d1778f950a0000001976a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac80969800000000001976a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac00000000"
-
-const mockRawTransactionVerbose = {
- hex:
- "02000000014e6b52500110b1c30315b85805fb274f0f4afceffc1589f889b27709e59e987d000000006a473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792ffffffff02d1778f950a0000001976a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac80969800000000001976a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac00000000",
- txid: "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971",
- hash: "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971",
- size: 225,
- version: 2,
- locktime: 0,
- vin: [
- {
- txid: "7d989ee50977b289f88915fceffc4a0f4f27fb0558b81503c3b1100150526b4e",
- vout: 0,
- scriptSig: {
- asm:
- "3044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7[ALL|FORKID] 03c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792",
- hex:
- "473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792"
- },
- sequence: 4294967295
- }
- ],
- vout: [
- {
- value: 454.58880465,
- n: 0,
- scriptPubKey: {
- asm:
- "OP_DUP OP_HASH160 36d2f27bbd826a86db1e93618ce3de89ef331693 OP_EQUALVERIFY OP_CHECKSIG",
- hex: "76a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac",
- reqSigs: 1,
- type: "pubkeyhash",
- addresses: ["bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35"]
- }
- },
- {
- value: 0.1,
- n: 1,
- scriptPubKey: {
- asm:
- "OP_DUP OP_HASH160 152ea3cd65f18cb8fa9146c84ea1a97af8f051de OP_EQUALVERIFY OP_CHECKSIG",
- hex: "76a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac",
- reqSigs: 1,
- type: "pubkeyhash",
- addresses: ["bchtest:qq2jag7dvhccew86j9rvsn4p49a03uz3mcpw3d6aca"]
- }
- }
- ],
- blockhash: "000000000000026fa244de975ca89ea08008aa566564ce2e8ebb3144361b601b",
- confirmations: 125,
- time: 1542646373,
- blocktime: 1542646373
-}
-
-const mockWHDecode = {
- txid: "f8a9857fe3b8a288b5fcafb1b0fc196731f433add6d962f77acd7c10b970ff89",
- fee: "500",
- sendingaddress: "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
- referenceaddress: "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
- ismine: false,
- version: 0,
- type_int: 0,
- type: "Simple Send",
- propertyid: 368,
- precision: "8",
- amount: "10.00000000",
- valid: true,
- blockhash: "0000000046ba0bcef78caaa4492622176bbc563cf249ab52340a0449bc8e26f6",
- blocktime: 1542814183,
- positioninblock: 57,
- block: 1269008,
- confirmations: 2
-}
-
-const mockWHCreateInput = {
- txid: "f7ed9cf23dee85910f6269c9a101a75fcfd2f3c6fc81f17fad824ff7aaf99ab2",
- vout: 1,
- scriptPubKey: "76a914a4b98b0c118de83e7d39c834445f51dce62425f588ac",
- amount: 0.09984138,
- satoshis: 9984138,
- height: 1269011,
- confirmations: 4,
- legacyAddress: "mvXwPH74hW2yVTWwDwzsjGoaUAqJvWk7ZJ",
- cashAddress: "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
- value: 0.09984138
-}
-
-module.exports = {
- mockDecodeRawTransaction,
- mockDecodeScript,
- mockRawTransactionConcise,
- mockRawTransactionVerbose,
- mockWHDecode,
- mockWHCreateInput
-}
diff --git a/test/v2/mocks/slp-mocks.js b/test/v2/mocks/slp-mocks.js
deleted file mode 100644
index 1d70df0..0000000
--- a/test/v2/mocks/slp-mocks.js
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- This library contains mocking data for running unit tests.
-*/
-
-"use strict"
-
-const mockList = {
- t: [
- {
- tokenDetails: {
- tokenIdHex:
- "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb",
- documentUri: "",
- documentSha256: "",
- symbol: "NAKAMOTO",
- name: "NAKAMOTO",
- decimals: 8
- },
- tokenStats: {
- qty_valid_txns_since_genesis: 241,
- qty_valid_token_utxos: 151,
- qty_valid_token_addresses: 113,
- qty_token_circulating_supply: "20995990",
- qty_token_burned: "4010",
- qty_token_minted: "21000000",
- qty_satoshis_locked_up: 81900
- }
- }
- ]
-}
-
-const mockSingleToken = {
- t: [
- {
- tokenDetails: {
- decimals: 8,
- tokenIdHex:
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a",
- timestamp: "2018-08-26 07:06",
- transactionType: "GENESIS",
- versionType: 1,
- documentUri: "",
- documentSha256Hex: null,
- symbol: "",
- name: "TESTYCOIN",
- batonVout: null,
- containsBaton: false,
- genesisOrMintQuantity: "9999",
- sendOutputs: null
- },
- tokenStats: {
- block_created: 1253802,
- block_last_active_send: 1253802,
- block_last_active_mint: null,
- qty_valid_txns_since_genesis: 2,
- qty_valid_token_utxos: 0,
- qty_valid_token_addresses: 0,
- qty_token_minted: "9999",
- qty_token_burned: "9999",
- qty_token_circulating_supply: "0",
- qty_satoshis_locked_up: 0,
- minting_baton_status: "NEVER_CREATED"
- }
- }
- ]
-}
-
-const mockSingleTokenError = {
- t: []
-}
-
-const mockSingleAddress = {
- a: [
- {
- _id: "5c93ed62a19119333d1595bc",
- tokenDetails: {
- tokenIdHex:
- "6b081fcd1f78b187be1464313dac8ff257251b727a42b613552a4040870aeb29"
- },
- address: "slptest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqv7sq3kk7",
- satoshis_balance: 546,
- token_balance: "4616984"
- }
- ],
- t: [
- {
- tokenDetails: {
- decimals: 8,
- tokenIdHex:
- "6b081fcd1f78b187be1464313dac8ff257251b727a42b613552a4040870aeb29",
- timestamp: "2019-02-25 10:05",
- transactionType: "GENESIS",
- versionType: 1,
- documentUri: "https://developer.bitcoin.com",
- documentSha256Hex: "",
- symbol: "DEV",
- name: "DEVCOIN",
- batonVout: 2,
- containsBaton: true,
- genesisOrMintQuantity: "500000000",
- sendOutputs: null
- },
- tokenStats: {
- block_created: 571272,
- block_last_active_send: 574758,
- block_last_active_mint: 571272,
- qty_valid_txns_since_genesis: 172,
- qty_valid_token_utxos: 170,
- qty_valid_token_addresses: 170,
- qty_token_minted: "1000000000",
- qty_token_burned: "4.99999995",
- qty_token_circulating_supply: "999999995.00000005",
- qty_satoshis_locked_up: 92820,
- minting_baton_status: "ALIVE"
- }
- }
- ]
-}
-
-const mockTx = {
- txid: "57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b9457822d446",
- version: 2,
- locktime: 0,
- vin: [
- {
- txid: "61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49",
- vout: 2,
- sequence: 4294967295,
- n: 0,
- scriptSig: {
- hex:
- "4730440220409e79fec552f01203f41d3d621ae3db89c720af261c8268ce5f0453de009f5d022001e7ffefeba7b0716d32ea55cb6ace267b6ee9cbcc8a017bb9c3b6acf7889418412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585",
- asm:
- "30440220409e79fec552f01203f41d3d621ae3db89c720af261c8268ce5f0453de009f5d022001e7ffefeba7b0716d32ea55cb6ace267b6ee9cbcc8a017bb9c3b6acf7889418[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585"
- },
- value: 546,
- legacyAddress: "mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL",
- cashAddress: "bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09"
- },
- {
- txid: "61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49",
- vout: 1,
- sequence: 4294967295,
- n: 1,
- scriptSig: {
- hex:
- "483045022100a743bee56c99bd103be48a78fa4c7342100815d9d2448dbe6e1d338c3a13b241022066728b5279fc22eef5cd019582ff34771e29175835fc98aa3168a1548fd78ac8412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585",
- asm:
- "3045022100a743bee56c99bd103be48a78fa4c7342100815d9d2448dbe6e1d338c3a13b241022066728b5279fc22eef5cd019582ff34771e29175835fc98aa3168a1548fd78ac8[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585"
- },
- value: 546,
- legacyAddress: "mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL",
- cashAddress: "bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09"
- },
- {
- txid: "61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49",
- vout: 3,
- sequence: 4294967295,
- n: 2,
- scriptSig: {
- hex:
- "483045022100821473902eec5f1ce7d43b1ba7f9ec453bfe8b8dfc3de3e0723c883ab109922f02206162960e80618531fab2c16aee260fddd7979bab62471c8686af7de75f8732ec412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585",
- asm:
- "3045022100821473902eec5f1ce7d43b1ba7f9ec453bfe8b8dfc3de3e0723c883ab109922f02206162960e80618531fab2c16aee260fddd7979bab62471c8686af7de75f8732ec[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585"
- },
- value: 9997521,
- legacyAddress: "mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL",
- cashAddress: "bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09"
- }
- ],
- vout: [
- {
- value: "0.00000000",
- n: 0,
- scriptPubKey: {
- hex:
- "6a04534c500001010453454e44207ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796080000000049504f80080000001c71e64280",
- asm:
- "OP_RETURN 5262419 1 1145980243 7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796 0000000049504f80 0000001c71e64280"
- },
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- },
- {
- value: "0.00000546",
- n: 1,
- scriptPubKey: {
- hex: "76a914396b8e57ad0cb58d30e2992f22047b3c20377aa688ac",
- asm:
- "OP_DUP OP_HASH160 396b8e57ad0cb58d30e2992f22047b3c20377aa6 OP_EQUALVERIFY OP_CHECKSIG",
- addresses: ["mkkZf7T3fU3vHSzNPy51HBmM46ghN1gnN9"],
- type: "pubkeyhash"
- },
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- },
- {
- value: "0.00000546",
- n: 2,
- scriptPubKey: {
- hex: "76a914aa099b067337dc20993bbfdb5c4f3c6867ba2c5b88ac",
- asm:
- "OP_DUP OP_HASH160 aa099b067337dc20993bbfdb5c4f3c6867ba2c5b OP_EQUALVERIFY OP_CHECKSIG",
- addresses: ["mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL"],
- type: "pubkeyhash"
- },
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- },
- {
- value: "0.09996891",
- n: 3,
- scriptPubKey: {
- hex: "76a914aa099b067337dc20993bbfdb5c4f3c6867ba2c5b88ac",
- asm:
- "OP_DUP OP_HASH160 aa099b067337dc20993bbfdb5c4f3c6867ba2c5b OP_EQUALVERIFY OP_CHECKSIG",
- addresses: ["mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL"],
- type: "pubkeyhash"
- },
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- }
- ],
- blockhash: "000000000000ce978accc64a6bb567acf0c653c202309a0f8e220149bf0c6968",
- blockheight: 1287490,
- confirmations: 746,
- time: 1550855104,
- blocktime: 1550855104,
- valueOut: 0.09997983,
- size: 628,
- valueIn: 0.09998613,
- fees: 0.0000063,
- tokenInfo: {
- versionType: 1,
- transactionType: "SEND",
- tokenIdHex:
- "7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796",
- sendOutputs: ["0", "1230000000", "122170000000"]
- },
- tokenIsValid: true
-}
-
-const mockConvert = {
- slpAddress: "slptest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2shlcycvd5",
- cashAddress: "bchtest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2svtllzmlf",
- legacyAddress: "mvQPGnzRT6gMWASZBMg7NcT3vmvsSKSQtf"
-}
-
-const mockTokenDetails = {
- tokenIdHex:
- "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb",
- documentUri: "",
- symbol: "NAKAMOTO",
- name: "NAKAMOTO",
- decimals: 8,
- timestamp: "",
- containsBaton: true,
- versionType: 1
-}
-
-const mockTokenStats = {
- qty_valid_txns_since_genesis: 241,
- qty_valid_token_utxos: 151,
- qty_valid_token_addresses: 113,
- qty_token_circulating_supply: "20995990",
- qty_token_burned: "4010",
- qty_token_minted: "21000000",
- qty_satoshis_locked_up: 81900
-}
-
-const mockBalance = {
- slpAddress: "simpleledger:qp9d8mn8ypryfvea2mev0ggc3wg6plpn4suuaeuss3",
- satoshis_balance: 546,
- token_balance: "1000"
-}
-
-const mockTransactions = [
- {
- txid: "a302f045be8efa1cd982833a7f187ff4fac8baac36da0c887eb2787d8b45e2af",
- tokenDetails: {
- valid: true,
- detail: {
- decimals: null,
- tokenIdHex:
- "495322b37d6b2eae81f045eda612b95870a0c2b6069c58f70cf8ef4e6a9fd43a",
- timestamp: null,
- transactionType: "MINT",
- versionType: 1,
- documentUri: null,
- documentSha256Hex: null,
- symbol: null,
- name: null,
- batonVout: 2,
- containsBaton: true,
- genesisOrMintQuantity: {
- $numberDecimal: "1000"
- },
- sendOutputs: null
- },
- invalidReason: null,
- schema_version: 30
- }
- }
-]
-
-const mockFoobar = {
- c: [],
- u: []
-}
-
-module.exports = {
- mockList,
- mockSingleToken,
- mockConvert,
- mockTokenDetails,
- mockTokenStats,
- mockTx,
- mockBalance,
- mockTransactions,
- mockSingleTokenError,
- mockSingleAddress,
- mockFoobar
-}
diff --git a/test/v2/mocks/slpjs-mocks.js b/test/v2/mocks/slpjs-mocks.js
deleted file mode 100644
index c130935..0000000
--- a/test/v2/mocks/slpjs-mocks.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- Mocks used for unit tests that interact with slpjs.
-*/
-
-"use strict"
-
-const sinon = require("sinon")
-const proxyquire = require("proxyquire")
-const BigNumber = require("bignumber.js")
-const slpMocks = require("./slp-mocks")
-
-// Mock the BitboxNetwork class.
-class BitboxNetwork {
- constructor() {}
-
- async getAllSlpBalancesAndUtxos(address) {
- return {
- satoshis_available_bch: 9996891,
- satoshis_in_slp_baton: 546,
- satoshis_in_slp_token: 546,
- satoshis_in_invalid_token_dag: 0,
- satoshis_in_invalid_baton_dag: 0,
- slpTokenBalances: {
- "7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796": new BigNumber(
- 123400000000
- )
- },
- slpTokenUtxos: {
- "7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796": []
- },
- slpBatonUtxos: {
- "7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796": []
- },
- nonSlpUtxos: [{}],
- invalidTokenUtxos: [],
- invalidBatonUtxos: []
- }
- }
-
- async getTokenInformation(txid) {
- BigNumber.set({ DECIMAL_PLACES: 8, ROUNDING_MODE: 4 })
-
- const obj = {
- versionType: 1,
- transactionType: 0,
- symbol: "SLPSDK",
- name: "SLP SDK example using BITBOX",
- documentUri: "developer.bitcoin.com",
- documentSha256: null,
- decimals: 8,
- batonVout: 2,
- containsBaton: true,
- genesisOrMintQuantity: new BigNumber(123400000000)
- }
-
- return obj
- }
-
- async getTransactionDetails(txid) {
- return slpMocks.mockTx
- }
-}
-
-// Mock the slpjs library.
-const slpjs = {
- BitboxNetwork,
- slp: {},
- validator: {}
-}
-
-module.exports = slpjs
diff --git a/test/v2/mocks/transaction-mocks.js b/test/v2/mocks/transaction-mocks.js
deleted file mode 100644
index a8d22e2..0000000
--- a/test/v2/mocks/transaction-mocks.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-/*
-const mockDetails = {
- txid: "6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40",
- version: 2,
- locktime: 0,
- vin: [Array],
- vout: [Array],
- blockhash: "00000000e7232ff12462dedf9c11985f5b54202515277c337ccc59812758f28b",
- blockheight: 1270188,
- confirmations: 2,
- time: 1543436253,
- blocktime: 1543436253,
- valueOut: 450.78867333,
- size: 226,
- valueIn: 450.78867559,
- fees: 0.00000226
-}
-*/
-
-const mockDetails = {
- txid: "6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40",
- version: 2,
- locktime: 0,
- vin: [
- {
- txid: "273d616d1c48f4b075c497f36ffdc79da5c8d6ed75485808b3599aac504f8525",
- vout: 0,
- sequence: 4294967295,
- n: 0,
- scriptSig: [{}],
- addr: "bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35",
- valueSat: 45078867559,
- value: 450.78867559,
- doubleSpentTxID: null
- }
- ],
- vout: [
- {
- value: "450.68867333",
- n: 0,
- scriptPubKey: [{}],
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- },
- {
- value: "0.10000000",
- n: 1,
- scriptPubKey: [{}],
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- }
- ],
- blockhash: "00000000e7232ff12462dedf9c11985f5b54202515277c337ccc59812758f28b",
- blockheight: 1270188,
- confirmations: 3,
- time: 1543436253,
- blocktime: 1543436253,
- valueOut: 450.78867333,
- size: 226,
- valueIn: 450.78867559,
- fees: 0.00000226
-}
-
-module.exports = {
- mockDetails
-}
diff --git a/test/v2/mocks/util-mocks.js b/test/v2/mocks/util-mocks.js
deleted file mode 100644
index 4118358..0000000
--- a/test/v2/mocks/util-mocks.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-const mockAddress = {
- isvalid: true,
- address: "bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y",
- scriptPubKey: "76a914016a935f87e8deeab04501889b22d87e4e52db0988ac",
- ismine: false,
- iswatchonly: false,
- isscript: false
-}
-
-module.exports = {
- mockAddress
-}
diff --git a/test/v2/rate-limits.js b/test/v2/rate-limits.js
deleted file mode 100644
index 030fa64..0000000
--- a/test/v2/rate-limits.js
+++ /dev/null
@@ -1,166 +0,0 @@
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const nock = require("nock") // HTTP mocking
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-// Mocking data.
-const { mockReq, mockRes, mockNext } = require("./mocks/express-mocks")
-
-// Libraries under test
-const rateLimitMiddleware = require("../../src/middleware/route-ratelimit")
-const controlRoute = require("../../src/routes/v2/control")
-
-let req, res, next
-let originalEnvVars // Used during transition from integration to unit tests.
-
-describe("#route-ratelimits", () => {
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
- next = mockNext
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
- })
-
- describe("#routeRateLimit", () => {
- const routeRateLimit = rateLimitMiddleware.routeRateLimit
- const getInfo = controlRoute.testableComponents.getInfo
- /*
- it("should pass through rate-limit middleware", async () => {
- req.baseUrl = "/v2"
- req.path = "/control/getInfo"
- req.method = "GET"
-
- await routeRateLimit(req, res, next)
-
- // next() will be called if rate-limit is not triggered
- assert.equal(next.called, true)
- })
-
- it("should trigger rate-limit handler if rate limits exceeds 60 request per minute", async () => {
- req.baseUrl = "/v2"
- req.path = "/control/getInfo"
- req.method = "GET"
-
- for (let i = 0; i < 65; i++) {
- next.reset() // reset the stubbed next() function.
-
- await routeRateLimit(req, res, next)
- //console.log(`next() called: ${next.called}`)
- }
-
- // Note: next() will be called unless the rate-limit kicks in.
- assert.equal(
- next.called,
- false,
- `next should not be called if rate limit was triggered.`
- )
- })
- */
- /*
- it("should NOT trigger rate-limit handler for pro-tier at 65 RPM", async () => {
- // Clear the require cache before running this test.
- delete require.cache[
- require.resolve("../../dist/middleware/route-ratelimit")
- ]
- rateLimitMiddleware = require("../../dist/middleware/route-ratelimit")
- routeRateLimit = rateLimitMiddleware.routeRateLimit
-
- req.baseUrl = "/v2"
- req.path = "/control/getInfo"
- req.method = "GET"
-
- req.locals.proLimit = true
-
- //console.log(`req.locals before test: ${util.inspect(req.locals)}`)
-
- // Prepare the authorization header
- //req.headers.authorization = generateAuthHeader("BITBOX")
-
- for (let i = 0; i < 65; i++) {
- next.reset() // reset the stubbed next() function.
-
- await routeRateLimit(req, res, next)
- //console.log(`next() called: ${next.called}`)
- }
-
- //console.log(`req.locals after test: ${util.inspect(req.locals)}`)
-
- // Note: next() will be called unless the rate-limit kicks in.
- assert.equal(
- next.called,
- true,
- `next should be called if rate limit was not triggered.`
- )
- })
-
- it("rate-limiting should still kick in at a higher RPM for pro-tier", async () => {
- // Clear the require cache before running this test.
- delete require.cache[
- require.resolve("../../dist/middleware/route-ratelimit")
- ]
- rateLimitMiddleware = require("../../dist/middleware/route-ratelimit")
- routeRateLimit = rateLimitMiddleware.routeRateLimit
-
- req.baseUrl = "/v2"
- req.path = "/control/getInfo"
- req.method = "GET"
-
- req.locals.proLimit = true
-
- //console.log(`req.locals before test: ${util.inspect(req.locals)}`)
-
- // Prepare the authorization header
- //req.headers.authorization = generateAuthHeader("BITBOX")
-
- for (let i = 0; i < 650; i++) {
- next.reset() // reset the stubbed next() function.
-
- await routeRateLimit(req, res, next)
- //console.log(`next() called: ${next.called}`)
- }
-
- //console.log(`req.locals after test: ${util.inspect(req.locals)}`)
-
- // Note: next() will be called unless the rate-limit kicks in.
- assert.equal(
- next.called,
- false,
- `next should NOT be called if rate limit was triggered.`
- )
- })
- */
- })
-})
-
-// Generates a Basic authorization header.
-function generateAuthHeader(pass) {
- // https://en.wikipedia.org/wiki/Basic_access_authentication
- const username = "BITBOX"
- const combined = `${username}:${pass}`
-
- var base64Credential = Buffer.from(combined).toString("base64")
- var readyCredential = `Basic ${base64Credential}`
-
- return readyCredential
-}
diff --git a/test/v2/raw-transactions.js b/test/v2/raw-transactions.js
deleted file mode 100644
index bd20bcc..0000000
--- a/test/v2/raw-transactions.js
+++ /dev/null
@@ -1,807 +0,0 @@
-/*
- TESTS FOR THE RAWTRANSACTIONS.TS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- TODO:
- -Create e2e test for sendRawTransaction.
-
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const rawtransactions = require("../../src/routes/v2/rawtransactions")
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-//delete require.cache[require.resolve("./mocks/express-mocks")] // Fixes bug
-const { mockReq, mockRes, mockNext } = require("./mocks/express-mocks")
-const mockData = require("./mocks/raw-transactions-mocks")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 5 }
-
-describe("#Raw-Transactions", () => {
- let req, res, next
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
- next = mockNext
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
- req.locals = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = rawtransactions.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "rawtransactions", "Returns static string")
- })
- })
-
- describe("decodeRawTransactionSingle()", () => {
- // block route handler.
- const decodeRawTransaction =
- rawtransactions.testableComponents.decodeRawTransactionSingle
-
- it("should throw error if hex is missing", async () => {
- const result = await decodeRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "hex can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.hex =
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
-
- const result = await decodeRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should GET /decodeRawTransaction", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockDecodeRawTransaction })
- }
-
- req.params.hex =
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
-
- const result = await decodeRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "txid",
- "hash",
- "size",
- "version",
- "locktime",
- "vin",
- "vout"
- ])
- assert.isArray(result.vin)
- assert.isArray(result.vout)
- })
- })
-
- describe("decodeRawTransactionBulk()", () => {
- const decodeRawTransactionBulk =
- rawtransactions.testableComponents.decodeRawTransactionBulk
-
- it("should throw 400 error if hexes array is missing", async () => {
- const result = await decodeRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "hexes must be an array")
- })
-
- it("should throw 400 error if hexes array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.hexes = testArray
-
- const result = await decodeRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw 400 error if hexes is empty", async () => {
- req.body.hexes = [""]
-
- const result = await decodeRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Encountered empty hex")
- })
-
- it("should error on non-array single hex", async () => {
- req.body.hexes =
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
-
- const result = await decodeRawTransactionBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hexes must be an array",
- "Proper error message"
- )
- })
-
- it("should decode an array with a single hex", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockDecodeRawTransaction })
- }
-
- req.body.hexes = [
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
- ]
-
- const result = await decodeRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "txid",
- "hash",
- "size",
- "version",
- "locktime",
- "vin",
- "vout"
- ])
- assert.isArray(result[0].vin)
- assert.isArray(result[0].vout)
- })
-
- it("should decode an array with multiple hexes", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: mockData.mockDecodeRawTransaction })
- }
-
- req.body.hexes = [
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000",
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
- ]
-
- const result = await decodeRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "txid",
- "hash",
- "size",
- "version",
- "locktime",
- "vin",
- "vout"
- ])
- assert.isArray(result[0].vin)
- assert.isArray(result[0].vout)
- })
- })
-
- describe("decodeScriptSingle()", () => {
- // block route handler.
- const decodeScriptSingle =
- rawtransactions.testableComponents.decodeScriptSingle
-
- it("should throw error if hex is missing", async () => {
- const result = await decodeScriptSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "hex can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.hex =
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
-
- const result = await decodeScriptSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should GET /decodeScriptSingle", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockDecodeScript })
- }
-
- req.params.hex =
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
-
- const result = await decodeScriptSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["asm", "type", "p2sh"])
- })
- })
-
- describe("decodeScriptBulk()", () => {
- const decodeScriptBulk = rawtransactions.testableComponents.decodeScriptBulk
-
- it("should throw 400 error if hexes array is missing", async () => {
- const result = await decodeScriptBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "hexes must be an array")
- })
-
- it("should throw 400 error if hexes array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.hexes = testArray
-
- const result = await decodeScriptBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw 400 error if hexes is empty", async () => {
- req.body.hexes = [""]
-
- const result = await decodeScriptBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Encountered empty hex")
- })
-
- it("should error on non-array single hex", async () => {
- req.body.hexes =
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
-
- const result = await decodeScriptBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hexes must be an array",
- "Proper error message"
- )
- })
-
- it("should decode an array with a single hex", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockDecodeScript })
- }
-
- req.body.hexes = [
- "4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
- ]
-
- const result = await decodeScriptBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], ["asm", "type", "p2sh"])
- })
-
- it("should decode an array with a multiple hexes", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: mockData.mockDecodeScript })
- }
-
- req.body.hexes = [
- "4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16",
- "4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
- ]
-
- const result = await decodeScriptBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2)
- assert.hasAllKeys(result[0], ["asm", "type", "p2sh"])
- })
- })
-
- describe("getRawTransactionBulk()", () => {
- // block route handler.
- const getRawTransactionBulk =
- rawtransactions.testableComponents.getRawTransactionBulk
-
- it("should throw 400 error if txids array is missing", async () => {
- const result = await getRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txids must be an array")
- })
-
- it("should throw 400 error if txids array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.txids = testArray
-
- const result = await getRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw 400 error if txid is empty", async () => {
- req.body.txids = [""]
-
- const result = await getRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Encountered empty TXID")
- })
-
- it("should throw 400 error if txid is invalid", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(500, {
- error: { message: "parameter 1 must be of length 64 (not 6)" }
- })
- }
-
- req.body.txids = ["abc123"]
-
- const result = await getRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "parameter 1 must be of length 64 (not 6)")
- })
-
- it("should get concise transaction data", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockRawTransactionConcise })
- }
-
- req.body.txids = [
- "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971"
- ]
-
- const result = await getRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.isString(result[0])
- })
-
- it("should get verbose transaction data", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockRawTransactionVerbose })
- }
-
- req.body.txids = [
- "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971"
- ]
- req.body.verbose = true
-
- const result = await getRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "hex",
- "txid",
- "hash",
- "size",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "confirmations",
- "time",
- "blocktime"
- ])
- assert.isArray(result[0].vin)
- assert.isArray(result[0].vout)
- })
- })
-
- describe("getRawTransactionSingle()", () => {
- // block route handler.
- const getRawTransactionSingle =
- rawtransactions.testableComponents.getRawTransactionSingle
-
- it("should throw 400 error if txid is missing", async () => {
- const result = await getRawTransactionSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should throw 400 error if txid is invalid", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(500, {
- error: { message: "parameter 1 must be of length 64 (not 6)" }
- })
- }
-
- req.params.txid = "abc123"
-
- const result = await getRawTransactionSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "parameter 1 must be of length 64 (not 6)")
- })
-
- it("should get concise transaction data", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockRawTransactionConcise })
- }
-
- req.params.txid =
- "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971"
-
- const result = await getRawTransactionSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isString(result)
- })
-
- it("should get verbose transaction data", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockRawTransactionVerbose })
- }
-
- req.params.txid =
- "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971"
- req.query.verbose = "true"
-
- const result = await getRawTransactionSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "hex",
- "txid",
- "hash",
- "size",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "confirmations",
- "time",
- "blocktime"
- ])
- assert.isArray(result.vin)
- assert.isArray(result.vout)
- })
- })
-
- describe("sendRawTransactionBulk()", () => {
- const sendRawTransaction =
- rawtransactions.testableComponents.sendRawTransactionBulk
-
- it("should throw 400 error if hexs array is missing", async () => {
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "hex must be an array")
- })
-
- it("should throw 400 error if hexs array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.hexes = testArray
-
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw 400 error if hex array element is empty", async () => {
- req.body.hexes = [""]
-
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Encountered empty hex")
- })
-
- it("should throw 500 error if hex is invalid", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(500, {
- error: { message: "TX decode failed" }
- })
- }
-
- req.body.hexes = ["abc123"]
-
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "TX decode failed")
- })
-
- it("should submit hex encoded transaction", async () => {
- // This is a difficult test to run as transaction hex is invalid after a
- // block confirmation. So the unit tests simulates what the output 'should'
- // be, but the integration asserts an expected failure.
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, {
- result:
- "aef8848396e67532b42008b9d75b5a5a3459a6717740f31f0553b74102b4b118"
- })
- }
-
- req.body.hexes = [
- "0200000001189f7cf4303e2e0bcc5af4be323b9b397dd4104ca2de09528eb90a1450b8a999010000006a4730440220212ec2ffce136a30cec1bc86a40b08a2afdeb6f8dbd652d7bcb07b1aad6dfa8c022041f59585273b89d88879a9a531ba3272dc953f48ff57dad955b2dee70e76c0624121030143ffd18f1c4add75c86b2f930d9551d51f7a6bd786314247022b7afc45d231ffffffff0230d39700000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac58c20000000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac00000000"
- ]
-
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- if (process.env.TEST === "unit") {
- assert.isArray(result)
- assert.isString(result[0])
-
- // Integration test
- } else {
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "transaction already in block chain")
- }
- })
- })
-
- describe("sendRawTransactionSingle()", () => {
- // block route handler.
- const sendRawTransaction =
- rawtransactions.testableComponents.sendRawTransactionSingle
-
- it("should throw an error for an empty hex", async () => {
- req.params.hex = ""
-
- const result = await sendRawTransaction(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Encountered empty hex",
- "Proper error message"
- )
- })
-
- it("should throw an error for a non-string", async () => {
- req.params.hex = 456
-
- const result = await sendRawTransaction(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hex must be a string",
- "Proper error message"
- )
- })
-
- it("should throw 500 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl = process.env.BITCOINCOM_BASEURL
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.hex =
- "0200000001189f7cf4303e2e0bcc5af4be323b9b397dd4104ca2de09528eb90a1450b8a999010000006a4730440220212ec2ffce136a30cec1bc86a40b08a2afdeb6f8dbd652d7bcb07b1aad6dfa8c022041f59585273b89d88879a9a531ba3272dc953f48ff57dad955b2dee70e76c0624121030143ffd18f1c4add75c86b2f930d9551d51f7a6bd786314247022b7afc45d231ffffffff0230d39700000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac58c20000000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac00000000"
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or great expected."
- )
- })
-
- it("should throw an error for invalid hex", async () => {
- req.params.hex = "abc123"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(500, {
- error: { message: "TX decode failed" }
- })
- }
-
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "TX decode failed")
- })
-
- it("should GET /sendRawTransaction/:hex", async () => {
- // This is a difficult test to run as transaction hex is invalid after a
- // block confirmation. So the unit tests simulates what the output 'should'
- // be, but the integration asserts an expected failure.
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, {
- result:
- "aef8848396e67532b42008b9d75b5a5a3459a6717740f31f0553b74102b4b118"
- })
- }
-
- req.params.hex =
- "0200000001189f7cf4303e2e0bcc5af4be323b9b397dd4104ca2de09528eb90a1450b8a999010000006a4730440220212ec2ffce136a30cec1bc86a40b08a2afdeb6f8dbd652d7bcb07b1aad6dfa8c022041f59585273b89d88879a9a531ba3272dc953f48ff57dad955b2dee70e76c0624121030143ffd18f1c4add75c86b2f930d9551d51f7a6bd786314247022b7afc45d231ffffffff0230d39700000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac58c20000000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac00000000"
-
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- if (process.env.TEST === "unit") {
- assert.isString(result)
-
- // Integration test
- } else {
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "transaction already in block chain")
- }
- })
- })
-})
diff --git a/test/v2/slp.js b/test/v2/slp.js
deleted file mode 100644
index 2049a77..0000000
--- a/test/v2/slp.js
+++ /dev/null
@@ -1,971 +0,0 @@
-/*
- TESTS FOR THE SLP.TS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- TODO:
- -See listSingleToken() tests.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const nock = require("nock") // HTTP mocking
-const sinon = require("sinon")
-const proxyquire = require("proxyquire").noPreserveCache()
-
-// Prepare the slpRoute for stubbing dependcies on slpjs.
-const slpRoute = require("../../src/routes/v2/slp")
-const pathStub = {} // Used to stub methods within slpjs.
-const slpRouteStub = proxyquire("../../src/routes/v2/slp", { slpjs: pathStub })
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/slp-mocks")
-const slpjsMock = require("./mocks/slpjs-mocks")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#SLP", () => {
- let req, res, mockServerUrl
- let sandbox
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITDB_URL: process.env.BITDB_URL,
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- SLPDB_URL: process.env.SLPDB_URL
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
-
- // Block network connections for unit tests.
- if (process.env.TEST === "unit") {
- process.env.BITDB_URL = "http://fakeurl/"
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/"
- process.env.SLPDB_URL = "http://fakeurl/"
- mockServerUrl = `http://fakeurl`
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- //req.params = {}
- req.body = {}
- req.query = {}
- req.locals = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
-
- sandbox = sinon.createSandbox()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
-
- sandbox.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITDB_URL = originalEnvVars.BITDB_URL
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.SLPDB_URL = originalEnvVars.SLPDB_URL
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = slpRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "slp", "Returns static string")
- })
- })
-
- describe("list()", () => {
- // list route handler
- const list = slpRoute.testableComponents.list
-
- it("should throw 500 when network issues", async () => {
- // Save the existing SLPDB_URL.
- const savedUrl2 = process.env.SLPDB_URL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.SLPDB_URL = "http://fakeurl/api/"
-
- const result = await list(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.SLPDB_URL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should GET list", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- const b64 = `eyJ2IjozLCJxIjp7ImRiIjpbInQiXSwiZmluZCI6eyIkcXVlcnkiOnt9fSwicHJvamVjdCI6eyJ0b2tlbkRldGFpbHMiOjEsInRva2VuU3RhdHMiOjEsIl9pZCI6MH0sImxpbWl0IjoxMDB9fQ==`
-
- nock(process.env.SLPDB_URL)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockList)
- }
-
- const result = await list(req, res)
- // console.log(`test result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "id",
- "timestamp",
- "symbol",
- "name",
- "documentUri",
- "documentHash",
- "decimals",
- "initialTokenQty"
- ])
- })
- })
-
- describe("listSingleToken()", () => {
- const listSingleToken = slpRoute.testableComponents.listSingleToken
-
- it("should throw 400 if tokenId is empty", async () => {
- const result = await listSingleToken(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "tokenId can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing BITDB_URL.
- const savedUrl2 = process.env.SLPDB_URL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.SLPDB_URL = "http://fakeurl/api/"
-
- req.params.tokenId =
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
-
- const result = await listSingleToken(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.SLPDB_URL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should return 'not found' for mainnet txid on testnet", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockSingleToken)
- }
-
- req.params.tokenId =
- // testnet
- //"650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
- // mainnet
- "259908ae44f46ef585edef4bcc1e50dc06e4c391ac4be929fae27235b8158cf1"
-
- const result = await listSingleToken(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["id"])
- assert.include(result.id, "not found")
- })
-
- it("should get token information", async () => {
- // testnet
- const tokenIdToTest =
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockSingleToken)
- }
-
- req.params.tokenId = tokenIdToTest
-
- const result = await listSingleToken(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, [
- "id",
- "blockCreated",
- "blockLastActiveMint",
- "blockLastActiveSend",
- "circulatingSupply",
- "containsBaton",
- "mintingBatonStatus",
- "txnsSinceGenesis",
- "versionType",
- "timestamp",
- "symbol",
- "name",
- "documentUri",
- "documentHash",
- "decimals",
- "initialTokenQty",
- "totalBurned",
- "totalMinted",
- "validAddresses"
- ])
- })
- })
-
- describe("listBulkToken()", () => {
- const listBulkToken = slpRoute.testableComponents.listBulkToken
-
- it("should throw 400 if tokenIds array is empty", async () => {
- const result = await listBulkToken(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "tokenIds needs to be an array")
- assert.equal(res.statusCode, 400)
- })
-
- it("should throw 400 error if array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.tokenIds = testArray
-
- const result = await listBulkToken(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw 400 if tokenId is empty", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockEmptyTokenId)
- }
- req.body.tokenIds = ""
-
- const result = await listBulkToken(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(
- result.error,
- "tokenIds needs to be an array. Use GET for single tokenId."
- )
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing BITDB_URL.
- const savedUrl2 = process.env.SLPDB_URL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.SLPDB_URL = "http://fakeurl/api/"
-
- req.body.tokenIds = [
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
- ]
-
- const result = await listBulkToken(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.SLPDB_URL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should return 'not found' for mainnet txid on testnet", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockSingleTokenError)
- }
-
- req.body.tokenIds =
- // testnet
- //"650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
- // mainnet
- ["0b314bc2b2905b8844222871c6b665ae3494117c83b11302824561bb904efb6b"]
-
- const result = await listBulkToken(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], ["id", "valid"])
- assert.strictEqual(result[0].valid, false)
- })
-
- it("should get token information for single token ID", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockSingleToken)
- }
-
- req.body.tokenIds =
- // testnet
- ["650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"]
-
- const result = await listBulkToken(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "blockCreated",
- "blockLastActiveMint",
- "blockLastActiveSend",
- "circulatingSupply",
- "containsBaton",
- "mintingBatonStatus",
- "txnsSinceGenesis",
- "versionType",
- "timestamp",
- "symbol",
- "name",
- "documentUri",
- "documentHash",
- "decimals",
- "initialTokenQty",
- "id",
- "totalBurned",
- "totalMinted",
- "validAddresses"
- ])
- })
-
- it("should get token information for multiple token IDs", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockSingleToken)
- }
-
- req.body.tokenIds =
- // testnet
- [
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a",
- "c35a87afad11c8d086c1449ffd8b0a84324e72b15b1bcfdf166a493551b4eea6"
- ]
-
- const result = await listBulkToken(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "blockCreated",
- "blockLastActiveMint",
- "blockLastActiveSend",
- "circulatingSupply",
- "containsBaton",
- "mintingBatonStatus",
- "txnsSinceGenesis",
- "versionType",
- "timestamp",
- "symbol",
- "name",
- "documentUri",
- "documentHash",
- "decimals",
- "initialTokenQty",
- "id",
- "totalBurned",
- "totalMinted",
- "validAddresses"
- ])
- })
- })
-
- describe("balancesForAddress()", () => {
- const balancesForAddress = slpRoute.testableComponents.balancesForAddress
-
- it("should throw 400 if address is empty", async () => {
- const result = await balancesForAddress(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should throw 400 if address is invalid", async () => {
- req.params.address = "badAddress"
-
- const result = await balancesForAddress(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Invalid BCH address.")
- })
-
- it("should throw 400 if address network mismatch", async () => {
- req.params.address =
- "simpleledger:qr5agtachyxvrwxu76vzszan5pnvuzy8duhv4lxrsk"
-
- const result = await balancesForAddress(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Invalid")
- })
-
- it("should throw 5XX error when network issues", async () => {
- // Save the existing SLPDB_URL.
- const savedUrl2 = process.env.SLPDB_URL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.SLPDB_URL = "http://fakeurl/api/"
-
- req.params.address = "slptest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2shlcycvd5"
-
- const result = await balancesForAddress(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.SLPDB_URL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- assert.include(
- result.error,
- "Network error: Could not communicate",
- "Error message expected"
- )
- })
-
- it("should get token balance for an address", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockSingleAddress)
- }
-
- req.params.address = "slptest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqv7sq3kk7"
-
- const result = await balancesForAddress(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "tokenId",
- "balance",
- "slpAddress",
- "decimalCount"
- ])
- })
- })
-
- describe("balancesForAddressByTokenID()", () => {
- const balancesForAddressByTokenID =
- slpRoute.testableComponents.balancesForAddressByTokenID
-
- it("should throw 400 if address is empty", async () => {
- req.params.address = ""
- req.params.tokenId =
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
- const result = await balancesForAddressByTokenID(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should throw 400 if tokenId is empty", async () => {
- req.params.address =
- "simpleledger:qr5agtachyxvrwxu76vzszan5pnvuzy8duhv4lxrsk"
- req.params.tokenId = ""
- const result = await balancesForAddressByTokenID(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "tokenId can not be empty")
- })
-
- it("should throw 400 if address is invalid", async () => {
- req.params.address = "badAddress"
- req.params.tokenId =
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
-
- const result = await balancesForAddressByTokenID(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Invalid BCH address.")
- })
-
- it("should throw 400 if address network mismatch", async () => {
- req.params.address =
- "simpleledger:qr5agtachyxvrwxu76vzszan5pnvuzy8duhv4lxrsk"
-
- const result = await balancesForAddressByTokenID(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Invalid")
- })
-
- it("should throw 5XX error when network issues", async () => {
- // Save the existing SLPDB_URL.
- const savedUrl2 = process.env.SLPDB_URL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.SLPDB_URL = "http://fakeurl/api/"
-
- req.params.address = "slptest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvxu67w0ac"
- req.params.tokenId =
- "7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796"
-
- const result = await balancesForAddressByTokenID(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.SLPDB_URL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- assert.include(
- result.error,
- "Network error: Could not communicate",
- "Error message expected"
- )
- })
-
- it("should get token information", async () => {
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockSingleAddress)
- }
-
- req.params.address = "slptest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqv7sq3kk7"
- req.params.tokenId =
- "6b081fcd1f78b187be1464313dac8ff257251b727a42b613552a4040870aeb29"
-
- const result = await balancesForAddressByTokenID(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // TODO - add decimalCount
- // assert.hasAllKeys(result, ["tokenId", "balance", "decimalCount"])
- assert.hasAllKeys(result, ["tokenId", "balance"])
- })
- })
-
- describe("convertAddressSingle()", () => {
- const convertAddressSingle =
- slpRoute.testableComponents.convertAddressSingle
-
- it("should throw 400 if address is empty", async () => {
- req.params.address = ""
- const result = await convertAddressSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
- //
- it("should convert address", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.SLPDB_URL}`)
- .post(``)
- .reply(200, { result: mockData.mockConvert })
- }
-
- req.params.address = "slptest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2shlcycvd5"
-
- const result = await convertAddressSingle(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["cashAddress", "legacyAddress", "slpAddress"])
- })
- })
-
- describe("convertAddressBulk()", () => {
- const convertAddressBulk = slpRoute.testableComponents.convertAddressBulk
-
- it("should throw 400 if addresses array is empty", async () => {
- const result = await convertAddressBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "addresses needs to be an array")
- assert.equal(res.statusCode, 400)
- })
-
- it("should throw 400 error if array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await convertAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should error on malformed address", async () => {
- try {
- req.body.addresses = ["bitcoincash:qzs02v05l7qs5s5dwuj0cx5ehjm2c"]
-
- await convertAddressBulk(req, res)
-
- assert.equal(true, false, "Unsupported address format")
- } catch (err) {
- // console.log(`err.message: ${util.inspect(err.message)}`)
-
- assert.include(err.message, `Unsupported address format`)
- }
- })
-
- it("should validate array with single element", async () => {
- req.body.addresses = [
- "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"
- ]
-
- const result = await convertAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "slpAddress",
- "cashAddress",
- "legacyAddress"
- ])
- })
-
- it("should validate array with multiple elements", async () => {
- req.body.addresses = [
- "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c",
- "bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0"
- ]
-
- const result = await convertAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "slpAddress",
- "cashAddress",
- "legacyAddress"
- ])
- })
- })
-
- describe("validateBulk()", () => {
- const validateBulk = slpRoute.testableComponents.validateBulk
-
- it("should throw 400 if txid array is empty", async () => {
- const result = await validateBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txids needs to be an array")
- assert.equal(res.statusCode, 400)
- })
-
- it("should throw 400 error if array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.txids = testArray
-
- const result = await validateBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should validate array with single element", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- sandbox
- .stub(slpRoute.testableComponents, "isValidSlpTxid")
- .resolves(true)
- }
-
- req.body.txids = [
- "78d57a82a0dd9930cc17843d9d06677f267777dd6b25055bad0ae43f1b884091"
- ]
-
- const result = await validateBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], ["txid", "valid"])
- })
-
- it("should validate array with two elements", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- sandbox
- .stub(slpRoute.testableComponents, "isValidSlpTxid")
- .resolves(true)
- }
-
- req.body.txids = [
- "78d57a82a0dd9930cc17843d9d06677f267777dd6b25055bad0ae43f1b884091",
- "82d996847a861b08b1601284ef7d40a1777d019154a6c4ed11571609dd3555ac"
- ]
-
- const result = await validateBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], ["txid", "valid"])
- assert.equal(result.length, 2)
- })
- })
-
- describe("tokenStatsSingle()", () => {
- const tokenStatsSingle = slpRoute.testableComponents.tokenStats
-
- it("should throw 400 if tokenID is empty", async () => {
- req.params.tokenId = ""
- const result = await tokenStatsSingle(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "tokenId can not be empty")
- })
- //
- it("should get token stats for tokenId", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.SLPDB_URL}`)
- .get(uri => uri.includes("/"))
- .reply(200, {
- t: [
- {
- tokenDetails: mockData.mockTokenDetails,
- tokenStats: mockData.mockTokenStats
- }
- ]
- })
- }
-
- req.params.tokenId =
- "37279c7dc81ceb34d12f03344b601c582e931e05d0e552c29c428bfa39d39af3"
-
- const result = await tokenStatsSingle(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, [
- "blockCreated",
- "blockLastActiveMint",
- "blockLastActiveSend",
- "containsBaton",
- "initialTokenQty",
- "mintingBatonStatus",
- "circulatingSupply",
- "decimals",
- "documentHash",
- "versionType",
- "timestamp",
- "documentUri",
- "name",
- "symbol",
- "id",
- "totalBurned",
- "totalMinted",
- "txnsSinceGenesis",
- "validAddresses"
- ])
- })
- })
-
- describe("balancesForTokenSingle()", () => {
- const balancesForTokenSingle =
- slpRoute.testableComponents.balancesForTokenSingle
-
- it("should throw 400 if tokenID is empty", async () => {
- req.params.tokenId = ""
- const result = await balancesForTokenSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "tokenId can not be empty")
- })
- //
- it("should get balances for tokenId", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.SLPDB_URL}`)
- .get(uri => uri.includes("/"))
- .reply(200, {
- a: [mockData.mockBalance]
- })
- }
-
- req.params.tokenId =
- "37279c7dc81ceb34d12f03344b601c582e931e05d0e552c29c428bfa39d39af3"
-
- const result = await balancesForTokenSingle(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result[0], ["tokenId", "slpAddress", "tokenBalance"])
- })
- })
-
- describe("txDetails()", () => {
- let txDetails = slpRoute.testableComponents.txDetails
-
- it("should throw 400 if txid is empty", async () => {
- const result = await txDetails(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should throw 400 for malformed txid", async () => {
- req.params.txid =
- "57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b9457"
-
- const result = await txDetails(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "This is not a txid")
- })
-
- it("should throw 400 for non-existant txid", async () => {
- // Integration test
- if (process.env.TEST !== "unit") {
- req.params.txid =
- "57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b94578223333"
-
- const result = await txDetails(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "TXID not found")
- }
- })
-
- it("should get tx details with token info", async () => {
- if (process.env.TEST === "unit") {
- // Mock the slpjs library for unit tests.
- pathStub.BitboxNetwork = slpjsMock.BitboxNetwork
- txDetails = slpRouteStub.testableComponents.txDetails
- }
-
- req.params.txid =
- "57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b9457822d446"
-
- const result = await txDetails(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.hasAnyKeys(result, ["tokenIsValid", "tokenInfo"])
- })
- })
-
- describe("txsTokenIdAddressSingle()", () => {
- const txsTokenIdAddressSingle =
- slpRoute.testableComponents.txsTokenIdAddressSingle
-
- it("should throw 400 if tokenId is empty", async () => {
- req.params.tokenId = ""
- const result = await txsTokenIdAddressSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "tokenId can not be empty")
- })
-
- it("should throw 400 if address is empty", async () => {
- req.params.tokenId =
- "495322b37d6b2eae81f045eda612b95870a0c2b6069c58f70cf8ef4e6a9fd43a"
- req.params.address = ""
- const result = await txsTokenIdAddressSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
- /*
- it("should get tx details with tokenId and address", async () => {
- if (process.env.TEST === "unit") {
- nock(`${process.env.SLPDB_URL}`)
- .get(uri => uri.includes("/"))
- .reply(200, {
- c: mockData.mockTransactions
- })
- }
-
- //req.params.tokenId =
- // "37279c7dc81ceb34d12f03344b601c582e931e05d0e552c29c428bfa39d39af3"
- //req.params.address = "slptest:qr83cu3p7yg9yac7qthwm0nul2ev2kukvsqmes3vl0"
-
- req.params.tokenId =
- "7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796"
- req.params.address = "slptest:qpwa35xq0q0cnmdu0rwzkct369hddzsqpsqdzw6h9h"
-
-
- const result = await txsTokenIdAddressSingle(req, res)
- console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.hasAnyKeys(result[0], ["txid", "tokenDetails"])
- })
-*/
- })
-})
diff --git a/test/v2/transaction.js b/test/v2/transaction.js
deleted file mode 100644
index 4eb1bdc..0000000
--- a/test/v2/transaction.js
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- TESTS FOR THE TRANSACTION.TS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- TODO:
- -See "should throw an error for an invalid txid" for detailsSingle:
- --The error handler should be refactored to return an intelligent error message,
- instead of the 503 error it is returning now.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const transactionRoute = require("../../src/routes/v2/transaction")
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/transaction-mocks")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Transactions", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = transactionRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "transaction", "Returns static string")
- })
- })
-
- describe("#detailsBulk", async () => {
- const detailsBulk = transactionRoute.testableComponents.detailsBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single txid", async () => {
- req.body = {
- txids: `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
- }
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid txid", async () => {
- const fakeTXID = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${fakeTXID}`)
- .reply(400, {
- result: { error: "parameter 1 must be hexadecimal string" }
- })
- }
-
- req.body = {
- txids: [fakeTXID]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- })
-
- it("should process a single txid", async () => {
- const txid = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid}`)
- .reply(200, mockData.mockDetails)
- }
-
- req.body = {
- txids: [txid]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "txid",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "blockheight",
- "confirmations",
- "time",
- "blocktime",
- "valueOut",
- "size",
- "valueIn",
- "fees"
- ])
- })
-
- it("should process a multiple txids", async () => {
- const txid1 = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
- const txid2 = `8d4fd4dcaa9d8051dc7d862dc23d8aa23e20b77b9c928c49380685459caa7043`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid1}`)
- .reply(200, mockData.mockDetails)
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid2}`)
- .reply(200, mockData.mockDetails)
- }
-
- req.body = {
- txids: [txid1, txid2]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "txid",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "blockheight",
- "confirmations",
- "time",
- "blocktime",
- "valueOut",
- "size",
- "valueIn",
- "fees"
- ])
- })
- })
-
- describe("#detailsSingle", () => {
- // details route handler.
- const detailsSingle = transactionRoute.testableComponents.detailsSingle
-
- it("should throw 400 if txid is empty", async () => {
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.txid = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txid can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid txid", async () => {
- if (process.env.TEST !== "unit") {
- req.params.txid = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // The error handling code should probably be updated to respond with a better
- // error message.
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "parameter 1 must be hexadecimal string",
- "Proper error message"
- )
- }
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.txid = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- const txid = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
- req.params.txid = txid
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid}`)
- .reply(200, mockData.mockDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.hasAllKeys(result, [
- "txid",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "blockheight",
- "confirmations",
- "time",
- "blocktime",
- "valueOut",
- "size",
- "valueIn",
- "fees"
- ])
- assert.isArray(result.vin)
- assert.isArray(result.vout)
- })
- })
-})
diff --git a/test/v2/util.js b/test/v2/util.js
deleted file mode 100644
index e550f14..0000000
--- a/test/v2/util.js
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- TESTS FOR THE UTIL.TS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const utilRoute = require("../../src/routes/v2/util")
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/util-mocks")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Util", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = utilRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "util", "Returns static string")
- })
- })
-
- describe("#validateAddressSingle", async () => {
- const validateAddress = utilRoute.testableComponents.validateAddressSingle
-
- it("should throw an error for an empty address", async () => {
- const result = await validateAddress(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be empty",
- "Proper error message"
- )
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
-
- const result = await validateAddress(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should validate address", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockAddress })
- }
-
- req.params.address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
-
- const result = await validateAddress(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, [
- "isvalid",
- "address",
- "scriptPubKey",
- "ismine",
- "iswatchonly",
- "isscript"
- ])
- })
- })
-
- describe("#validateAddressBulk", async () => {
- const validateAddressBulk = utilRoute.testableComponents.validateAddressBulk
-
- it("should throw an error for an empty body", async () => {
- const result = await validateAddressBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array. Use GET for single address.",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- addresses: `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
- }
-
- const result = await validateAddressBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array. Use GET for single address.",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await validateAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should error on invalid address", async () => {
- req.body = {
- addresses: [`bchtest:qqqk4y6lsl5da64sg5qc3xezmpl`]
- }
-
- const result = await validateAddressBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address. Double check your address is valid",
- "Proper error message"
- )
- })
-
- it("should error on mainnet address when using testnet", async () => {
- req.body = {
- addresses: [`bitcoincash:qrcc3jsqpgwqcdru70sk54sd0g3l04q7c53ycm6ucj`]
- }
-
- const result = await validateAddressBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid network. Trying to use a testnet address on mainnet, or vice versa.",
- "Proper error message"
- )
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.body.addresses = [
- `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
- ]
-
- const result = await validateAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- })
-
- it("should validate a single address", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockAddress })
- }
-
- req.body.addresses = [
- `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
- ]
-
- const result = await validateAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "isvalid",
- "address",
- "scriptPubKey",
- "ismine",
- "iswatchonly",
- "isscript"
- ])
- })
-
- it("should validate a multiple addresses", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: mockData.mockAddress })
- }
-
- req.body.addresses = [
- `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`,
- `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
- ]
-
- const result = await validateAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "isvalid",
- "address",
- "scriptPubKey",
- "ismine",
- "iswatchonly",
- "isscript"
- ])
- })
- })
-})
diff --git a/test/v3/blockchain.js b/test/v3/blockchain.js
index 2101961..fe1d70b 100644
--- a/test/v3/blockchain.js
+++ b/test/v3/blockchain.js
@@ -11,7 +11,7 @@
const chai = require("chai")
const assert = chai.assert
const nock = require("nock") // HTTP mocking
-const blockchainRoute = require("../../src/routes/v3/blockchain")
+const blockchainRoute = require("../../src/routes/v3/full-node/blockchain")
const util = require("util")
util.inspect.defaultOptions = { depth: 1 }
diff --git a/test/v3/control.js b/test/v3/control.js
index dd2d799..e651b26 100644
--- a/test/v3/control.js
+++ b/test/v3/control.js
@@ -11,7 +11,7 @@
const chai = require("chai")
const assert = chai.assert
-const controlRoute = require("../../src/routes/v3/control")
+const controlRoute = require("../../src/routes/v3/full-node/control")
const nock = require("nock") // HTTP mocking
let originalEnvVars // Used during transition from integration to unit tests.
diff --git a/test/v3/mining.js b/test/v3/mining.js
index e9a8b65..7ba81c4 100644
--- a/test/v3/mining.js
+++ b/test/v3/mining.js
@@ -10,7 +10,7 @@
const chai = require("chai")
const assert = chai.assert
-const miningRoute = require("../../src/routes/v3/mining")
+const miningRoute = require("../../src/routes/v3/full-node/mining")
const nock = require("nock") // HTTP mocking
let originalEnvVars // Used during transition from integration to unit tests.
diff --git a/test/v3/rate-limits.js b/test/v3/rate-limits.js
index 3b2db1f..0d81b5b 100644
--- a/test/v3/rate-limits.js
+++ b/test/v3/rate-limits.js
@@ -13,7 +13,7 @@ const { mockReq, mockRes, mockNext } = require("./mocks/express-mocks")
// Libraries under test
let rateLimitMiddleware = require("../../src/middleware/route-ratelimit")
-const controlRoute = require("../../src/routes/v3/control")
+const controlRoute = require("../../src/routes/v3/full-node/control")
let req, res, next
let originalEnvVars // Used during transition from integration to unit tests.
diff --git a/test/v3/raw-transactions.js b/test/v3/raw-transactions.js
index c6af05e..bf1c78b 100644
--- a/test/v3/raw-transactions.js
+++ b/test/v3/raw-transactions.js
@@ -14,7 +14,7 @@
const chai = require("chai")
const assert = chai.assert
-const rawtransactions = require("../../src/routes/v3/rawtransactions")
+const rawtransactions = require("../../src/routes/v3/full-node/rawtransactions")
const nock = require("nock") // HTTP mocking
let originalEnvVars // Used during transition from integration to unit tests.
From 1886a2cb3f9a6e5e806afbba7b433080db3c70af Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Thu, 31 Oct 2019 16:47:52 -0700
Subject: [PATCH 08/49] feat(tiers): Enforcing tiered access to endpoints
---
src/app.js | 3 +-
src/middleware/jwt-auth.js | 60 ++++++++++++++++++---
test/v3/rate-limits.js | 104 +++++++++++++++++++++++++++++++++++--
3 files changed, 156 insertions(+), 11 deletions(-)
diff --git a/src/app.js b/src/app.js
index 99a8a29..7f04668 100644
--- a/src/app.js
+++ b/src/app.js
@@ -75,7 +75,8 @@ const auth = new AuthMW()
app.use(`/${v3prefix}/`, auth.mw())
// Rate limit on all v3 routes
-app.use(`/${v3prefix}/`, routeRateLimit)
+app.use(`/${v3prefix}/`, routeRateLimit) // Establish and enforce rate limits.
+app.use(`/${v3prefix}/`, jwtAuth.routeAccess) // Enforce access tiers.
app.use(`/${v3prefix}/` + `health-check`, healthCheckV3)
app.use(`/${v3prefix}/` + `blockchain`, blockchainV3.router)
app.use(`/${v3prefix}/` + `control`, controlV3.router)
diff --git a/src/middleware/jwt-auth.js b/src/middleware/jwt-auth.js
index b006035..684f95a 100644
--- a/src/middleware/jwt-auth.js
+++ b/src/middleware/jwt-auth.js
@@ -10,12 +10,9 @@
// req.locals.jwtToken property.
const getTokenFromHeaders = (req, res, next) => {
try {
- // console.log(`getTokenFromHeaders2: Searching headers for a JWT token.`)
-
- // console.log(`req.headers: `, req.headers)
-
- // If the authorization header exists.
+ // Only executes if the authorization header exists.
if (req.headers.authorization) {
+ // Retrieve the auth string from the header object.
const authStr = req.headers.authorization
// If the header is proceeded by the word 'Token'
@@ -31,18 +28,67 @@ const getTokenFromHeaders = (req, res, next) => {
proLimit: false,
apiLevel: 0
}
+ } else {
+ req.locals.jwtToken = token
}
}
}
} catch (err) {
- console.log(`Error in getTokenFromHeaders2: `, err)
+ console.log(`Error in getTokenFromHeaders: `, err)
+ }
+
+ next()
+}
+
+// This middleware analyizes the combination of JWT token and apiLevel. It will
+// stop users from accessing routes they have not paid for.
+//
+// It is assumed this middleware is run AFTER the route-ratelimit.js middleware,
+// so that the req.locals.apiLevel property has been populated.
+const routeAccess = (req, res, next) => {
+ try {
+ // console.log(`req.locals: ${JSON.stringify(req.locals, null, 2)}`)
+ console.log(`req.url: `, req.url)
+
+ const locals = req.locals
+ const url = req.url
+
+ const level20Routes = ["insight", "bitcore", "blockbook"]
+
+ // JWT token is included in header.
+ if (!!locals.jwtToken && locals.jwtToken !== "") {
+ // API Level is 0 (free tier): do nothing. All endpoints are open to
+ // free public access within the drastically limited rate limits.
+
+ if (locals.apiLevel === 10) {
+ // API level is 10 (full node tier)
+
+ // Loop through the routes that are not accessible to this tier.
+ for (let i = 0; i < level20Routes.length; i++) {
+ // If the requested route is for a higher tier, return a 403.
+ if (url.indexOf(level20Routes[i]) > -1) {
+ res.status(403)
+ return res.json({
+ error:
+ "route is not accessible for your JWT tier. Upgrade or use anonymous access."
+ })
+ }
+ }
+ }
+ // else if (locals.apiLevel > 11) {
+ // // API level is 20 (indexer tier)
+ // }
+ }
+ } catch (err) {
+ console.log(`Error in routeAccess: `, err)
}
next()
}
const jwtAuth = {
- getTokenFromHeaders
+ getTokenFromHeaders,
+ routeAccess
}
module.exports = jwtAuth
diff --git a/test/v3/rate-limits.js b/test/v3/rate-limits.js
index 0d81b5b..6f74c42 100644
--- a/test/v3/rate-limits.js
+++ b/test/v3/rate-limits.js
@@ -14,11 +14,15 @@ const { mockReq, mockRes, mockNext } = require("./mocks/express-mocks")
// Libraries under test
let rateLimitMiddleware = require("../../src/middleware/route-ratelimit")
const controlRoute = require("../../src/routes/v3/full-node/control")
+const jwtAuth = require("../../src/middleware/jwt-auth")
let req, res, next
let originalEnvVars // Used during transition from integration to unit tests.
-describe("#route-ratelimits", () => {
+// JWT token used in tests.
+const jwt = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYWRlM2Y1NzM5ZTZjMGZmMDM0YjlhMSIsImlhdCI6MTU3MTY3NzQ1MCwiZXhwIjoxNTc0MjY5NDUwfQ.SSz7F7ETyBB3eoNG2VKCzPOhddtB-vrtmEoj7PxicrQ`
+
+describe("#route-ratelimits & jwt-auth", () => {
before(() => {
// Save existing environment variables.
originalEnvVars = {
@@ -35,8 +39,8 @@ describe("#route-ratelimits", () => {
// Setup the mocks before each test.
beforeEach(() => {
// Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
+ req = Object.assign({}, mockReq)
+ res = Object.assign({}, mockRes)
next = mockNext
// Explicitly reset the parmas and body.
@@ -45,6 +49,100 @@ describe("#route-ratelimits", () => {
req.query = {}
})
+ describe("#jwt-auth.js", () => {
+ describe("#getTokenFromHeaders", () => {
+ it(`should populate the req.locals object correctly`, () => {
+ // Initialize req.locals
+ req.locals = {
+ proLimit: false,
+ apiLevel: 0
+ }
+
+ const header = `Token ${jwt}`
+ req.headers.authorization = header
+
+ jwtAuth.getTokenFromHeaders(req, res, next)
+
+ // console.log(`req.locals: ${JSON.stringify(req.locals, null, 2)}`)
+
+ assert.property(req.locals, "proLimit")
+ assert.property(req.locals, "apiLevel")
+ assert.property(req.locals, "jwtToken")
+ assert.equal(req.locals.jwtToken, jwt)
+ })
+ })
+
+ describe("#routeAccess", () => {
+ it("should do nothing if req.locals.jwtToken is undefined", () => {
+ // Initialize req.locals
+ req.locals = {
+ proLimit: false,
+ apiLevel: 0
+ }
+ req.url = "/insight/address/details"
+
+ // Reset the history of the stub and assert it has not been called.
+ res.status.resetHistory()
+ assert.equal(res.status.called, false, "stub history reset")
+
+ jwtAuth.routeAccess(req, res, next)
+
+ // console.log(`req.locals: ${JSON.stringify(req.locals, null, 2)}`)
+ assert.equal(
+ res.status.called,
+ false,
+ "stub should NOT have been called."
+ )
+ })
+
+ it("should throw error if full-node tier tries to access indexer", () => {
+ // Initialize req.locals
+ req.locals = {
+ proLimit: true,
+ apiLevel: 10,
+ jwtToken: jwt
+ }
+ req.url = "/insight/address/details"
+
+ try {
+ res.status.resetHistory()
+ assert.equal(res.status.called, false, "stub history reset")
+
+ jwtAuth.routeAccess(req, res, next)
+
+ assert.equal(res.status.called, true, "stub should have been called.")
+ } catch (err) {
+ console.log(`caught error: `, err)
+ }
+ })
+
+ it("should allow indexer tier tries access indexer endpoints", () => {
+ // Initialize req.locals
+ req.locals = {
+ proLimit: true,
+ apiLevel: 20,
+ jwtToken: jwt
+ }
+ req.url = "/insight/address/details"
+
+ try {
+ res.status.resetHistory()
+ assert.equal(res.status.called, false, "stub history reset")
+
+ jwtAuth.routeAccess(req, res, next)
+
+ assert.equal(
+ res.status.called,
+ false,
+ "stub should NOT have been called."
+ )
+ } catch (err) {
+ console.log(`caught error: `, err)
+ }
+ })
+ })
+ })
+
describe("#routeRateLimit", () => {
let routeRateLimit = rateLimitMiddleware.routeRateLimit
const getInfo = controlRoute.testableComponents.getInfo
From 39faf7cd4c5fea4ae9adc5c2c745ba0b24eaaaec Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Sat, 2 Nov 2019 13:49:10 -0700
Subject: [PATCH 09/49] Achieving desired rate limiting results.
---
src/app.js | 2 +-
src/middleware/jwt-auth.js | 4 +-
src/middleware/route-ratelimit.js | 65 ++++++++++++++++++++++++++++---
3 files changed, 62 insertions(+), 9 deletions(-)
diff --git a/src/app.js b/src/app.js
index 7f04668..20b90bc 100644
--- a/src/app.js
+++ b/src/app.js
@@ -76,7 +76,7 @@ app.use(`/${v3prefix}/`, auth.mw())
// Rate limit on all v3 routes
app.use(`/${v3prefix}/`, routeRateLimit) // Establish and enforce rate limits.
-app.use(`/${v3prefix}/`, jwtAuth.routeAccess) // Enforce access tiers.
+// app.use(`/${v3prefix}/`, jwtAuth.routeAccess) // Enforce access tiers.
app.use(`/${v3prefix}/` + `health-check`, healthCheckV3)
app.use(`/${v3prefix}/` + `blockchain`, blockchainV3.router)
app.use(`/${v3prefix}/` + `control`, controlV3.router)
diff --git a/src/middleware/jwt-auth.js b/src/middleware/jwt-auth.js
index 684f95a..be719fc 100644
--- a/src/middleware/jwt-auth.js
+++ b/src/middleware/jwt-auth.js
@@ -60,8 +60,8 @@ const routeAccess = (req, res, next) => {
// API Level is 0 (free tier): do nothing. All endpoints are open to
// free public access within the drastically limited rate limits.
- if (locals.apiLevel === 10) {
- // API level is 10 (full node tier)
+ if (locals.apiLevel < 20) {
+ // API level does not include indexer access.
// Loop through the routes that are not accessible to this tier.
for (let i = 0; i < level20Routes.length; i++) {
diff --git a/src/middleware/route-ratelimit.js b/src/middleware/route-ratelimit.js
index 2bb2c2b..fca640d 100644
--- a/src/middleware/route-ratelimit.js
+++ b/src/middleware/route-ratelimit.js
@@ -53,17 +53,35 @@ const routeRateLimit = async function(req, res, next) {
if (req.locals.jwtToken) {
// console.log(`req.locals.jwtToken: ${req.locals.jwtToken}`)
+ // URL for the auth server.
const path = `${authServer}apitoken/isvalid/${req.locals.jwtToken}`
+ // Ask Auth server if the JWT token is valid.
+ // Get the API level for this user.
let jwtInfo = await axios.get(path)
jwtInfo = jwtInfo.data
- // console.log(`jwtInfo: ${JSON.stringify(jwtInfo, null, 2)}`)
+ console.log(`jwtInfo: ${JSON.stringify(jwtInfo, null, 2)}`)
- // Enable pro-tier rate limits if JWT if valid.
+ // If JWT if valid, evaluate the API level for the user.
if (jwtInfo.isValid) {
- // console.log(`JWT is valid. Enabling pro-tier rate limits.`)
- req.locals.proLimit = true
- req.locals.apiLevel = jwtInfo.apiLevel
+ // Set fine-grain permissions for each user based on the JWT token.
+ const userPermissions = evalUserPermissioins(req, jwtInfo)
+ console.log(
+ `userPermissions: ${JSON.stringify(userPermissions, null, 2)}`
+ )
+ console.log(` `)
+
+ req.locals.proLimit = userPermissions.proLimit
+ req.locals.apiLevel = userPermissions.apiLevel
+
+ // const locals = req.locals
+ // console.log(`locals: ${JSON.stringify(locals, null, 2)}`)
+ // const url = req.url
+ // console.log(`url: ${JSON.stringify(url, null, 2)}`)
+ //
+ // // console.log(`JWT is valid. Enabling pro-tier rate limits.`)
+ // req.locals.proLimit = true
+ // req.locals.apiLevel = jwtInfo.apiLevel
}
}
}
@@ -126,7 +144,7 @@ const routeRateLimit = async function(req, res, next) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
- error: `Too many requests. Limits are ${maxRequests} requests per minute.`
+ error: `Too many requests. Your limits are currently ${maxRequests} requests per minute.`
})
}
})
@@ -139,4 +157,39 @@ const routeRateLimit = async function(req, res, next) {
uniqueRateLimits[route](req, res, next)
}
+// This function returns the an object with proLimit and apiLevel properties.
+// It does fine-grane analysis on the data coming from the auth servers and
+// uses its output to adjust rate limits on-the-fly based on the users
+// permission level.
+function evalUserPermissioins(req, authData) {
+ console.log(`authData: ${JSON.stringify(authData, null, 2)}`)
+
+ // Return object with default values
+ const retObj = {
+ proLimit: authData.isValid,
+ apiLevel: authData.apiLevel
+ }
+
+ const level20Routes = ["insight", "bitcore", "blockbook"]
+
+ const locals = req.locals
+ console.log(`locals: ${JSON.stringify(locals, null, 2)}`)
+ const url = req.url
+ console.log(`url: ${JSON.stringify(url, null, 2)}`)
+
+ if (authData.apiLevel < 20) {
+ // Loop through the routes that are not accessible to this tier.
+ for (let i = 0; i < level20Routes.length; i++) {
+ // If the requested route is for a higher tier,
+ // revert to anonymous level permissions.
+ if (url.indexOf(level20Routes[i]) > -1) {
+ retObj.proLimit = false
+ retObj.apiLevel = 0
+ }
+ }
+ }
+
+ return retObj
+}
+
module.exports = { routeRateLimit }
From 1c1bb25a5458edd773cc01c61d272965a7195def Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Sat, 2 Nov 2019 16:24:38 -0700
Subject: [PATCH 10/49] Completed e2e bch-js rate limit tests
---
src/app.js | 2 --
src/middleware/jwt-auth.js | 49 +-----------------------------
src/middleware/route-ratelimit.js | 15 +++++----
src/routes/v3/full-node/control.js | 2 --
4 files changed, 8 insertions(+), 60 deletions(-)
diff --git a/src/app.js b/src/app.js
index 20b90bc..26f8020 100644
--- a/src/app.js
+++ b/src/app.js
@@ -71,12 +71,10 @@ app.use(`/${v3prefix}/`, jwtAuth.getTokenFromHeaders)
// Instantiate the authorization middleware, used to implement pro-tier rate limiting.
const auth = new AuthMW()
-// app.use(`/${v2prefix}/`, auth.mw())
app.use(`/${v3prefix}/`, auth.mw())
// Rate limit on all v3 routes
app.use(`/${v3prefix}/`, routeRateLimit) // Establish and enforce rate limits.
-// app.use(`/${v3prefix}/`, jwtAuth.routeAccess) // Enforce access tiers.
app.use(`/${v3prefix}/` + `health-check`, healthCheckV3)
app.use(`/${v3prefix}/` + `blockchain`, blockchainV3.router)
app.use(`/${v3prefix}/` + `control`, controlV3.router)
diff --git a/src/middleware/jwt-auth.js b/src/middleware/jwt-auth.js
index be719fc..6880ea0 100644
--- a/src/middleware/jwt-auth.js
+++ b/src/middleware/jwt-auth.js
@@ -40,55 +40,8 @@ const getTokenFromHeaders = (req, res, next) => {
next()
}
-// This middleware analyizes the combination of JWT token and apiLevel. It will
-// stop users from accessing routes they have not paid for.
-//
-// It is assumed this middleware is run AFTER the route-ratelimit.js middleware,
-// so that the req.locals.apiLevel property has been populated.
-const routeAccess = (req, res, next) => {
- try {
- // console.log(`req.locals: ${JSON.stringify(req.locals, null, 2)}`)
- console.log(`req.url: `, req.url)
-
- const locals = req.locals
- const url = req.url
-
- const level20Routes = ["insight", "bitcore", "blockbook"]
-
- // JWT token is included in header.
- if (!!locals.jwtToken && locals.jwtToken !== "") {
- // API Level is 0 (free tier): do nothing. All endpoints are open to
- // free public access within the drastically limited rate limits.
-
- if (locals.apiLevel < 20) {
- // API level does not include indexer access.
-
- // Loop through the routes that are not accessible to this tier.
- for (let i = 0; i < level20Routes.length; i++) {
- // If the requested route is for a higher tier, return a 403.
- if (url.indexOf(level20Routes[i]) > -1) {
- res.status(403)
- return res.json({
- error:
- "route is not accessible for your JWT tier. Upgrade or use anonymous access."
- })
- }
- }
- }
- // else if (locals.apiLevel > 11) {
- // // API level is 20 (indexer tier)
- // }
- }
- } catch (err) {
- console.log(`Error in routeAccess: `, err)
- }
-
- next()
-}
-
const jwtAuth = {
- getTokenFromHeaders,
- routeAccess
+ getTokenFromHeaders
}
module.exports = jwtAuth
diff --git a/src/middleware/route-ratelimit.js b/src/middleware/route-ratelimit.js
index fca640d..b67c045 100644
--- a/src/middleware/route-ratelimit.js
+++ b/src/middleware/route-ratelimit.js
@@ -60,16 +60,15 @@ const routeRateLimit = async function(req, res, next) {
// Get the API level for this user.
let jwtInfo = await axios.get(path)
jwtInfo = jwtInfo.data
- console.log(`jwtInfo: ${JSON.stringify(jwtInfo, null, 2)}`)
+ // console.log(`jwtInfo: ${JSON.stringify(jwtInfo, null, 2)}`)
// If JWT if valid, evaluate the API level for the user.
if (jwtInfo.isValid) {
// Set fine-grain permissions for each user based on the JWT token.
const userPermissions = evalUserPermissioins(req, jwtInfo)
- console.log(
- `userPermissions: ${JSON.stringify(userPermissions, null, 2)}`
- )
- console.log(` `)
+ // console.log(
+ // `userPermissions: ${JSON.stringify(userPermissions, null, 2)}`
+ // )
req.locals.proLimit = userPermissions.proLimit
req.locals.apiLevel = userPermissions.apiLevel
@@ -162,7 +161,7 @@ const routeRateLimit = async function(req, res, next) {
// uses its output to adjust rate limits on-the-fly based on the users
// permission level.
function evalUserPermissioins(req, authData) {
- console.log(`authData: ${JSON.stringify(authData, null, 2)}`)
+ // console.log(`authData: ${JSON.stringify(authData, null, 2)}`)
// Return object with default values
const retObj = {
@@ -173,9 +172,9 @@ function evalUserPermissioins(req, authData) {
const level20Routes = ["insight", "bitcore", "blockbook"]
const locals = req.locals
- console.log(`locals: ${JSON.stringify(locals, null, 2)}`)
+ // console.log(`locals: ${JSON.stringify(locals, null, 2)}`)
const url = req.url
- console.log(`url: ${JSON.stringify(url, null, 2)}`)
+ // console.log(`url: ${JSON.stringify(url, null, 2)}`)
if (authData.apiLevel < 20) {
// Loop through the routes that are not accessible to this tier.
diff --git a/src/routes/v3/full-node/control.js b/src/routes/v3/full-node/control.js
index e2e6374..1a0ae1e 100644
--- a/src/routes/v3/full-node/control.js
+++ b/src/routes/v3/full-node/control.js
@@ -36,8 +36,6 @@ async function getNetworkInfo(req, res, next) {
requestConfig
} = routeUtils.setEnvVars()
- console.log(`req.locals: ${JSON.stringify(req.locals, null, 2)}`)
-
requestConfig.data.id = "getnetworkinfo"
requestConfig.data.method = "getnetworkinfo"
requestConfig.data.params = []
From 4079bbdd4850b8da129f4396a7442dbd6d0c4fee Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Sun, 3 Nov 2019 17:33:34 -0800
Subject: [PATCH 11/49] fix(array limits): 20 elem array enforcement for all
tiers
---
src/routes/v3/route-utils.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/routes/v3/route-utils.js b/src/routes/v3/route-utils.js
index be11a4e..d49b29d 100644
--- a/src/routes/v3/route-utils.js
+++ b/src/routes/v3/route-utils.js
@@ -26,7 +26,7 @@ module.exports = {
// or not.
function validateArraySize(req, array) {
const FREEMIUM_INPUT_SIZE = 20
- const PRO_INPUT_SIZE = 100
+ const PRO_INPUT_SIZE = 20
if (req.locals && req.locals.proLimit) {
if (array.length <= PRO_INPUT_SIZE) return true
From b158321e7978d35ffc8cad2fbf6611f69041e9c7 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com>
Date: Mon, 4 Nov 2019 19:05:06 +0000
Subject: [PATCH 12/49] fix(package): update @chris.troutner/bch-js to version
2.0.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 36617f3..88ec0eb 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,7 @@
"node": ">=10.15.1"
},
"dependencies": {
- "@chris.troutner/bch-js": "^1.6.1",
+ "@chris.troutner/bch-js": "^2.0.0",
"apidoc": "^0.17.7",
"axios": "^0.19.0",
"body-parser": "^1.18.3",
From 5d571ea0bc50435d92a5db62ed7c904f4534f510 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com>
Date: Mon, 4 Nov 2019 19:05:11 +0000
Subject: [PATCH 13/49] chore(package): update lockfile package-lock.json
---
package-lock.json | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 6070ee0..d24396a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -101,9 +101,9 @@
}
},
"@chris.troutner/bch-js": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@chris.troutner/bch-js/-/bch-js-1.6.1.tgz",
- "integrity": "sha512-Wkv7iVw9wYjNF5/Ewy5Qq995x1AV+DWRqikZg9FQxCl7Tub7PmmDfADcJwp+tNKGZs5Q+dpiL30P6zBld52g7g==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@chris.troutner/bch-js/-/bch-js-2.0.0.tgz",
+ "integrity": "sha512-ufb2pthdZtXAOVkB/G1jhTrdRML9moIaN8F28rBTq8I7nfh59A4MSRtgr5lFvahs/sHsWmhYu5OAVoSZKDADWA==",
"requires": {
"apidoc": "^0.17.7",
"assert": "^2.0.0",
@@ -1543,12 +1543,22 @@
}
},
"bchaddrjs-slp": {
- "version": "0.2.5",
- "resolved": "https://registry.npmjs.org/bchaddrjs-slp/-/bchaddrjs-slp-0.2.5.tgz",
- "integrity": "sha512-33flmPcqMFswerKu7477DSUNMVMQR3tHDk3lvbmsdkEva+TxVGGWWE/p5Lqx9M/8t3vkbe7fzmVhj4QhChcCyA==",
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/bchaddrjs-slp/-/bchaddrjs-slp-0.2.7.tgz",
+ "integrity": "sha512-wqd4RFMGWzT3ukNbIzLR3pG6EMpcbCUcqXHa0UsegNKkKXZUFXg3dIfa01MRFr4R9D4jnJgDCgY0pa4B4ih4vQ==",
"requires": {
"bs58check": "^2.1.2",
- "cashaddrjs-slp": "^0.2.11"
+ "cashaddrjs-slp": "^0.2.12"
+ },
+ "dependencies": {
+ "cashaddrjs-slp": {
+ "version": "0.2.12",
+ "resolved": "https://registry.npmjs.org/cashaddrjs-slp/-/cashaddrjs-slp-0.2.12.tgz",
+ "integrity": "sha512-n2TTIuW6vZZxYvjvsUAA+wOM0Zkj+3RRKUtDC1XSu4Ic4XVr0yFJkl1bzQkHWda7nkVT51sxjZneygz7D0SyrQ==",
+ "requires": {
+ "big-integer": "^1.6.34"
+ }
+ }
}
},
"bcrypt-pbkdf": {
From eb6b2e6ff34837a700c10b50f9ae21af2d60e3e3 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Wed, 13 Nov 2019 08:09:58 -0800
Subject: [PATCH 14/49] Commented out failing unit tests
---
test/v3/rate-limits.js | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/test/v3/rate-limits.js b/test/v3/rate-limits.js
index 6f74c42..50d7ca6 100644
--- a/test/v3/rate-limits.js
+++ b/test/v3/rate-limits.js
@@ -72,6 +72,9 @@ describe("#route-ratelimits & jwt-auth", () => {
})
})
+ // TODO: This code has been refactored and these unit tests no longer apply.
+ // I think I forgot to create new unit tests to reflect the change in code though.
+ /*
describe("#routeAccess", () => {
it("should do nothing if req.locals.jwtToken is undefined", () => {
// Initialize req.locals
@@ -141,6 +144,7 @@ describe("#route-ratelimits & jwt-auth", () => {
}
})
})
+ */
})
describe("#routeRateLimit", () => {
From ccac98dd5e031bcec1dfae4caf73b7c393c81004 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Wed, 13 Nov 2019 08:40:37 -0800
Subject: [PATCH 15/49] Fixed integration test for gettxout
---
src/routes/v3/full-node/blockchain.js | 2 ++
test/v3/blockchain.js | 5 +++--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/routes/v3/full-node/blockchain.js b/src/routes/v3/full-node/blockchain.js
index 8e2403b..cd3d556 100644
--- a/src/routes/v3/full-node/blockchain.js
+++ b/src/routes/v3/full-node/blockchain.js
@@ -732,6 +732,8 @@ async function getTxOut(req, res, next) {
requestConfig.data.method = "gettxout"
requestConfig.data.params = [txid, n, include_mempool]
+ // console.log(`requestConfig: ${JSON.stringify(requestConfig, null, 2)}`)
+
const response = await BitboxHTTP(requestConfig)
return res.json(response.data.result)
diff --git a/test/v3/blockchain.js b/test/v3/blockchain.js
index fe1d70b..aee8ed5 100644
--- a/test/v3/blockchain.js
+++ b/test/v3/blockchain.js
@@ -840,11 +840,12 @@ describe("#BlockchainRouter", () => {
.reply(200, { result: mockData.mockTxOut })
}
- req.params.txid = `2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266`
+ req.params.txid = `197dcda59864b1eee05498fd3c52cad787ec56ab7e635503cb39f9ab6f295d5d`
req.params.n = 1
+ req.query.include_mempool = "true"
const result = await getTxOut(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
+ // console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, [
"bestblock",
From 1f6f96721dd1897ab2214ecfa113711e6348246d Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Wed, 13 Nov 2019 08:47:08 -0800
Subject: [PATCH 16/49] Fixed communication with Insight API
---
src/routes/v3/insight/address.js | 14 +++++++++-----
test/v3/insight-address.js | 2 +-
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/src/routes/v3/insight/address.js b/src/routes/v3/insight/address.js
index 165156a..9603682 100644
--- a/src/routes/v3/insight/address.js
+++ b/src/routes/v3/insight/address.js
@@ -45,8 +45,8 @@ function root(req, res, next) {
// Returns a Promise.
async function detailsFromInsight(thisAddress, currentPage = 0) {
try {
- //const addr = bchjs.Address.toLegacyAddress(thisAddress)
- const addr = bchjs.Address.toCashAddress(thisAddress)
+ const addr = bchjs.Address.toLegacyAddress(thisAddress)
+ // const addr = bchjs.Address.toCashAddress(thisAddress)
let path = `${process.env.BITCOINCOM_BASEURL}addr/${addr}`
@@ -56,12 +56,12 @@ async function detailsFromInsight(thisAddress, currentPage = 0) {
const to = from + PAGE_SIZE
path = `${path}?from=${from}&to=${to}`
- //console.log(`insight path: ${path}`)
+ // console.log(`insight path: ${path}`)
// Query the Insight server.
const axiosResponse = await axios.get(path)
const retData = axiosResponse.data
- //console.log(`retData: ${util.inspect(retData)}`)
+ // console.log(`retData: ${util.inspect(retData)}`)
// Calculate pagesTotal from response
const pagesTotal = Math.ceil(retData.txApperances / PAGE_SIZE)
@@ -254,7 +254,8 @@ async function detailsSingle(req, res, next) {
// Retrieve UTXO data from the Insight API
async function utxoFromInsight(thisAddress) {
try {
- const addr = bchjs.Address.toCashAddress(thisAddress)
+ const addr = bchjs.Address.toLegacyAddress(thisAddress)
+ // const addr = bchjs.Address.toCashAddress(thisAddress)
const path = `${process.env.BITCOINCOM_BASEURL}addr/${addr}/utxo`
@@ -288,6 +289,7 @@ async function utxoFromInsight(thisAddress) {
throw err
}
}
+
/**
* @api {post} /address/utxo Get Address utxos bulk.
* @apiName Address utxos bulk.
@@ -449,6 +451,7 @@ async function utxoSingle(req, res, next) {
return res.json({ error: util.inspect(err) })
}
}
+
/**
* @api {post} /address/utxo Get Unconfirmed transactions bulk.
* @apiName Unconfirmed transactions bulk
@@ -545,6 +548,7 @@ async function unconfirmedBulk(req, res, next) {
return res.json({ error: util.inspect(err) })
}
}
+
/**
* @api {get} /insight/address/utxo/{address} Get Unconfirmed transactions single.
* @apiName Unconfirmed transactions single.
diff --git a/test/v3/insight-address.js b/test/v3/insight-address.js
index e5a280b..992141b 100644
--- a/test/v3/insight-address.js
+++ b/test/v3/insight-address.js
@@ -197,7 +197,7 @@ describe("#Insight Address", () => {
// Call the details API.
const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
+ // console.log(`result: ${util.inspect(result)}`)
// Assert current page defaults to 0
assert.equal(result[0].currentPage, 0)
From 8eac534d26095eb7f41aa821237f8e09d9824193 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com>
Date: Wed, 13 Nov 2019 16:57:48 +0000
Subject: [PATCH 17/49] fix(package): update apidoc to version 0.18.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 36617f3..41fdde3 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
},
"dependencies": {
"@chris.troutner/bch-js": "^1.6.1",
- "apidoc": "^0.17.7",
+ "apidoc": "^0.18.0",
"axios": "^0.19.0",
"body-parser": "^1.18.3",
"cookie-parser": "~1.4.3",
From 252e6b02e6ce121a3c1c31e97332e832de689d51 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com>
Date: Wed, 13 Nov 2019 16:57:53 +0000
Subject: [PATCH 18/49] chore(package): update lockfile package-lock.json
---
package-lock.json | 53 ++++++++++++++---------------------------------
1 file changed, 16 insertions(+), 37 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 6070ee0..f670a41 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -105,7 +105,6 @@
"resolved": "https://registry.npmjs.org/@chris.troutner/bch-js/-/bch-js-1.6.1.tgz",
"integrity": "sha512-Wkv7iVw9wYjNF5/Ewy5Qq995x1AV+DWRqikZg9FQxCl7Tub7PmmDfADcJwp+tNKGZs5Q+dpiL30P6zBld52g7g==",
"requires": {
- "apidoc": "^0.17.7",
"assert": "^2.0.0",
"axios": "^0.19.0",
"bc-bip68": "^1.0.5",
@@ -905,40 +904,22 @@
}
},
"apidoc": {
- "version": "0.17.7",
- "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.17.7.tgz",
- "integrity": "sha512-9Wf4bRPwCuWOIOxR42dDnsXnFw+rhJg5VrMQK+KmNxJwyIh30UqX6gvjjXSG6YO74MqE87F18bbQXUENK9dPGg==",
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.18.0.tgz",
+ "integrity": "sha512-6gDuxCizXYzFap5JVEdXsATvVsx0Q2waZO39AHhFxFdikvfQ37U8GKASgJugTJNltWjnyUj2YasquUZw19Wmeg==",
"requires": {
- "apidoc-core": "~0.8.2",
- "commander": "^2.19.0",
- "fs-extra": "^7.0.0",
- "lodash": "^4.17.10",
- "markdown-it": "^8.3.1",
- "winston": "^3.0.0"
+ "apidoc-core": "~0.8.3",
+ "commander": "^2.20.0",
+ "fs-extra": "^8.1.0",
+ "lodash": "^4.17.15",
+ "markdown-it": "^10.0.0",
+ "winston": "^3.2.1"
},
"dependencies": {
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
- },
- "fs-extra": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
- "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
- "requires": {
- "graceful-fs": "^4.1.2",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
- }
- },
- "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"
- }
}
}
},
@@ -3574,9 +3555,9 @@
}
},
"entities": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
- "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
+ "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
},
"env-ci": {
"version": "4.5.1",
@@ -5231,7 +5212,6 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
- "dev": true,
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
@@ -5242,7 +5222,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
- "dev": true,
"requires": {
"graceful-fs": "^4.1.6"
}
@@ -7503,12 +7482,12 @@
}
},
"markdown-it": {
- "version": "8.4.2",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz",
- "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
+ "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
"requires": {
"argparse": "^1.0.7",
- "entities": "~1.1.1",
+ "entities": "~2.0.0",
"linkify-it": "^2.0.0",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
From 764c601373ebc61a6889d6687e21fae6ed11e67b Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Wed, 13 Nov 2019 11:59:56 -0800
Subject: [PATCH 19/49] Updated integration tests
---
test/v3/raw-transactions.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/v3/raw-transactions.js b/test/v3/raw-transactions.js
index bf1c78b..014f9b5 100644
--- a/test/v3/raw-transactions.js
+++ b/test/v3/raw-transactions.js
@@ -692,7 +692,7 @@ describe("#Raw-Transactions", () => {
// Integration test
} else {
assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "transaction already in block chain")
+ assert.include(result.error, "Missing inputs")
}
})
})
@@ -800,7 +800,7 @@ describe("#Raw-Transactions", () => {
// Integration test
} else {
assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "transaction already in block chain")
+ assert.include(result.error, "Missing inputs")
}
})
})
From 8be3428e6f9e6228c72dacc4aa997574f16fa6d1 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Mon, 18 Nov 2019 20:08:49 -0800
Subject: [PATCH 20/49] Fixing broken integration test
---
test/v3/blockchain.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/v3/blockchain.js b/test/v3/blockchain.js
index aee8ed5..7a75b08 100644
--- a/test/v3/blockchain.js
+++ b/test/v3/blockchain.js
@@ -841,7 +841,7 @@ describe("#BlockchainRouter", () => {
}
req.params.txid = `197dcda59864b1eee05498fd3c52cad787ec56ab7e635503cb39f9ab6f295d5d`
- req.params.n = 1
+ req.params.n = 0
req.query.include_mempool = "true"
const result = await getTxOut(req, res)
From 719490d852874cd895d00f2de6719db8fe0db94d Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Mon, 18 Nov 2019 21:04:12 -0800
Subject: [PATCH 21/49] fix(request logging): Logging requests to winston
---
src/app.js | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/src/app.js b/src/app.js
index 26f8020..9aa93d1 100644
--- a/src/app.js
+++ b/src/app.js
@@ -57,7 +57,19 @@ app.set("view engine", "jade")
// Mount the docs
app.use("/docs", express.static(`${__dirname}/../docs`))
-app.use(logger("dev"))
+// Log each request to the console with IP addresses.
+// app.use(logger("dev"))
+const morganFormat = `:remote-addr :remote-user :method :url :status :response-time ms - :res[content-length] :user-agent`
+app.use(logger(morganFormat))
+
+// Log the same data to the winston logs.
+const logStream = {
+ write: function(message, encoding) {
+ wlogger.info(`request: ${message}`)
+ }
+}
+app.use(logger(morganFormat, { stream: logStream }))
+
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
app.use(cookieParser())
From 6d4dafdc14680a85aa31ec7f008cd547af5eb8af Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Mon, 25 Nov 2019 20:44:37 -0800
Subject: [PATCH 22/49] Removing slp-sdk and slpjs dependencies
---
package-lock.json | 611 ++----------------------------------------
package.json | 2 -
src/routes/v3/slp.js | 12 -
test/v3/blockchain.js | 2 +-
4 files changed, 16 insertions(+), 611 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 8149bb8..638bc0f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -335,9 +335,9 @@
}
},
"@semantic-release/npm": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-5.3.2.tgz",
- "integrity": "sha512-4uE4pYvf5XEWqJPTLCrrmp5zu9XnnLqDjsn+2yrpMICNCpTq3M5g9OD7hwQoolg5v373t2ZnNgdcjsz+lqU0aA==",
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-5.3.4.tgz",
+ "integrity": "sha512-XjITNRA/oOpJ7BfHk/WaOHs1WniYBszTde/bwADjjk1Luacpxg87jbDQVVt/oA3Zlx+MelxACRIEuRiPC5gu8g==",
"dev": true,
"requires": {
"@semantic-release/error": "^2.2.0",
@@ -366,9 +366,9 @@
}
},
"execa": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-3.2.0.tgz",
- "integrity": "sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw==",
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz",
+ "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.0",
@@ -441,9 +441,9 @@
}
},
"path-key": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz",
- "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true
},
"read-pkg": {
@@ -484,9 +484,9 @@
"dev": true
},
"which": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.1.tgz",
- "integrity": "sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
@@ -642,19 +642,6 @@
"integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
"dev": true
},
- "@types/bigi": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/@types/bigi/-/bigi-1.4.2.tgz",
- "integrity": "sha512-St8Vm0x1ApYlU9yNaFx3jBis5JVU6oR/5Xtgvn8+N8Ts8f3ze6kOvAAg0aNkbGMGhhG6PrP0nMOgDI9NMFETkA=="
- },
- "@types/bip39": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/@types/bip39/-/bip39-2.4.2.tgz",
- "integrity": "sha512-Vo9lqOIRq8uoIzEVrV87ZvcIM0PN9t0K3oYZ/CS61fIYKCBdOIM7mlWzXuRvSXrDtVa1uUO2w1cdfufxTC0bzg==",
- "requires": {
- "@types/node": "*"
- }
- },
"@types/events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
@@ -672,11 +659,6 @@
"@types/node": "*"
}
},
- "@types/lodash": {
- "version": "4.14.144",
- "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.144.tgz",
- "integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg=="
- },
"@types/minimatch": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
@@ -694,28 +676,12 @@
"integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
"dev": true
},
- "@types/randombytes": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@types/randombytes/-/randombytes-2.0.0.tgz",
- "integrity": "sha512-bz8PhAVlwN72vqefzxa14DKNT8jK/mV66CSjwdVQM/k3Th3EPKfUtdMniwZgMedQTFuywAsfjnZsg+pEnltaMA==",
- "requires": {
- "@types/node": "*"
- }
- },
"@types/retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
"dev": true
},
- "@types/wif": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@types/wif/-/wif-2.0.1.tgz",
- "integrity": "sha512-FQKvE4EncC8C4qxW9y0psAOs2XVkxSAGIofB8tqNDPSeOsR4OueEf9TED3PHf8xlOquI+m++AXTWjJIS07FNHw==",
- "requires": {
- "@types/node": "*"
- }
- },
"JSONStream": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
@@ -1227,180 +1193,6 @@
}
}
},
- "babel-core": {
- "version": "6.26.3",
- "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz",
- "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==",
- "requires": {
- "babel-code-frame": "^6.26.0",
- "babel-generator": "^6.26.0",
- "babel-helpers": "^6.24.1",
- "babel-messages": "^6.23.0",
- "babel-register": "^6.26.0",
- "babel-runtime": "^6.26.0",
- "babel-template": "^6.26.0",
- "babel-traverse": "^6.26.0",
- "babel-types": "^6.26.0",
- "babylon": "^6.18.0",
- "convert-source-map": "^1.5.1",
- "debug": "^2.6.9",
- "json5": "^0.5.1",
- "lodash": "^4.17.4",
- "minimatch": "^3.0.4",
- "path-is-absolute": "^1.0.1",
- "private": "^0.1.8",
- "slash": "^1.0.0",
- "source-map": "^0.5.7"
- },
- "dependencies": {
- "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"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- }
- }
- },
- "babel-generator": {
- "version": "6.26.1",
- "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
- "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
- "requires": {
- "babel-messages": "^6.23.0",
- "babel-runtime": "^6.26.0",
- "babel-types": "^6.26.0",
- "detect-indent": "^4.0.0",
- "jsesc": "^1.3.0",
- "lodash": "^4.17.4",
- "source-map": "^0.5.7",
- "trim-right": "^1.0.1"
- },
- "dependencies": {
- "jsesc": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
- "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s="
- }
- }
- },
- "babel-helpers": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
- "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
- "requires": {
- "babel-runtime": "^6.22.0",
- "babel-template": "^6.24.1"
- }
- },
- "babel-messages": {
- "version": "6.23.0",
- "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
- "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
- "requires": {
- "babel-runtime": "^6.22.0"
- }
- },
- "babel-register": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
- "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
- "requires": {
- "babel-core": "^6.26.0",
- "babel-runtime": "^6.26.0",
- "core-js": "^2.5.0",
- "home-or-tmp": "^2.0.0",
- "lodash": "^4.17.4",
- "mkdirp": "^0.5.1",
- "source-map-support": "^0.4.15"
- }
- },
- "babel-runtime": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
- "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "requires": {
- "core-js": "^2.4.0",
- "regenerator-runtime": "^0.11.0"
- }
- },
- "babel-template": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
- "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
- "requires": {
- "babel-runtime": "^6.26.0",
- "babel-traverse": "^6.26.0",
- "babel-types": "^6.26.0",
- "babylon": "^6.18.0",
- "lodash": "^4.17.4"
- }
- },
- "babel-traverse": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
- "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
- "requires": {
- "babel-code-frame": "^6.26.0",
- "babel-messages": "^6.23.0",
- "babel-runtime": "^6.26.0",
- "babel-types": "^6.26.0",
- "babylon": "^6.18.0",
- "debug": "^2.6.8",
- "globals": "^9.18.0",
- "invariant": "^2.2.2",
- "lodash": "^4.17.4"
- },
- "dependencies": {
- "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"
- }
- },
- "globals": {
- "version": "9.18.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
- "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ=="
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- }
- }
- },
- "babel-types": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
- "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
- "requires": {
- "babel-runtime": "^6.26.0",
- "esutils": "^2.0.2",
- "lodash": "^4.17.4",
- "to-fast-properties": "^1.0.3"
- },
- "dependencies": {
- "to-fast-properties": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
- "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc="
- }
- }
- },
- "babylon": {
- "version": "6.18.0",
- "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
- "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
- },
"backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
@@ -1674,105 +1466,6 @@
"safe-buffer": "^5.0.1"
}
},
- "bitbox-sdk": {
- "version": "8.10.1",
- "resolved": "https://registry.npmjs.org/bitbox-sdk/-/bitbox-sdk-8.10.1.tgz",
- "integrity": "sha512-7h6JrvwGburPXIAykFpYGgVHD3hCBCEAME2C5mH9uKuCp4AbmqWYBYZhB4PPb6IAwxxXR9dtK7X3rP6PGFFEWA==",
- "requires": {
- "assert": "^1.4.1",
- "axios": "0.19.0",
- "bc-bip68": "^1.0.5",
- "bigi": "^1.4.2",
- "bip-schnorr": "^0.3.0",
- "bip21": "github:Bitcoin-com/bip21",
- "bip32-utils": "github:Bitcoin-com/bip32-utils#0.13.1",
- "bip38": "^2.0.2",
- "bip39": "^2.5.0",
- "bip66": "^1.1.5",
- "bitcoincash-ops": "github:Bitcoin-com/bitcoincash-ops#2.0.0",
- "bitcoincashjs-lib": "github:Bitcoin-com/bitcoincashjs-lib#v4.0.1",
- "bitcoinjs-message": "^2.0.0",
- "bs58": "^4.0.1",
- "cashaddrjs": "^0.2.9",
- "coininfo": "github:Bitcoin-com/coininfo",
- "eventsource": "^1.0.7",
- "randombytes": "^2.0.6",
- "safe-buffer": "^5.1.2",
- "satoshi-bitcoin": "^1.0.4",
- "socket.io": "^2.2.0",
- "socket.io-client": "^2.2.0",
- "wif": "^2.0.6"
- },
- "dependencies": {
- "assert": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
- "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
- "requires": {
- "object-assign": "^4.1.1",
- "util": "0.10.3"
- }
- },
- "bip39": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/bip39/-/bip39-2.6.0.tgz",
- "integrity": "sha512-RrnQRG2EgEoqO24ea+Q/fftuPUZLmrEM3qNhhGsA3PbaXaCW791LTzPuVyx/VprXQcTbPJ3K3UeTna8ZnVl2sg==",
- "requires": {
- "create-hash": "^1.1.0",
- "pbkdf2": "^3.0.9",
- "randombytes": "^2.0.1",
- "safe-buffer": "^5.0.1",
- "unorm": "^1.3.3"
- }
- },
- "bitcoincash-ops": {
- "version": "github:Bitcoin-com/bitcoincash-ops#6ab82cc7326c67236f3b2d9d0457258ac2ef48e3",
- "from": "github:Bitcoin-com/bitcoincash-ops#2.0.0"
- },
- "bitcoincashjs-lib": {
- "version": "github:Bitcoin-com/bitcoincashjs-lib#28447b40a4ccd23913f7ade6589dc7214c99e60a",
- "from": "github:Bitcoin-com/bitcoincashjs-lib#v4.0.1",
- "requires": {
- "bech32": "^1.1.2",
- "bigi": "^1.4.0",
- "bip66": "^1.1.0",
- "bitcoincash-ops": "github:Bitcoin-com/bitcoincash-ops#2.0.0",
- "bs58check": "^2.0.0",
- "create-hash": "^1.1.0",
- "create-hmac": "^1.1.3",
- "ecurve": "^1.0.0",
- "merkle-lib": "^2.0.10",
- "pushdata-bitcoin": "github:Bitcoin-com/pushdata-bitcoin#1.2.1",
- "randombytes": "^2.0.1",
- "safe-buffer": "^5.0.1",
- "typeforce": "^1.11.3",
- "varuint-bitcoin": "^1.0.4",
- "wif": "^2.0.1"
- }
- },
- "cashaddrjs": {
- "version": "0.2.9",
- "resolved": "https://registry.npmjs.org/cashaddrjs/-/cashaddrjs-0.2.9.tgz",
- "integrity": "sha512-DhJF4iAH0/RM3UjHDHKRxzs09YGL9px+oTyizzydanhC7jTyM2aJ+aLKA96vZGTTWayvvr2iDF2l13lpqXiRFg==",
- "requires": {
- "big-integer": "^1.6.34"
- }
- },
- "inherits": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
- "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
- },
- "util": {
- "version": "0.10.3",
- "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
- "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
- "requires": {
- "inherits": "2.0.1"
- }
- }
- }
- },
"bitcoincash-ops": {
"version": "github:christroutner/bitcoincash-ops#6ab82cc7326c67236f3b2d9d0457258ac2ef48e3",
"from": "github:christroutner/bitcoincash-ops"
@@ -1816,45 +1509,6 @@
"varuint-bitcoin": "^1.0.1"
}
},
- "bitcore-lib-cash": {
- "version": "0.19.0",
- "resolved": "https://registry.npmjs.org/bitcore-lib-cash/-/bitcore-lib-cash-0.19.0.tgz",
- "integrity": "sha512-JBD30YS5M2OSUPbXggM257FjWXb5A1pHFn88lZQsqOokgddmdwp45K4APVEsj2iaKLR7uLOnGppSbAWj5Hihwg==",
- "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": {
- "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"
- }
- },
- "inherits": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
- "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
- },
- "lodash": {
- "version": "4.17.11",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
- "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
- }
- }
- },
"bl": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
@@ -2108,11 +1762,6 @@
"ieee754": "^1.1.4"
}
},
- "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-equals": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/buffer-equals/-/buffer-equals-1.0.4.tgz",
@@ -2905,11 +2554,6 @@
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
"dev": true
},
- "core-js": {
- "version": "2.6.10",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz",
- "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA=="
- },
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@@ -3271,14 +2915,6 @@
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
- "detect-indent": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
- "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
- "requires": {
- "repeating": "^2.0.0"
- }
- },
"diagnostics": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz",
@@ -4525,14 +4161,6 @@
"es5-ext": "~0.10.14"
}
},
- "eventsource": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz",
- "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==",
- "requires": {
- "original": "^1.0.0"
- }
- },
"evp_bytestokey": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
@@ -6036,9 +5664,9 @@
"integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA=="
},
"handlebars": {
- "version": "4.5.1",
- "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.1.tgz",
- "integrity": "sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==",
+ "version": "4.5.3",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
+ "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
"requires": {
"neo-async": "^2.6.0",
"optimist": "^0.6.1",
@@ -6288,15 +5916,6 @@
"minimalistic-crypto-utils": "^1.0.1"
}
},
- "home-or-tmp": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
- "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
- "requires": {
- "os-homedir": "^1.0.0",
- "os-tmpdir": "^1.0.1"
- }
- },
"hook-std": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz",
@@ -6569,14 +6188,6 @@
"p-is-promise": "^3.0.0"
}
},
- "invariant": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
- "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
- "requires": {
- "loose-envify": "^1.0.0"
- }
- },
"ipaddr.js": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
@@ -6722,14 +6333,6 @@
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
},
- "is-finite": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
- "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
- "requires": {
- "number-is-nan": "^1.0.0"
- }
- },
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
@@ -7097,11 +6700,6 @@
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
"dev": true
},
- "json5": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
- "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE="
- },
"jsonfile": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz",
@@ -11721,11 +11319,6 @@
"path-key": "^2.0.0"
}
},
- "number-is-nan": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
- },
"nyc": {
"version": "14.1.1",
"resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz",
@@ -12005,14 +11598,6 @@
}
}
},
- "original": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
- "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==",
- "requires": {
- "url-parse": "^1.4.3"
- }
- },
"os-homedir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
@@ -12510,11 +12095,6 @@
"fast-diff": "^1.1.2"
}
},
- "private": {
- "version": "0.1.8",
- "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
- "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg=="
- },
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -12661,11 +12241,6 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.0.tgz",
"integrity": "sha512-27RP4UotQORTpmNQDX8BHPukOnBP3p1uUJY5UnDhaJB+rMt9iMsok724XL+UHU23bEFOHRMQ2ZhI99qOWUMGFA=="
},
- "querystringify": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
- "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA=="
- },
"quick-lru": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz",
@@ -12822,11 +12397,6 @@
"resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz",
"integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA=="
},
- "regenerator-runtime": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
- "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
- },
"regex-not": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
@@ -12892,14 +12462,6 @@
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
"dev": true
},
- "repeating": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
- "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
- "requires": {
- "is-finite": "^1.0.0"
- }
- },
"repl.history": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/repl.history/-/repl.history-0.1.4.tgz",
@@ -12988,11 +12550,6 @@
}
}
},
- "requires-port": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
- "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
- },
"resolve": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
@@ -13646,11 +13203,6 @@
"supports-color": "^5.5.0"
}
},
- "slash": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
- "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU="
- },
"slice-ansi": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
@@ -13659,112 +13211,6 @@
"is-fullwidth-code-point": "^2.0.0"
}
},
- "slp-sdk": {
- "version": "4.13.1",
- "resolved": "https://registry.npmjs.org/slp-sdk/-/slp-sdk-4.13.1.tgz",
- "integrity": "sha512-6ZUBbKldtoRSRvzHyDFMd4FbIQeZIymywJy/mfB+8OJiqEFxdqeqdXti9bbnIF5vT6xQjq6a45LZ6WNPUVhexg==",
- "requires": {
- "@types/bigi": "^1.4.2",
- "@types/bip39": "^2.4.2",
- "@types/randombytes": "^2.0.0",
- "@types/wif": "^2.0.1",
- "axios": "0.19.0",
- "babel-register": "^6.26.0",
- "bignumber.js": "^8.0.2",
- "bitbox-sdk": "8.10.1",
- "chalk": "^2.3.0",
- "clear": "0.1.0",
- "commander": "^2.13.0",
- "figlet": "^1.2.1",
- "git-clone": "^0.1.0",
- "mkdirp": "^0.5.1",
- "node-emoji": "^1.8.1",
- "repl.history": "^0.1.4",
- "slpjs": "0.21.1",
- "touch": "^3.1.0"
- },
- "dependencies": {
- "bchaddrjs-slp": {
- "version": "git://github.com/simpleledger/bchaddrjs.git#ea05d679783a6737f2f99adc37ebf485dc64f006",
- "from": "git://github.com/simpleledger/bchaddrjs.git#master",
- "requires": {
- "bs58check": "^2.1.2",
- "cashaddrjs-slp": "^0.2.11"
- }
- },
- "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=="
- },
- "commander": {
- "version": "2.20.3",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
- "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
- },
- "slpjs": {
- "version": "0.21.1",
- "resolved": "https://registry.npmjs.org/slpjs/-/slpjs-0.21.1.tgz",
- "integrity": "sha512-f030k+bsYOyNuuU7qmbvtQ19Xs75vkvlBZDP965j9Y9O6ehvTtiF5EDzMW5xA3Y4ur0fir01h2KbJPpEncTqqA==",
- "requires": {
- "@types/lodash": "^4.14.120",
- "axios": "^0.18.1",
- "bchaddrjs-slp": "git://github.com/simpleledger/bchaddrjs.git#master",
- "bignumber.js": "^8.1.1",
- "bitcore-lib-cash": "^0.19.0",
- "lodash": "^4.17.14"
- },
- "dependencies": {
- "axios": {
- "version": "0.18.1",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz",
- "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==",
- "requires": {
- "follow-redirects": "1.5.10",
- "is-buffer": "^2.0.2"
- }
- }
- }
- }
- }
- },
- "slpjs": {
- "version": "0.21.4",
- "resolved": "https://registry.npmjs.org/slpjs/-/slpjs-0.21.4.tgz",
- "integrity": "sha512-DkxuhmXD4W+UVpwnxT5NBfoc1JTwGBjADeyZZl0gPfjsWiiVJbos01z6plaiMZyetde6QPARw73jNxVs7SzW8Q==",
- "requires": {
- "@types/lodash": "^4.14.120",
- "axios": "^0.18.1",
- "bchaddrjs-slp": "git://github.com/simpleledger/bchaddrjs.git#master",
- "bignumber.js": "^8.1.1",
- "bitcore-lib-cash": "^0.19.0",
- "lodash": "^4.17.14"
- },
- "dependencies": {
- "axios": {
- "version": "0.18.1",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz",
- "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==",
- "requires": {
- "follow-redirects": "1.5.10",
- "is-buffer": "^2.0.2"
- }
- },
- "bchaddrjs-slp": {
- "version": "git://github.com/simpleledger/bchaddrjs.git#ea05d679783a6737f2f99adc37ebf485dc64f006",
- "from": "git://github.com/simpleledger/bchaddrjs.git#master",
- "requires": {
- "bs58check": "^2.1.2",
- "cashaddrjs-slp": "^0.2.11"
- }
- },
- "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=="
- }
- }
- },
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -13999,14 +13445,6 @@
"urix": "^0.1.0"
}
},
- "source-map-support": {
- "version": "0.4.18",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
- "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
- "requires": {
- "source-map": "^0.5.6"
- }
- },
"source-map-url": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
@@ -14740,11 +14178,6 @@
"integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=",
"dev": true
},
- "trim-right": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
- "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM="
- },
"triple-beam": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
@@ -14940,11 +14373,6 @@
"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",
@@ -15041,15 +14469,6 @@
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
"dev": true
},
- "url-parse": {
- "version": "1.4.7",
- "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz",
- "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==",
- "requires": {
- "querystringify": "^2.1.1",
- "requires-port": "^1.0.0"
- }
- },
"url-parse-lax": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz",
diff --git a/package.json b/package.json
index cd1070c..fec623c 100644
--- a/package.json
+++ b/package.json
@@ -43,8 +43,6 @@
"passport-http": "^0.3.0",
"pg": "^7.11.0",
"pg-hstore": "^2.3.2",
- "slp-sdk": "^4.4.1",
- "slpjs": "0.21.4",
"strftime": "^0.10.0",
"winston": "^3.2.1",
"winston-daily-rotate-file": "^4.0.0"
diff --git a/src/routes/v3/slp.js b/src/routes/v3/slp.js
index d86c6dc..6f6e1af 100644
--- a/src/routes/v3/slp.js
+++ b/src/routes/v3/slp.js
@@ -13,18 +13,6 @@ const wlogger = require("../../util/winston-logging")
const util = require("util")
util.inspect.defaultOptions = { depth: 5 }
-const SLPSDK = require("slp-sdk")
-const SLP = new SLPSDK()
-
-// Instantiate SLPJS.
-const slp = require("slpjs")
-const slpjs = new slp.Slp(SLP)
-const utils = slp.Utils
-
-// SLP tx db (LevelDB for caching)
-// const level = require("level")
-// const slpTxDb = level("./slp-tx-db")
-
// Setup JSON RPC
const BitboxHTTP = axios.create({
baseURL: process.env.RPC_BASEURL
diff --git a/test/v3/blockchain.js b/test/v3/blockchain.js
index 7a75b08..2607e70 100644
--- a/test/v3/blockchain.js
+++ b/test/v3/blockchain.js
@@ -107,7 +107,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
From a9ec0acc1a0c1d6e5a94ca2ff8cf938fa7ce6497 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Mon, 25 Nov 2019 20:47:36 -0800
Subject: [PATCH 23/49] fix(unit tests): Fixing unit tests for 503 network
errors
---
test/v3/blockchain.js | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/test/v3/blockchain.js b/test/v3/blockchain.js
index 2607e70..503e08a 100644
--- a/test/v3/blockchain.js
+++ b/test/v3/blockchain.js
@@ -149,7 +149,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -201,7 +201,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -252,7 +252,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Network error: Could not communicate with full node",
@@ -499,7 +499,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -540,7 +540,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -580,7 +580,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -626,7 +626,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -678,7 +678,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -823,7 +823,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -891,7 +891,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -1028,7 +1028,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
From b6b8d54cdacd700cae23d54480f43cb84704ab1c Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Mon, 25 Nov 2019 20:57:02 -0800
Subject: [PATCH 24/49] Handling EAI_AGAIN error
---
src/routes/v3/route-utils.js | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/routes/v3/route-utils.js b/src/routes/v3/route-utils.js
index d49b29d..38652fc 100644
--- a/src/routes/v3/route-utils.js
+++ b/src/routes/v3/route-utils.js
@@ -131,6 +131,15 @@ function decodeError(err) {
}
}
+ // Different kind of network error
+ if (err.message && err.message.indexOf("EAI_AGAIN") > -1) {
+ return {
+ msg:
+ "Network error: Could not communicate with full node or other external service.",
+ status: 503
+ }
+ }
+
return { msg: false, status: 500 }
} catch (err) {
wlogger.error(`unhandled error in route-utils.js/decodeError(): `, err)
From c53b6e09407ddead71ffc653593477ee57fb9833 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Mon, 2 Dec 2019 19:25:10 -0800
Subject: [PATCH 25/49] fix(SLP balancesForAddress): Fixed unit tests
---
src/routes/v3/slp.js | 11 +++++++----
test/v3/slp.js | 4 ++--
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/routes/v3/slp.js b/src/routes/v3/slp.js
index 6f6e1af..40357a7 100644
--- a/src/routes/v3/slp.js
+++ b/src/routes/v3/slp.js
@@ -9,6 +9,9 @@ const routeUtils = require("./route-utils")
const strftime = require("strftime")
const wlogger = require("../../util/winston-logging")
+const BCHJS = require("@chris.troutner/bch-js")
+const bchjs = new BCHJS()
+
// Used to convert error messages to strings, to safely pass to users.
const util = require("util")
util.inspect.defaultOptions = { depth: 5 }
@@ -363,7 +366,7 @@ async function balancesForAddress(req, res, next) {
// Ensure the input is a valid BCH address.
try {
- const cash = utils.toCashAddress(address)
+ const cash = bchjs.SLP.Address.toCashAddress(address)
} catch (err) {
res.status(400)
return res.json({
@@ -372,7 +375,7 @@ async function balancesForAddress(req, res, next) {
}
// Prevent a common user error. Ensure they are using the correct network address.
- const cashAddr = utils.toCashAddress(address)
+ const cashAddr = bchjs.SLP.Address.toCashAddress(address)
const networkIsValid = routeUtils.validateNetwork(cashAddr)
if (!networkIsValid) {
res.status(400)
@@ -386,7 +389,7 @@ async function balancesForAddress(req, res, next) {
q: {
db: ["a"],
find: {
- address: SLP.Address.toSLPAddress(address),
+ address: bchjs.SLP.Address.toSLPAddress(address),
token_balance: { $gte: 0 }
},
limit: 10000
@@ -469,7 +472,7 @@ async function balancesForAddress(req, res, next) {
res.status(500)
return res.json({
- error: `Error in /ddress/:address: ${err.message}`
+ error: `Error in /address/:address: ${err.message}`
})
}
}
diff --git a/test/v3/slp.js b/test/v3/slp.js
index 3592ae9..6a2440c 100644
--- a/test/v3/slp.js
+++ b/test/v3/slp.js
@@ -429,7 +429,7 @@ describe("#SLP", () => {
])
})
})
-
+*/
describe("balancesForAddress()", () => {
const balancesForAddress = slpRoute.testableComponents.balancesForAddress
@@ -513,7 +513,7 @@ describe("#SLP", () => {
])
})
})
-
+ /*
describe("balancesForAddressBulk()", () => {
const balancesForAddressBulk =
slpRoute.testableComponents.balancesForAddressBulk
From 3e26fd2a8907bd48138d4c87ef9d67b876f1cc94 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Mon, 2 Dec 2019 19:31:00 -0800
Subject: [PATCH 26/49] Fixed unit and integration tests for balancesForAddress
bulk and single
---
src/routes/v3/slp.js | 6 +++---
test/v3/slp.js | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/routes/v3/slp.js b/src/routes/v3/slp.js
index 40357a7..4c4a4b3 100644
--- a/src/routes/v3/slp.js
+++ b/src/routes/v3/slp.js
@@ -524,7 +524,7 @@ async function balancesForAddressBulk(req, res, next) {
// Ensure the input is a valid BCH address.
try {
- utils.toCashAddress(address)
+ bchjs.SLP.Address.toCashAddress(address)
} catch (err) {
res.status(400)
return res.json({
@@ -533,7 +533,7 @@ async function balancesForAddressBulk(req, res, next) {
}
// Prevent a common user error. Ensure they are using the correct network address.
- const cashAddr = utils.toCashAddress(address)
+ const cashAddr = bchjs.SLP.Address.toCashAddress(address)
const networkIsValid = routeUtils.validateNetwork(cashAddr)
if (!networkIsValid) {
res.status(400)
@@ -552,7 +552,7 @@ async function balancesForAddressBulk(req, res, next) {
q: {
db: ["a"],
find: {
- address: SLP.Address.toSLPAddress(address),
+ address: bchjs.SLP.Address.toSLPAddress(address),
token_balance: { $gte: 0 }
},
limit: 10000
diff --git a/test/v3/slp.js b/test/v3/slp.js
index 6a2440c..88f70ae 100644
--- a/test/v3/slp.js
+++ b/test/v3/slp.js
@@ -513,7 +513,7 @@ describe("#SLP", () => {
])
})
})
- /*
+
describe("balancesForAddressBulk()", () => {
const balancesForAddressBulk =
slpRoute.testableComponents.balancesForAddressBulk
@@ -599,7 +599,7 @@ describe("#SLP", () => {
})
}
})
-
+ /*
describe("balancesForAddressByTokenID()", () => {
const balancesForAddressByTokenID =
slpRoute.testableComponents.balancesForAddressByTokenID
From fb6a54f8f51fabd597ad1101ae0bb1073fc6a29e Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Wed, 4 Dec 2019 06:57:53 -0800
Subject: [PATCH 27/49] Ran npm audit fix
---
package-lock.json | 38 +++++++++++++++-----------------------
1 file changed, 15 insertions(+), 23 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 606dc24..f5b6bb3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1969,14 +1969,6 @@
}
}
},
- "cashaddrjs-slp": {
- "version": "0.2.11",
- "resolved": "https://registry.npmjs.org/cashaddrjs-slp/-/cashaddrjs-slp-0.2.11.tgz",
- "integrity": "sha512-c6od4HHecD+1aEl0WmTEw+ncWBKZNqRW9Q8F+jwB1m1VozbNAmcwy0P8ihVD+cZEpwiviFyOva2simH2txINwg==",
- "requires": {
- "big-integer": "^1.6.34"
- }
- },
"chai": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
@@ -7836,9 +7828,9 @@
"dev": true
},
"npm": {
- "version": "6.12.1",
- "resolved": "https://registry.npmjs.org/npm/-/npm-6.12.1.tgz",
- "integrity": "sha512-+pMvUpgSXVBythrv//64j4i6DaLLJ1O0y8kwjNgjAE7atBNGzX4rcOEWvmsuiei6J+mA38O0nUZ/P35GuCD/jg==",
+ "version": "6.13.2",
+ "resolved": "https://registry.npmjs.org/npm/-/npm-6.13.2.tgz",
+ "integrity": "sha512-TG7AFkKpjBNJh8OVJYcGaAbW0PZxEkjew51Lc6TRdhQpNjSSEnAOEpidApqEuciB7cs09C8mxbo8NbuPs4QDzg==",
"dev": true,
"requires": {
"JSONStream": "^1.3.5",
@@ -7926,14 +7918,14 @@
"once": "~1.4.0",
"opener": "^1.5.1",
"osenv": "^0.1.5",
- "pacote": "^9.5.8",
+ "pacote": "^9.5.9",
"path-is-inside": "~1.0.2",
"promise-inflight": "~1.0.1",
"qrcode-terminal": "^0.12.0",
"query-string": "^6.8.2",
"qw": "~1.0.1",
"read": "~1.0.7",
- "read-cmd-shim": "^1.0.4",
+ "read-cmd-shim": "^1.0.5",
"read-installed": "~4.0.3",
"read-package-json": "^2.1.0",
"read-package-tree": "^5.3.1",
@@ -9162,7 +9154,7 @@
}
},
"https-proxy-agent": {
- "version": "2.2.2",
+ "version": "2.2.4",
"bundled": true,
"dev": true,
"requires": {
@@ -9749,7 +9741,7 @@
}
},
"make-fetch-happen": {
- "version": "5.0.0",
+ "version": "5.0.2",
"bundled": true,
"dev": true,
"requires": {
@@ -9757,7 +9749,7 @@
"cacache": "^12.0.0",
"http-cache-semantics": "^3.8.1",
"http-proxy-agent": "^2.1.0",
- "https-proxy-agent": "^2.2.1",
+ "https-proxy-agent": "^2.2.3",
"lru-cache": "^5.1.1",
"mississippi": "^3.0.0",
"node-fetch-npm": "^2.0.2",
@@ -10198,7 +10190,7 @@
}
},
"pacote": {
- "version": "9.5.8",
+ "version": "9.5.9",
"bundled": true,
"dev": true,
"requires": {
@@ -10234,7 +10226,7 @@
},
"dependencies": {
"minipass": {
- "version": "2.3.5",
+ "version": "2.9.0",
"bundled": true,
"dev": true,
"requires": {
@@ -10467,7 +10459,7 @@
}
},
"read-cmd-shim": {
- "version": "1.0.4",
+ "version": "1.0.5",
"bundled": true,
"dev": true,
"requires": {
@@ -10683,17 +10675,17 @@
"dev": true
},
"smart-buffer": {
- "version": "4.0.2",
+ "version": "4.1.0",
"bundled": true,
"dev": true
},
"socks": {
- "version": "2.3.2",
+ "version": "2.3.3",
"bundled": true,
"dev": true,
"requires": {
- "ip": "^1.1.5",
- "smart-buffer": "4.0.2"
+ "ip": "1.1.5",
+ "smart-buffer": "^4.1.0"
}
},
"socks-proxy-agent": {
From 0c31036940ac4b137b7e256985acd1eff0779253 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Fri, 6 Dec 2019 16:12:29 -0800
Subject: [PATCH 28/49] feat(insight): removing insight API as a downstream
service
---
src/app.js | 8 -
src/routes/v3/bitcore.js | 1 -
src/routes/v3/blockbook.js | 1 -
src/routes/v3/insight/address.js | 891 -------------------------
src/routes/v3/insight/block.js | 324 ---------
src/routes/v3/insight/index.js | 38 --
src/routes/v3/insight/transaction.js | 210 ------
src/routes/v3/services/bitbox.js | 11 -
src/routes/v3/services/requestUtils.js | 20 -
src/routes/v3/slp.js | 8 +-
src/routes/v3/xpub.js | 1 -
11 files changed, 5 insertions(+), 1508 deletions(-)
delete mode 100644 src/routes/v3/insight/address.js
delete mode 100644 src/routes/v3/insight/block.js
delete mode 100644 src/routes/v3/insight/index.js
delete mode 100644 src/routes/v3/insight/transaction.js
delete mode 100644 src/routes/v3/services/bitbox.js
delete mode 100644 src/routes/v3/services/requestUtils.js
diff --git a/src/app.js b/src/app.js
index 9aa93d1..6010573 100644
--- a/src/app.js
+++ b/src/app.js
@@ -32,10 +32,6 @@ const slpV3 = require("./routes/v3/slp")
const xpubV3 = require("./routes/v3/xpub")
const bitcoreV3 = require("./routes/v3/bitcore")
const blockbookV3 = require("./routes/v3/blockbook")
-const insightV3 = require("./routes/v3/insight")
-const insightBlockV3 = require("./routes/v3/insight/block")
-const insightTranactionV3 = require("./routes/v3/insight/transaction")
-const insightAddressV3 = require("./routes/v3/insight/address")
require("dotenv").config()
@@ -98,10 +94,6 @@ app.use(`/${v3prefix}/` + `slp`, slpV3.router)
app.use(`/${v3prefix}/` + `xpub`, xpubV3.router)
app.use(`/${v3prefix}/` + `bitcore`, bitcoreV3.router)
app.use(`/${v3prefix}/` + `blockbook`, blockbookV3.router)
-app.use(`/${v3prefix}/` + `insight`, insightV3.router)
-app.use(`/${v3prefix}/` + `insight/block`, insightBlockV3.router)
-app.use(`/${v3prefix}/` + `insight/transaction`, insightTranactionV3.router)
-app.use(`/${v3prefix}/` + `insight/address`, insightAddressV3.router)
// catch 404 and forward to error handler
app.use((req, res, next) => {
diff --git a/src/routes/v3/bitcore.js b/src/routes/v3/bitcore.js
index 83342fd..6bccd26 100644
--- a/src/routes/v3/bitcore.js
+++ b/src/routes/v3/bitcore.js
@@ -5,7 +5,6 @@
"use strict"
const express = require("express")
-const requestUtils = require("./services/requestUtils")
const axios = require("axios")
const routeUtils = require("./route-utils")
const wlogger = require("../../util/winston-logging")
diff --git a/src/routes/v3/blockbook.js b/src/routes/v3/blockbook.js
index 8b548c1..a499fc5 100644
--- a/src/routes/v3/blockbook.js
+++ b/src/routes/v3/blockbook.js
@@ -5,7 +5,6 @@
"use strict"
const express = require("express")
-const requestUtils = require("./services/requestUtils")
const axios = require("axios")
const routeUtils = require("./route-utils")
const wlogger = require("../../util/winston-logging")
diff --git a/src/routes/v3/insight/address.js b/src/routes/v3/insight/address.js
deleted file mode 100644
index 9603682..0000000
--- a/src/routes/v3/insight/address.js
+++ /dev/null
@@ -1,891 +0,0 @@
-/*
- Address route
-*/
-
-"use strict"
-
-const express = require("express")
-const requestUtils = require("../services/requestUtils")
-const axios = require("axios")
-const routeUtils = require("../route-utils")
-const wlogger = require("../../../util/winston-logging")
-
-//const router = express.Router()
-const router = express.Router()
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BCHJS = require("@chris.troutner/bch-js")
-const bchjs = new BCHJS()
-
-// Use the default (and max) page size of 1000
-// https://github.com/bitpay/insight-api#notes-on-upgrading-from-v03
-const PAGE_SIZE = 1000
-
-// Connect the route endpoints to their handler functions.
-router.get("/", root)
-router.get("/details/:address", detailsSingle)
-router.post("/details", detailsBulk)
-router.post("/utxo", utxoBulk)
-router.get("/utxo/:address", utxoSingle)
-router.post("/unconfirmed", unconfirmedBulk)
-router.get("/unconfirmed/:address", unconfirmedSingle)
-router.get("/transactions/:address", transactionsSingle)
-router.post("/transactions", transactionsBulk)
-router.get("/fromXPub/:xpub", fromXPubSingle)
-
-// Root API endpoint. Simply acknowledges that it exists.
-function root(req, res, next) {
- return res.json({ status: "address" })
-}
-
-// Query the Insight API for details on a single BCH address.
-// Returns a Promise.
-async function detailsFromInsight(thisAddress, currentPage = 0) {
- try {
- const addr = bchjs.Address.toLegacyAddress(thisAddress)
- // const addr = bchjs.Address.toCashAddress(thisAddress)
-
- let path = `${process.env.BITCOINCOM_BASEURL}addr/${addr}`
-
- // Set from and to params based on currentPage and pageSize
- // https://github.com/bitpay/insight-api/blob/master/README.md#notes-on-upgrading-from-v02
- const from = currentPage * PAGE_SIZE
- const to = from + PAGE_SIZE
- path = `${path}?from=${from}&to=${to}`
-
- // console.log(`insight path: ${path}`)
-
- // Query the Insight server.
- const axiosResponse = await axios.get(path)
- const retData = axiosResponse.data
- // console.log(`retData: ${util.inspect(retData)}`)
-
- // Calculate pagesTotal from response
- const pagesTotal = Math.ceil(retData.txApperances / PAGE_SIZE)
-
- // Append different address formats to the return data.
- retData.legacyAddress = bchjs.Address.toLegacyAddress(retData.addrStr)
- retData.cashAddress = bchjs.Address.toCashAddress(retData.addrStr)
- delete retData.addrStr
-
- // Append pagination information to the return data.
- retData.currentPage = currentPage
- retData.pagesTotal = pagesTotal
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-// POST handler for bulk queries on address details
-// curl -d '{"addresses": ["bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr", "bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"]}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v2/address/details
-// curl -d '{"addresses": ["bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr", "bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"], "from": 1, "to": 5}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v2/address/details
-/**
- * @api {post} /address/details Get Address details bulk.
- * @apiName Address details bulk
- * @apiGroup Address
- * @apiDescription Returns the details of multiple addresses.
- *
- *
- * @apiExample Example usage:
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"]}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/details
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"], "from": 1, "to": 5}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/details
- *
- */
-async function detailsBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
- const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
-
- // Reject if addresses is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({
- error: "addresses needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- wlogger.debug(`Executing address/details with these addresses: `, addresses)
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- bchjs.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Loops through each address and creates an array of Promises, querying
- // Insight API in parallel.
- addresses = addresses.map(async (address, index) =>
- detailsFromInsight(address, currentPage)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- //logger.error(`Error in detailsBulk(): `, err)
- wlogger.error(`Error in address.ts/detailsBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler for single address details
-/**
- * @api {get} insight/address/details/{address} Get Address details single.
- * @apiName Address details single
- * @apiGroup Address
- * @apiDescription Returns the details of an address including balance.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/address/details/bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c" -H "accept: application/json"
- *
- *
- */
-async function detailsSingle(req, res, next) {
- try {
- const address = req.params.address
- const currentPage = req.query.page ? parseInt(req.query.page, 10) : 0
-
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(
- `Executing address/detailsSingle with this address: `,
- address
- )
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = bchjs.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await detailsFromInsight(address, currentPage)
-
- // Return the retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in address.ts/detailsSingle: `, err)
- wlogger.error(`Error in address.ts/detailsSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Retrieve UTXO data from the Insight API
-async function utxoFromInsight(thisAddress) {
- try {
- const addr = bchjs.Address.toLegacyAddress(thisAddress)
- // const addr = bchjs.Address.toCashAddress(thisAddress)
-
- const path = `${process.env.BITCOINCOM_BASEURL}addr/${addr}/utxo`
-
- // Query the Insight server.
- const response = await axios.get(path)
-
- // Append different address formats to the return data.
- const retData = {
- utxos: Array,
- legacyAddress: String,
- cashAddress: String,
- scriptPubKey: String
- }
- if (response.data.length && response.data[0].scriptPubKey) {
- const spk = response.data[0].scriptPubKey
- retData.scriptPubKey = spk
- }
- retData.legacyAddress = bchjs.Address.toLegacyAddress(thisAddress)
- retData.cashAddress = bchjs.Address.toCashAddress(thisAddress)
- retData.utxos = response.data.map(utxo => {
- delete utxo.address
- delete utxo.scriptPubKey
- return utxo
- })
- //console.log(`utxoFromInsight retData: ${util.inspect(retData)}`)
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-/**
- * @api {post} /address/utxo Get Address utxos bulk.
- * @apiName Address utxos bulk.
- * @apiGroup Address
- * @apiDescription Returns the utxo of multiple addresses.
- *
- *
- * @apiExample Example usage:
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"]}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/utxo
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"], "from": 1, "to": 5}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/utxo
- *
- */
-// Retrieve UTXO information for an address.
-async function utxoBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
-
- // Reject if address is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({ error: "addresses needs to be an array" })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- bchjs.Address.toLegacyAddress(thisAddress)
- } catch (er) {
- //if (er.message.includes("Unsupported address format"))
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- wlogger.debug(
- `Executing address/utxoBulk with these addresses: `,
- addresses
- )
-
- // Loops through each address and creates an array of Promises, querying
- // Insight API in parallel.
- addresses = addresses.map(async (address, index) =>
- utxoFromInsight(address)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/utxoBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler for single address details
-/**
- * @api {get} /insight/address/utxo/{address} Get Address utxos single.
- * @apiName Address utxos single.
- * @apiGroup Address
- * @apiDescription Returns the list of utxo for an address.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/address/utxo/bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c" -H "accept: application/json"
- *
- *
- */
-async function utxoSingle(req, res, next) {
- try {
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(`Executing address/utxoSingle with this address: `, address)
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = bchjs.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await utxoFromInsight(address)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/utxoSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-/**
- * @api {post} /address/utxo Get Unconfirmed transactions bulk.
- * @apiName Unconfirmed transactions bulk
- * @apiGroup Address
- * @apiDescription Returns the list of unconfirmed transactions for an array of addresses.
- *
- *
- * @apiExample Example usage:
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"]}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/unconfirmed
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"], "from": 1, "to": 5}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/unconfirmed
- *
- */
-// Retrieve any unconfirmed TX information for a given address.
-async function unconfirmedBulk(req, res, next) {
- try {
- const addresses = req.body.addresses
-
- // Reject if address is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({ error: "addresses needs to be an array" })
- }
-
- wlogger.debug(`Executing address/utxo with these addresses: `, addresses)
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- bchjs.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Collect an array of promises.
- const promises = addresses.map(address => utxoFromInsight(address))
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(promises)
-
- // Loop through each result
- const finalResult = result.map(elem => {
- //console.log(`elem: ${util.inspect(elem)}`)
-
- // Filter out confirmed transactions.
- const unconfirmedUtxos = elem.utxos.filter(
- utxo => utxo.confirmations === 0
- )
-
- elem.utxos = unconfirmedUtxos
-
- return elem
- })
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(finalResult)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/unconfirmedBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-/**
- * @api {get} /insight/address/utxo/{address} Get Unconfirmed transactions single.
- * @apiName Unconfirmed transactions single.
- * @apiGroup Address
- * @apiDescription Returns the list of unconfirmed transactions for an address.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/address/unconfirmed/bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c" -H "accept: application/json"
- *
- *
- */
-// GET handler. Retrieve any unconfirmed TX information for a given address.
-async function unconfirmedSingle(req, res, next) {
- try {
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(`Executing address/utxoSingle with this address: `, address)
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = bchjs.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await utxoFromInsight(address)
- //console.log(`retData: ${JSON.stringify(retData,null,2)}`)
-
- // Loop through each returned UTXO.
- const unconfirmedUTXOs = []
- for (let j = 0; j < retData.utxos.length; j++) {
- const thisUtxo = retData.utxos[j]
-
- // Only interested in UTXOs with no confirmations.
- if (thisUtxo.confirmations === 0) unconfirmedUTXOs.push(thisUtxo)
- }
-
- retData.utxos = unconfirmedUTXOs
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/unconfirmedSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Retrieve transaction data from the Insight API
-async function transactionsFromInsight(thisAddress, currentPage = 0) {
- try {
- const path = `${process.env.BITCOINCOM_BASEURL}txs/?address=${thisAddress}&pageNum=${currentPage}`
-
- // Query the Insight server.
- const response = await axios.get(path)
-
- // Append different address formats to the return data.
- const retData = response.data
- retData.legacyAddress = bchjs.Address.toLegacyAddress(thisAddress)
- retData.cashAddress = bchjs.Address.toCashAddress(thisAddress)
- retData.currentPage = currentPage
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-/**
- * @api {post} /address/transactions Get Transactions bulk.
- * @apiName Transactions bulk.
- * @apiGroup Address
- * @apiDescription Returns the list of transactions for an array of addresses.
- *
- *
- * @apiExample Example usage:
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"]}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/transactions
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"], "from": 1, "to": 5}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/transactions
- *
- */
-// Get an array of TX information for a given address.
-async function transactionsBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
- const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
-
- // Reject if address is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({ error: "addresses needs to be an array" })
- }
-
- wlogger.debug(`Executing address/utxo with these addresses: `, addresses)
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- bchjs.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Loop through each address and collect an array of promises.
- addresses = addresses.map(async (address, index) =>
- transactionsFromInsight(address, currentPage)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/transactionsBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-/**
- * @api {get} /insight/address/transactions/{address} Get Transactions single.
- * @apiName Transactions single.
- * @apiGroup Address
- * @apiDescription Returns the list of transactions for an address.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/address/transactions/bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c" -H "accept: application/json"
- *
- *
- */
-// GET handler. Retrieve any unconfirmed TX information for a given address.
-async function transactionsSingle(req, res, next) {
- try {
- const address = req.params.address
- const currentPage = req.query.page ? parseInt(req.query.page, 10) : 0
-
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(
- `Executing address/transactionsSingle with this address: `,
- address
- )
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = bchjs.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await transactionsFromInsight(address, currentPage)
- //console.log(`retData: ${JSON.stringify(retData,null,2)}`)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/transactionsSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-/**
- * @api {get} /insight/address/fromXPub/{xpub} Get FromXPub
- * @apiName FromXPub
- * @apiGroup Address
- * @apiDescription Returns an address for an extended public key and hdpath.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/address/fromXPub/xpub661MyMwAqRbcG4CnhNYoK1r1TKLwQQ1UdC3LHoWFK61rsnzh7Hx35qQ9Z53ucYcE5WvA7GEDXhqqKjSY2e6Y8n7WNVLYHpXCuuX945VPuYn" -H "accept: application/json"
- *
- *
- */
-async function fromXPubSingle(req, res, next) {
- try {
- const xpub = req.params.xpub
- const hdPath = req.query.hdPath ? req.query.hdPath : "0"
-
- if (!xpub || xpub === "") {
- res.status(400)
- return res.json({ error: "xpub can not be empty" })
- }
-
- // Reject if xpub is an array.
- if (Array.isArray(xpub)) {
- res.status(400)
- return res.json({
- error: "xpub can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(`Executing address/fromXPub with this xpub: `, xpub)
-
- const cashAddr = bchjs.Address.fromXPub(xpub, hdPath)
- const legacyAddr = bchjs.Address.toLegacyAddress(cashAddr)
- res.status(200)
- return res.json({
- cashAddress: cashAddr,
- legacyAddress: legacyAddr
- })
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/fromXPubSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- detailsBulk,
- detailsSingle,
- utxoBulk,
- utxoSingle,
- unconfirmedBulk,
- unconfirmedSingle,
- transactionsBulk,
- transactionsSingle,
- fromXPubSingle
- }
-}
diff --git a/src/routes/v3/insight/block.js b/src/routes/v3/insight/block.js
deleted file mode 100644
index d813806..0000000
--- a/src/routes/v3/insight/block.js
+++ /dev/null
@@ -1,324 +0,0 @@
-"use strict"
-
-const express = require("express")
-const requestUtils = require("../services/requestUtils")
-const axios = require("axios")
-const bitbox = require("../services/bitbox")
-const wlogger = require("../../../util/winston-logging")
-
-const routeUtils = require("../route-utils")
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 3 }
-
-const router = express.Router()
-//const BitboxHTTP = bitbox.getInstance()
-
-router.get("/", root)
-router.get("/detailsByHash/:hash", detailsByHashSingle)
-router.post("/detailsByHash", detailsByHashBulk)
-router.get("/detailsByHeight/:height", detailsByHeightSingle)
-router.post("/detailsByHeight", detailsByHeightBulk)
-
-function root(req, res, next) {
- return res.json({ status: "block" })
-}
-/**
- * @api {get} /block/detailsByHash/{hash} Get Block details single.
- * @apiName Block details single
- * @apiGroup Block
- * @apiDescription Returns details about a single block by hash.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/block/detailsByHash/000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201" -H "accept: application/json"
- *
- *
- */
-// Call the insight server to get block details based on the hash.
-async function detailsByHashSingle(req, res, next) {
- try {
- const hash = req.params.hash
-
- // Reject if hash is empty
- if (!hash || hash === "") {
- res.status(400)
- return res.json({ error: "hash must not be empty" })
- }
-
- const response = await axios.get(
- `${process.env.BITCOINCOM_BASEURL}block/${hash}`
- )
- //console.log(`response.data: ${JSON.stringify(response.data,null,2)}`)
-
- const parsed = response.data
- return res.json(parsed)
- } catch (error) {
- //console.log(`error object: ${util.inspect(error)}`)
-
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(error)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- if (error.response && error.response.status === 404) {
- res.status(404)
- return res.json({ error: "Not Found" })
- }
-
- // Write out error to error log.
- //logger.error(`Error in block/detailsByHash: `, error)
- wlogger.error(`Error in block.ts/detailsByHashSingle().`, error)
-
- res.status(500)
- return res.json({ error: util.inspect(error) })
- }
-}
-/**
- * @api {post} /block/detailsByHash Get Block details bulk.
- * @apiName Block details bulk
- * @apiGroup Block
- * @apiDescription Returns retails about multiple blocks by hashes.
- *
- *
- * @apiExample Example usage:
- * curl -d '{"hashes":["0000000000000000040e83398a79a16390897f0d18c92bada6350a19a32ec984","000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201"]}' -H "Content-Type: application/json" "https://mainnet.bchjs.cash/v3/insight/block/detailsByHash"
- * curl -d '{"hashes":["0000000000000000040e83398a79a16390897f0d18c92bada6350a19a32ec984","000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201"], "from": 1, "to": 5}' -H "Content-Type: application/json" "https://mainnet.bchjs.cash/v3/insight/block/detailsByHash"
- *
- */
-async function detailsByHashBulk(req, res, next) {
- try {
- const hashes = req.body.hashes
- //console.log(`hashes: ${JSON.stringify(hashes, null, 2)}`)
-
- // Reject if hashes is not an array.
- if (!Array.isArray(hashes)) {
- res.status(400)
- return res.json({
- error: "hashes needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, hashes)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each hash in the array.
- for (let i = 0; i < hashes.length; i++) {
- const thisHash = hashes[i]
-
- if (thisHash.length !== 64) {
- res.status(400)
- return res.json({
- error: `Invalid hash. Double check your hash is valid: ${thisHash}`
- })
- }
- }
-
- // Loop through each hash and creates an array of promises
- const axiosPromises = hashes.map(async hash =>
- axios.get(`${process.env.BITCOINCOM_BASEURL}block/${hash}`)
- )
-
- // Wait for all parallel promises to return.
- const axiosResult = await axios.all(axiosPromises)
-
- // Extract the data component from the axios response.
- const result = axiosResult.map(x => x.data)
- //console.log(`result: ${util.inspect(result)}`)
-
- res.status(200)
- return res.json(result)
- } catch (error) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(error)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- if (error.response && error.response.status === 404) {
- res.status(404)
- return res.json({ error: "Not Found" })
- }
-
- // Write out error to error log.
- //logger.error(`Error in block/detailsByHash: `, error)
- wlogger.error(`Error in block.ts/detailsByHashBulk().`, error)
-
- res.status(500)
- return res.json({ error: util.inspect(error) })
- }
-}
-/**
- * @api {get} /block/detailsByHeight/{hash} Get Block details single by height.
- * @apiName Block details single by height
- * @apiGroup Block
- * @apiDescription Returns Details about a single block by height.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/block/block/detailsByHeight/500000" -H "accept: application/json"
- *
- *
- */
-// Call the Full Node to get block hash based on height, then call the Insight
-// server to get details from that hash.
-async function detailsByHeightSingle(req, res, next) {
- try {
- const height = req.params.height
-
- // Reject if id is empty
- if (!height || height === "") {
- res.status(400)
- return res.json({ error: "height must not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getblockhash"
- requestConfig.data.method = "getblockhash"
- requestConfig.data.params = [parseInt(height)]
-
- const response = await BitboxHTTP(requestConfig)
-
- const hash = response.data.result
- //console.log(`response.data: ${util.inspect(response.data)}`)
-
- // Call detailsByHashSingle now that the hash has been retrieved.
- req.params.hash = hash
- return detailsByHashSingle(req, res, next)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in control/getInfo: `, error)
- wlogger.error(`Error in block.ts/detailsByHeightSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-/**
- * @api {post} /block/detailsByHash Get Block details bulk by height.
- * @apiName Block details bulk by height
- * @apiGroup Block
- * @apiDescription Returns Bulk details about blocks by heights.
- *
- *
- * @apiExample Example usage:
- * curl -d '{"heights":[499000,500000]}' -H "Content-Type: application/json" "https://mainnet.bchjs.cash/v3/insight/block/detailsByHeight"
- * curl -d '{"heights":[499000,500000], "from": 1, "to": 5}' -H "Content-Type: application/json" "https://mainnet.bchjs.cash/v3/insight/block/detailsByHeight"
- *
- */
-async function detailsByHeightBulk(req, res, next) {
- try {
- const heights = req.body.heights
-
- // Reject if heights is not an array.
- if (!Array.isArray(heights)) {
- res.status(400)
- return res.json({
- error: "heights needs to be an array. Use GET for single height."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, heights)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- wlogger.debug(`Executing detailsByHeight with these heights: `, heights)
-
- // Validate each element in the address array.
- for (let i = 0; i < heights.length; i++) {
- const thisHeight = heights[i]
-
- // Reject if id is empty
- if (!thisHeight || thisHeight === "") {
- res.status(400)
- return res.json({ error: "height must not be empty" })
- }
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each height and creates an array of requests to call in parallel
- const promises = heights.map(async height => {
- requestConfig.data.id = "getblockhash"
- requestConfig.data.method = "getblockhash"
- requestConfig.data.params = [parseInt(height)]
-
- const response = await BitboxHTTP(requestConfig)
-
- const hash = response.data.result
-
- const axiosResult = await axios.get(
- `${process.env.BITCOINCOM_BASEURL}block/${hash}`
- )
-
- return axiosResult.data
- })
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(promises)
-
- res.status(200)
- return res.json(result)
- } catch (error) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(error)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- if (error.response && error.response.status === 404) {
- res.status(404)
- return res.json({ error: "Not Found" })
- }
-
- // Write out error to error log.
- //logger.error(`Error in block/detailsByHash: `, error)
- wlogger.error(`Error in block.ts/detailsByHeightBulk().`, error)
-
- res.status(500)
- return res.json({ error: util.inspect(error) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- detailsByHashSingle,
- detailsByHashBulk,
- detailsByHeightSingle,
- detailsByHeightBulk
- }
-}
diff --git a/src/routes/v3/insight/index.js b/src/routes/v3/insight/index.js
deleted file mode 100644
index 8f3c11f..0000000
--- a/src/routes/v3/insight/index.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- Insight API route
- A parent route that encompases the other libraries.
-*/
-
-"use strict"
-
-const express = require("express")
-const requestUtils = require("../services/requestUtils")
-const axios = require("axios")
-const routeUtils = require("../route-utils")
-const wlogger = require("../../../util/winston-logging")
-
-const router = express.Router()
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-//const BCHJS = require("@chris.troutner/bch-js")
-//const bchjs = new BCHJS()
-
-//const BITCORE_URL = process.env.BITCORE_URL
-
-// Connect the route endpoints to their handler functions.
-router.get("/", root)
-
-// Root API endpoint. Simply acknowledges that it exists.
-function root(req, res, next) {
- return res.json({ status: "address" })
-}
-
-module.exports = {
- router,
- testableComponents: {
- root
- }
-}
diff --git a/src/routes/v3/insight/transaction.js b/src/routes/v3/insight/transaction.js
deleted file mode 100644
index ad6cc29..0000000
--- a/src/routes/v3/insight/transaction.js
+++ /dev/null
@@ -1,210 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("../route-utils")
-const wlogger = require("../../../util/winston-logging")
-
-const BCHJS = require("@chris.troutner/bch-js")
-const bchjs = new BCHJS()
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 3 }
-
-// Manipulates and formats the raw data comming from Insight API.
-const processInputs = tx => {
- // Add legacy and cashaddr to tx vin
- if (tx.vin) {
- tx.vin.forEach(vin => {
- if (!vin.coinbase) {
- vin.value = vin.valueSat
- const address = vin.addr
- if (address) {
- vin.legacyAddress = bchjs.Address.toLegacyAddress(address)
- vin.cashAddress = bchjs.Address.toCashAddress(address)
- delete vin.addr
- }
- delete vin.valueSat
- delete vin.doubleSpentTxID
- }
- })
- }
-
- // Add legacy and cashaddr to tx vout
- if (tx.vout) {
- tx.vout.forEach(vout => {
- // Overwrite value string with value in satoshis
- //vout.value = parseFloat(vout.value) * 100000000
-
- if (vout.scriptPubKey) {
- if (vout.scriptPubKey.addresses) {
- const cashAddrs = []
- vout.scriptPubKey.addresses.forEach(addr => {
- const cashAddr = bchjs.Address.toCashAddress(addr)
- cashAddrs.push(cashAddr)
- })
- vout.scriptPubKey.cashAddrs = cashAddrs
- }
- }
- })
- }
-}
-
-router.get("/", root)
-router.post("/details", detailsBulk)
-router.get("/details/:txid", detailsSingle)
-
-function root(req, res, next) {
- return res.json({ status: "transaction" })
-}
-
-// Retrieve transaction data from the Insight API
-// This function is also used by the SLP route library.
-async function transactionsFromInsight(txid) {
- try {
- const path = `${process.env.BITCOINCOM_BASEURL}tx/${txid}`
-
- // Query the Insight server.
- const response = await axios.get(path)
- //console.log(`Insight output: ${JSON.stringify(response.data, null, 2)}`)
-
- // Parse the data.
- const parsed = response.data
- if (parsed) processInputs(parsed)
-
- return parsed
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-/**
- * @api {post} /transaction/details Get Transaction details bulk.
- * @apiName Transaction details bulk
- * @apiGroup Transaction
- * @apiDescription Returns Bulk Details about a transaction.
- *
- *
- * @apiExample Example usage:
- * curl -X POST "https://mainnet.bchjs.cash/v3/insight/transaction/details" -H "Content-Type: application/json" -d "{"txids":["a5f972572ee1753e2fd2457dd61ce5f40fa2f8a30173d417e49feef7542c96a1","5165dc531aad05d1149bb0f0d9b7bda99c73e2f05e314bcfb5b4bb9ca5e1af5e"]}"
- *
- */
-
-async function detailsBulk(req, res, next) {
- try {
- const txids = req.body.txids
-
- // Reject if address is not an array.
- if (!Array.isArray(txids)) {
- res.status(400)
- return res.json({ error: "txids needs to be an array" })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, txids)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- wlogger.debug(`Executing transaction/details with these txids: `, txids)
-
- // Collect an array of promises
- const promises = txids.map(
- async txid => await transactionsFromInsight(txid)
- )
-
- // Wait for all parallel promises to return.
- const result = await Promise.all(promises)
-
- // Return the array of retrieved transaction information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in transactions.ts/detailsBulk().`, err)
-
- //console.log(`Error in transaction details: `, err)
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler. Retrieve any unconfirmed TX information for a given address.
-/**
- * @api {get} insight/transaction/details/{txid} Get Transaction details single.
- * @apiName Transaction details single
- * @apiGroup Transaction
- * @apiDescription Returns the details about a single transaction.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/transaction/details/fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33" -H "accept: application/json"
- *
- *
- */
-async function detailsSingle(req, res, next) {
- try {
- const txid = req.params.txid
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: "txid can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(txid)) {
- res.status(400)
- return res.json({
- error: "txid can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(
- `Executing transaction.ts/detailsSingle with this txid: `,
- txid
- )
-
- // Query the Insight API.
- const retData = await transactionsFromInsight(txid)
- //console.log(`retData: ${JSON.stringify(retData,null,2)}`)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in transactions.ts/detailsSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- transactionsFromInsight,
- testableComponents: {
- root,
- detailsBulk,
- detailsSingle
- }
-}
diff --git a/src/routes/v3/services/bitbox.js b/src/routes/v3/services/bitbox.js
deleted file mode 100644
index 8fb0414..0000000
--- a/src/routes/v3/services/bitbox.js
+++ /dev/null
@@ -1,11 +0,0 @@
-"use strict"
-
-const axios = require("axios")
-
-const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
-})
-
-const getInstance = () => BitboxHTTP
-
-module.exports = getInstance
diff --git a/src/routes/v3/services/requestUtils.js b/src/routes/v3/services/requestUtils.js
deleted file mode 100644
index 7f64965..0000000
--- a/src/routes/v3/services/requestUtils.js
+++ /dev/null
@@ -1,20 +0,0 @@
-"use strict"
-
-const username = process.env.RPC_USERNAME
-const password = process.env.RPC_PASSWORD
-
-const getRequestConfig = (method, params) => ({
- method: "post",
- auth: {
- username,
- password
- },
- data: {
- jsonrpc: "1.0",
- id: method,
- method,
- params
- }
-})
-
-module.exports = getRequestConfig
diff --git a/src/routes/v3/slp.js b/src/routes/v3/slp.js
index 4c4a4b3..c3eb6eb 100644
--- a/src/routes/v3/slp.js
+++ b/src/routes/v3/slp.js
@@ -27,7 +27,8 @@ const password = process.env.RPC_PASSWORD
// https://gist.github.com/christroutner/fc717ca704dec3dded8b52fae387eab2
const SLPDB_PASS = process.env.SLPDB_PASS ? process.env.SLPDB_PASS : "BITBOX"
-const transactions = require("./insight/transaction")
+// const transactions = require("./insight/transaction")
+const rawtransactions = require("./full-node/rawtransactions")
// Setup REST and TREST URLs used by slpjs
// Dev note: this allows for unit tests to mock the URL.
@@ -1201,8 +1202,9 @@ async function txDetails(req, res, next) {
// console.log(`formatted: ${JSON.stringify(formatted,null,2)}`)
// Get information on the transaction from Insight API.
- const retData = await transactions.transactionsFromInsight(txid)
- // console.log(`retData: ${JSON.stringify(retData,null,2)}`)
+ // const retData = await transactions.transactionsFromInsight(txid)
+ const retData = await rawtransactions.getRawTransactionsFromNode(txid, true)
+ // console.log(`retData: ${JSON.stringify(retData, null, 2)}`)
// Return both the tx data from Insight and the formatted token information.
const response = {
diff --git a/src/routes/v3/xpub.js b/src/routes/v3/xpub.js
index d7da89a..142a75e 100644
--- a/src/routes/v3/xpub.js
+++ b/src/routes/v3/xpub.js
@@ -5,7 +5,6 @@
"use strict"
const express = require("express")
-const requestUtils = require("./services/requestUtils")
const axios = require("axios")
const routeUtils = require("./route-utils")
const wlogger = require("../../util/winston-logging")
From 098f5214e0d11e191dee90751d825ebe2c7f3498 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Fri, 6 Dec 2019 16:15:27 -0800
Subject: [PATCH 29/49] Fixed tests
---
test/v3/block.js | 611 ----------------
test/v3/insight-address.js | 1348 ------------------------------------
test/v3/transaction.js | 333 ---------
3 files changed, 2292 deletions(-)
delete mode 100644 test/v3/block.js
delete mode 100644 test/v3/insight-address.js
delete mode 100644 test/v3/transaction.js
diff --git a/test/v3/block.js b/test/v3/block.js
deleted file mode 100644
index 26477f4..0000000
--- a/test/v3/block.js
+++ /dev/null
@@ -1,611 +0,0 @@
-"use strict"
-
-const blockRoute = require("../../src/routes/v3/insight/block")
-const chai = require("chai")
-const assert = chai.assert
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/block-mock")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Block", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", () => {
- // root route handler.
- const root = blockRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
-
- assert.equal(result.status, "block", "Returns static string")
- })
- })
-
- describe("#detailsByHashSingle", () => {
- const detailsByHash = blockRoute.testableComponents.detailsByHashSingle
-
- it("should throw an error for an empty hash", async () => {
- req.params.hash = ""
-
- const result = await detailsByHash(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hash must not be empty",
- "Proper error message"
- )
- })
-
- it("should throw 50X when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- req.params.hash = "abc123"
- const result = await detailsByHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(res.statusCode, 499, "HTTP status code 50X expected.")
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- })
-
- it("should throw an error for invalid hash", async () => {
- req.params.hash = "abc123"
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.params.hash}`)
- .reply(404, "Not found")
- }
-
- const result = await detailsByHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.include(result.error, "Not found", "Proper error message")
- })
-
- it("should GET /detailsByHash/:hash", async () => {
- req.params.hash =
- "0000000000000000009ff8b38118d540e33c262bf6f78fc6863cc444526dc086"
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.params.hash}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- const result = await detailsByHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "hash",
- "size",
- "height",
- "version",
- "merkleroot",
- "tx",
- "time",
- "nonce",
- "bits",
- "difficulty",
- "chainwork",
- "confirmations",
- "previousblockhash",
- "nextblockhash",
- "reward",
- "isMainChain",
- "poolInfo"
- ])
- assert.isArray(result.tx)
- })
- })
-
- describe("#detailsByHashBulk", () => {
- // details route handler.
- const detailsByHashBulk = blockRoute.testableComponents.detailsByHashBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsByHashBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hashes needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- hashes:
- "0000000000000000009ff8b38118d540e33c262bf6f78fc6863cc444526dc086"
- }
-
- const result = await detailsByHashBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hashes needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.hashes = testArray
-
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw an error for an invalid hash", async () => {
- req.body = {
- hashes: [`abc123`]
- }
-
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid hash", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- hashes: [
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
- ]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsByHashBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single hash", async () => {
- req.body = {
- hashes: [
- "0000000000000000009ff8b38118d540e33c262bf6f78fc6863cc444526dc086"
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[0]}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.equal(result.length, 1, "Array with one entry")
- assert.hasAllKeys(result[0], [
- "bits",
- "chainwork",
- "confirmations",
- "difficulty",
- "hash",
- "height",
- "isMainChain",
- "merkleroot",
- "nextblockhash",
- "nonce",
- "poolInfo",
- "previousblockhash",
- "reward",
- "size",
- "time",
- "tx",
- "version"
- ])
- })
-
- it("should get details for multiple hashes", async () => {
- req.body = {
- hashes: [
- `0000000000000000009ff8b38118d540e33c262bf6f78fc6863cc444526dc086`,
- `0000000000000000009ff8b38118d540e33c262bf6f78fc6863cc444526dc086`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[0]}`)
- .reply(200, mockData.mockBlockDetails)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[1]}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
-
- it("should throw an error if hash not found", async () => {
- req.body = {
- hashes: [
- `00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44abcdef`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[0]}`)
- //.reply(404, { error: { message: "Not Found" } })
- .reply(404, "Not found")
- }
-
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 404, "HTTP status code 404 expected.")
- assert.include(result.error, "Not found", "Proper error message")
- })
- })
-
- describe("Block Details By Height", () => {
- // block route handler.
- const detailsByHeight = blockRoute.testableComponents.detailsByHeightSingle
-
- it("should throw an error for an empty height", async () => {
- req.params.height = ""
-
- const result = await detailsByHeight(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "height must not be empty",
- "Proper error message"
- )
- })
-
- it("should throw 500 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl = process.env.BITCOINCOM_BASEURL
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.height = "abc123"
- const result = await detailsByHeight(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or great expected."
- )
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- })
-
- it("should throw an error for invalid height", async () => {
- req.params.height = "abc123"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- console.log(`process.env.RPC_BASEURL: ${process.env.RPC_BASEURL}`)
- nock(`${process.env.RPC_BASEURL}`)
- .post(uri => uri.includes("/"))
- .reply(500, {
- error: {
- code: -1,
- message: "JSON value is not an integer as expected"
- }
- })
- }
-
- const result = await detailsByHeight(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "JSON value is not an integer as expected",
- "Proper error message"
- )
- })
-
- it("should GET /detailsByHeight/:height", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(uri => uri.includes("/"))
- .reply(200, { result: mockData.mockBlockHash })
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/block/00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79`
- )
- .reply(200, mockData.mockBlockDetails)
- }
-
- req.params.height = 500000
-
- const result = await detailsByHeight(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "hash",
- "size",
- "height",
- "version",
- "merkleroot",
- "tx",
- "time",
- "nonce",
- "bits",
- "difficulty",
- "chainwork",
- "confirmations",
- "previousblockhash",
- "nextblockhash",
- "reward",
- "isMainChain",
- "poolInfo"
- ])
- assert.isArray(result.tx)
- })
- })
-
- describe("#detailsByHeightBulk", () => {
- // details route handler.
- const detailsByHeightBulk =
- blockRoute.testableComponents.detailsByHeightBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsByHeightBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "heights needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single height", async () => {
- req.body = {
- heights: 500000
- }
-
- const result = await detailsByHeightBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "heights needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.heights = testArray
-
- const result = await detailsByHeightBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw error for an invalid height", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(uri => uri.includes("/"))
- .reply(500, {
- error: {
- code: -1,
- message: "JSON value is not an integer as expected"
- }
- })
- }
-
- req.body.heights = [`abc123`]
-
- const result = await detailsByHeightBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body.heights = [`500000`]
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsByHeightBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single height", async () => {
- req.body.heights = [`500000`]
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(uri => uri.includes("/"))
- .reply(200, { result: mockData.mockBlockHash })
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${mockData.mockBlockHash}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHeightBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.equal(result.length, 1, "Array with one entry")
- assert.hasAllKeys(result[0], [
- "bits",
- "chainwork",
- "confirmations",
- "difficulty",
- "hash",
- "height",
- "isMainChain",
- "merkleroot",
- "nextblockhash",
- "nonce",
- "poolInfo",
- "previousblockhash",
- "reward",
- "size",
- "time",
- "tx",
- "version"
- ])
- })
-
- it("should get details for multiple block heights", async () => {
- req.body = {
- heights: [`500000`, `500001`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(uri => uri.includes("/"))
- .times(2)
- .reply(200, { result: mockData.mockBlockHash })
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${mockData.mockBlockHash}`)
- .times(2)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHeightBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
- })
-})
diff --git a/test/v3/insight-address.js b/test/v3/insight-address.js
deleted file mode 100644
index 992141b..0000000
--- a/test/v3/insight-address.js
+++ /dev/null
@@ -1,1348 +0,0 @@
-/*
- TESTS FOR THE ADDRESS.JS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- To-Do:
- -/details/:address
- --Verify to/from query options work correctly.
- -GET /unconfirmed/:address & POST /unconfirmed
- --Should initiate a transfer of BCH to verify unconfirmed TX.
- ---This would be more of an e2e test.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const addressRoute = require("../../src/routes/v3/insight/address")
-const nock = require("nock") // HTTP mocking
-
-let originalUrl // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/address-mock")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Insight Address", () => {
- let req, res
-
- before(() => {
- originalUrl = process.env.BITCOINCOM_BASEURL
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit")
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- // console.log(`Testing type is: ${process.env.TEST}`)
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- process.env.BITCOINCOM_BASEURL = originalUrl
- })
-
- describe("#root", () => {
- // root route handler.
- const root = addressRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
-
- assert.equal(result.status, "address", "Returns static string")
- })
- })
-
- describe("#AddressDetailsBulk", () => {
- // details route handler.
- const detailsBulk = addressRoute.testableComponents.detailsBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsBulk(req, res)
- //console.log(`network issue result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(res.statusCode, 499, "HTTP status code 500 expected.")
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- assert.include(
- result.error,
- "Network error: Could not communicate",
- "Error message expected"
- )
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Assert current page defaults to 0
- assert.equal(result[0].currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`],
- page: 5
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert current page is same as requested
- assert.equal(result[0].currentPage, 5)
- })
-
- it("should calculate the total number of pages", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result[0].pagesTotal, 1)
- })
-
- it("should get details for a single address", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.equal(result.length, 1, "Array with one entry")
- assert.hasAllKeys(result[0], [
- "balance",
- "balanceSat",
- "totalReceived",
- "totalReceivedSat",
- "totalSent",
- "totalSentSat",
- "unconfirmedBalance",
- "unconfirmedBalanceSat",
- "unconfirmedTxApperances",
- "txApperances",
- "transactions",
- "legacyAddress",
- "cashAddress",
- "currentPage",
- "pagesTotal"
- ])
- })
-
- it("should get details for multiple addresses", async () => {
- req.body = {
- addresses: [
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`,
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
- })
-
- describe("#AddressDetailsSingle", () => {
- // details route handler.
- const detailsSingle = addressRoute.testableComponents.detailsSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert current page defaults to 0
- assert.equal(result.currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- req.query.page = 5
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
-
- // Assert current page is same as requested
- assert.equal(result.currentPage, 5)
- })
-
- it("should calculate the total number of pages", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
-
- assert.equal(result.pagesTotal, 1)
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.hasAllKeys(result, [
- "balance",
- "balanceSat",
- "totalReceived",
- "totalReceivedSat",
- "totalSent",
- "totalSentSat",
- "unconfirmedBalance",
- "unconfirmedBalanceSat",
- "unconfirmedTxApperances",
- "txApperances",
- "transactions",
- "legacyAddress",
- "cashAddress",
- "currentPage",
- "pagesTotal"
- ])
- })
- })
-
- describe("#AddressUtxoBulk", () => {
- // utxo route handler.
- const utxoBulk = addressRoute.testableComponents.utxoBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api"
-
- const result = await utxoBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get utxos for a single address", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await utxoBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result, "result should be an array")
-
- // Each element should have these primary properties.
- assert.hasAllKeys(result[0], [
- "utxos",
- "legacyAddress",
- "cashAddress",
- "scriptPubKey"
- ])
-
- // Validate the UTXO data structure.
- assert.hasAnyKeys(result[0].utxos[0], [
- "txid",
- "vout",
- "amount",
- "satoshis",
- "height",
- "confirmations"
- ])
- })
-
- it("should get utxos for mulitple addresses", async () => {
- req.body = {
- addresses: [
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`,
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await utxoBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await utxoBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
- })
-
- describe("#AddressUtxoSingle", () => {
- // details route handler.
- const utxoSingle = addressRoute.testableComponents.utxoSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await utxoSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await utxoSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await utxoSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- const result = await utxoSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await utxoSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await utxoSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Each element should have these primary properties.
- assert.hasAllKeys(result, [
- "utxos",
- "legacyAddress",
- "cashAddress",
- "scriptPubKey"
- ])
-
- // Validate the UTXO data structure.
- assert.hasAnyKeys(result.utxos[0], [
- "txid",
- "vout",
- "amount",
- "satoshis",
- "height",
- "confirmations"
- ])
- })
- })
-
- describe("#AddressUnconfirmedBulk", () => {
- // unconfirmed route handler.
- const unconfirmedBulk = addressRoute.testableComponents.unconfirmedBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- }
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await unconfirmedBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api"
-
- const result = await unconfirmedBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get unconfirmed data for a single address", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await unconfirmedBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
- //console.log(`result[0].utxos: ${util.inspect(result[0].utxos)}`)
-
- assert.isArray(result, "result should be an array")
-
- // Dev note: Unconfirmed TXs are hard to test in an integration test because
- // the nature of an unconfirmed transation is transient. It quickly becomes
- // confirmed and thus should not show up.
- })
-
- it("should get unconfirmed data for an array of addresses", async () => {
- req.body = {
- addresses: [
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`,
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxoDetails)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await unconfirmedBulk(req, res)
-
- assert.isArray(result)
- })
- })
-
- describe("#AddressUnconfirmedSingle", () => {
- // details route handler.
- const unconfirmedSingle = addressRoute.testableComponents.unconfirmedSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await unconfirmedSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await unconfirmedSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await unconfirmedSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- const result = await unconfirmedSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await unconfirmedSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await unconfirmedSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Each element should have these primary properties.
- assert.hasAllKeys(result, [
- "utxos",
- "legacyAddress",
- "cashAddress",
- "scriptPubKey"
- ])
-
- assert.isArray(result.utxos)
- })
- })
-
- describe("#AddressTransactionsBulk", () => {
- // unconfirmed route handler.
- const transactionsBulk = addressRoute.testableComponents.transactionsBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await transactionsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api"
-
- const result = await transactionsBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsBulk(req, res)
-
- // Assert current page defaults to 0
- assert.equal(result[0].currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`],
- page: 5
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsBulk(req, res)
-
- // Assert current page is same as requested
- assert.equal(result[0].currentPage, 5)
- })
-
- it("should get transactions for a single address", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the details API.
- const result = await transactionsBulk(req, res)
-
- assert.isArray(result, "result should be an array")
-
- assert.exists(result[0].pagesTotal)
- assert.exists(result[0].currentPage)
- assert.exists(result[0].txs)
- assert.isArray(result[0].txs)
- assert.exists(result[0].legacyAddress)
- assert.exists(result[0].cashAddress)
- })
-
- it("should get transactions for an array of addresses", async () => {
- req.body = {
- addresses: [
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`,
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the details API.
- const result = await transactionsBulk(req, res)
-
- assert.isArray(result, "result should be an array")
-
- assert.equal(result.length, 2, "Array should have 2 elements")
- })
- })
-
- describe("#AddressTransactionsSingle", () => {
- // details route handler.
- const transactionsSingle =
- addressRoute.testableComponents.transactionsSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await transactionsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await transactionsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await transactionsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- const result = await transactionsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await transactionsSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsSingle(req, res)
-
- // Assert current page defaults to 0
- assert.equal(result.currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- req.query.page = 5
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsSingle(req, res)
-
- // Assert current page is same as requested
- assert.equal(result.currentPage, 5)
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the details API.
- const result = await transactionsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.exists(result.pagesTotal)
- assert.exists(result.currentPage)
- assert.exists(result.txs)
- assert.isArray(result.txs)
- assert.exists(result.legacyAddress)
- assert.exists(result.cashAddress)
- })
- })
-
- describe("#AddressFromXPubSingle", () => {
- // details route handler.
- const fromXPubSingle = addressRoute.testableComponents.fromXPubSingle
-
- it("should throw 400 if xpub is empty", async () => {
- const result = await fromXPubSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "xpub can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.xpub = [
- `tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
- ]
-
- const result = await fromXPubSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "xpub can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.xpub = `tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await fromXPubSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should create an address from xpub", async () => {
- req.params.xpub = `tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
-
- // Mock the Insight URL for unit tests.
- // TODO add unit test
- // if (process.env.TEST === "unit") {
- // nock(`${process.env.BITCOINCOM_BASEURL}`)
- // .get(
- // `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- // )
- // .reply(200, mockData.mockTransactions)
- // }
-
- // Call the details API.
- const result = await fromXPubSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.exists(result.legacyAddress)
- assert.exists(result.cashAddress)
- })
- })
-})
diff --git a/test/v3/transaction.js b/test/v3/transaction.js
deleted file mode 100644
index 2450134..0000000
--- a/test/v3/transaction.js
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- TESTS FOR THE TRANSACTION.TS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- TODO:
- -See "should throw an error for an invalid txid" for detailsSingle:
- --The error handler should be refactored to return an intelligent error message,
- instead of the 503 error it is returning now.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const transactionRoute = require("../../src/routes/v3/insight/transaction")
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/transaction-mocks")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Transactions", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = transactionRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "transaction", "Returns static string")
- })
- })
-
- describe("#detailsBulk", async () => {
- const detailsBulk = transactionRoute.testableComponents.detailsBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single txid", async () => {
- req.body = {
- txids: `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
- }
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid txid", async () => {
- const fakeTXID = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${fakeTXID}`)
- .reply(400, {
- result: { error: "parameter 1 must be hexadecimal string" }
- })
- }
-
- req.body = {
- txids: [fakeTXID]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- })
-
- it("should process a single txid", async () => {
- const txid = `2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid}`)
- .reply(200, mockData.mockDetails)
- }
-
- req.body = {
- txids: [txid]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "txid",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "blockheight",
- "confirmations",
- "time",
- "blocktime",
- "valueOut",
- "size",
- "valueIn",
- "fees"
- ])
- })
-
- it("should process a multiple txids", async () => {
- const txid1 = `2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266`
- const txid2 = `2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid1}`)
- .reply(200, mockData.mockDetails)
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid2}`)
- .reply(200, mockData.mockDetails)
- }
-
- req.body = {
- txids: [txid1, txid2]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "txid",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "blockheight",
- "confirmations",
- "time",
- "blocktime",
- "valueOut",
- "size",
- "valueIn",
- "fees"
- ])
- })
- })
-
- describe("#detailsSingle", () => {
- // details route handler.
- const detailsSingle = transactionRoute.testableComponents.detailsSingle
-
- it("should throw 400 if txid is empty", async () => {
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.txid = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txid can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid txid", async () => {
- if (process.env.TEST !== "unit") {
- req.params.txid = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // The error handling code should probably be updated to respond with a better
- // error message.
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "parameter 1 must be hexadecimal string",
- "Proper error message"
- )
- }
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.txid = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single txid", async () => {
- const txid = `2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266`
- req.params.txid = txid
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid}`)
- .reply(200, mockData.mockDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.hasAllKeys(result, [
- "txid",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "blockheight",
- "confirmations",
- "time",
- "blocktime",
- "valueOut",
- "size",
- "valueIn",
- "fees"
- ])
- assert.isArray(result.vin)
- assert.isArray(result.vout)
- })
- })
-})
From b0c5b4c6817952bdcead29275baa96dd47bb0782 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Fri, 6 Dec 2019 16:17:43 -0800
Subject: [PATCH 30/49] Removed bitcore as a downstream service
---
src/app.js | 2 -
src/routes/v3/bitcore.js | 395 ----------------------
test/v3/integration/bitcore.js | 599 ---------------------------------
3 files changed, 996 deletions(-)
delete mode 100644 src/routes/v3/bitcore.js
delete mode 100644 test/v3/integration/bitcore.js
diff --git a/src/app.js b/src/app.js
index 6010573..54661d7 100644
--- a/src/app.js
+++ b/src/app.js
@@ -30,7 +30,6 @@ const rawtransactionsV3 = require("./routes/v3/full-node/rawtransactions")
const utilV3 = require("./routes/v3/util")
const slpV3 = require("./routes/v3/slp")
const xpubV3 = require("./routes/v3/xpub")
-const bitcoreV3 = require("./routes/v3/bitcore")
const blockbookV3 = require("./routes/v3/blockbook")
require("dotenv").config()
@@ -92,7 +91,6 @@ app.use(`/${v3prefix}/` + `rawtransactions`, rawtransactionsV3.router)
app.use(`/${v3prefix}/` + `util`, utilV3.router)
app.use(`/${v3prefix}/` + `slp`, slpV3.router)
app.use(`/${v3prefix}/` + `xpub`, xpubV3.router)
-app.use(`/${v3prefix}/` + `bitcore`, bitcoreV3.router)
app.use(`/${v3prefix}/` + `blockbook`, blockbookV3.router)
// catch 404 and forward to error handler
diff --git a/src/routes/v3/bitcore.js b/src/routes/v3/bitcore.js
deleted file mode 100644
index 6bccd26..0000000
--- a/src/routes/v3/bitcore.js
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- Bitcore Node API route
-*/
-
-"use strict"
-
-const express = require("express")
-const axios = require("axios")
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
-
-const router = express.Router()
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BCHJS = require("@chris.troutner/bch-js")
-const bchjs = new BCHJS()
-
-//const BITCORE_URL = process.env.BITCORE_URL
-
-// Connect the route endpoints to their handler functions.
-router.get("/", root)
-router.get("/balance/:address", balanceSingle)
-router.post("/balance", balanceBulk)
-router.get("/utxos/:address", utxosSingle)
-router.post("/utxos", utxosBulk)
-
-// Root API endpoint. Simply acknowledges that it exists.
-function root(req, res, next) {
- return res.json({ status: "address" })
-}
-
-// Query the Bitcore Node API for a balance on a single BCH address.
-// Returns a Promise.
-async function balanceFromBitcore(thisAddress) {
- try {
- //console.log(`BITCORE_URL: ${BITCORE_URL}`)
-
- // Convert the address to a cashaddr without a prefix.
- const addr = bchjs.Address.toCashAddress(thisAddress, false)
-
- // Determine if we are working with the testnet or mainnet networks.
- let network = "mainnet"
- if (process.env.NETWORK === "testnet") network = "testnet"
-
- const path = `${process.env.BITCORE_URL}api/BCH/${network}/address/${addr}/balance`
-
- //console.log(`path: ${path}`)
-
- // Query the Bitcore Node API.
- const axiosResponse = await axios.get(path)
- const retData = axiosResponse.data
- //console.log(`retData: ${util.inspect(retData)}`)
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-/**
- * @api {get} /bitcore/balance/:address Get BCH balance for an address
- * @apiName GetBalance
- * @apiGroup Bitcore
- *
- * @apiParam {String} address Bitcoin Cash address.
- *
- * @apiSuccess {String} firstname Firstname of the User.
- * @apiSuccess {String} lastname Lastname of the User.
- */
-// GET handler for single balance
-async function balanceSingle(req, res, next) {
- try {
- const address = req.params.address
-
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(
- `Executing bitcore/balanceSingle with this address: `,
- address
- )
-
- // Ensure the input is a valid BCH address.
- try {
- const legacyAddr = bchjs.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Bitcore Node API.
- const retData = await balanceFromBitcore(address)
-
- // Return the retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- wlogger.error(`Error in bitcore.js/balanceSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// POST handler for bulk queries on address details
-// curl -d '{"addresses": ["bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr", "bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"]}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v2/address/details
-// curl -d '{"addresses": ["bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr", "bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"], "from": 1, "to": 5}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v2/address/details
-async function balanceBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
- const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
-
- // Reject if addresses is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({
- error: "addresses needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- wlogger.debug(
- `Executing bitcore.js/balanceBulk with these addresses: `,
- addresses
- )
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- bchjs.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Loops through each address and creates an array of Promises, querying
- // Insight API in parallel.
- addresses = addresses.map(async (address, index) =>
- balanceFromBitcore(address)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in bitcore.js/balanceBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Query the Bitcore Node API for utxos associated with a BCH address.
-// Returns a Promise.
-async function utxosFromBitcore(thisAddress) {
- try {
- //console.log(`BITCORE_URL: ${BITCORE_URL}`)
-
- // Convert the address to a cashaddr without a prefix.
- const addr = bchjs.Address.toCashAddress(thisAddress, false)
-
- // Determine if we are working with the testnet or mainnet networks.
- let network = "mainnet"
- if (process.env.NETWORK === "testnet") network = "testnet"
-
- const path = `${process.env.BITCORE_URL}api/BCH/${network}/address/${addr}/?unspent=true`
-
- // Query the Bitcore Node API.
- const axiosResponse = await axios.get(path)
- const retData = axiosResponse.data
- //console.log(`retData: ${util.inspect(retData)}`)
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-// GET handler for single balance
-async function utxosSingle(req, res, next) {
- try {
- const address = req.params.address
-
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(`Executing bitcore/utxoSingle with this address: `, address)
-
- // Ensure the input is a valid BCH address.
- try {
- const legacyAddr = bchjs.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Bitcore Node API.
- const retData = await utxosFromBitcore(address)
-
- // Return the retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- wlogger.error(`Error in bitcore.js/utxosSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// POST handler for bulk queries on address utxos
-async function utxosBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
- const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
-
- // Reject if addresses is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({
- error: "addresses needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- wlogger.debug(
- `Executing bitcore.js/utxosBulk with these addresses: `,
- addresses
- )
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- bchjs.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Loops through each address and creates an array of Promises, querying
- // Insight API in parallel.
- addresses = addresses.map(async (address, index) =>
- utxosFromBitcore(address)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in bitcore.js/utxosBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- balanceSingle,
- balanceBulk,
- utxosSingle,
- utxosBulk
- }
-}
diff --git a/test/v3/integration/bitcore.js b/test/v3/integration/bitcore.js
deleted file mode 100644
index fd6cf67..0000000
--- a/test/v3/integration/bitcore.js
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- TESTS FOR THE BITCORE.JS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- To-Do:
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const bitcoreRoute = require("../../src/routes/v3/bitcore")
-const nock = require("nock") // HTTP mocking
-
-let originalUrl // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/bitcore-mock")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Bitcore Router", () => {
- let req, res, mockServerUrl
-
- before(() => {
- originalUrl = process.env.BITCORE_URL
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCORE_URL = "http://fakeurl/api/"
- mockServerUrl = `http://fakeurl`
- }
- // console.log(`Testing type is: ${process.env.TEST}`)
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- process.env.BITCORE_URL = originalUrl
- })
-
- describe("#root", () => {
- // root route handler.
- const root = bitcoreRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
-
- assert.equal(result.status, "address", "Returns static string")
- })
- })
-
- describe("#Balance Single", () => {
- // details route handler.
- const balanceSingle = bitcoreRoute.testableComponents.balanceSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await balanceSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await balanceSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await balanceSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`
-
- const result = await balanceSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCORE_URL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCORE_URL = "http://fakeurl/api/"
-
- const result = await balanceSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCORE_URL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCORE_URL = savedUrl
- }
- })
-
- it("should get balance for a single address", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCORE_URL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockBalance)
- }
-
- // Call the details API.
- const result = await balanceSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["confirmed", "unconfirmed", "balance"])
- assert.isNumber(result.confirmed)
- assert.isNumber(result.unconfirmed)
- assert.isNumber(result.balance)
- })
- })
-
- describe("#Balance Bulk", () => {
- // details route handler.
- const balanceBulk = bitcoreRoute.testableComponents.balanceBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await balanceBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await balanceBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await balanceBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await balanceBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`]
- }
-
- const result = await balanceBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await balanceBulk(req, res)
- //console.log(`network issue result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(res.statusCode, 499, "HTTP status code 500 expected.")
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- assert.include(
- result.error,
- "Network error: Could not communicate",
- "Error message expected"
- )
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockBalance)
- }
-
- // Call the details API.
- const result = await balanceBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], ["confirmed", "unconfirmed", "balance"])
- assert.isNumber(result[0].confirmed)
- assert.isNumber(result[0].unconfirmed)
- assert.isNumber(result[0].balance)
- })
-
- it("should get details for multiple addresses", async () => {
- req.body = {
- addresses: [
- `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`,
- `bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockBalance)
- }
-
- // Call the details API.
- const result = await balanceBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
- })
-
- describe("#UTXOs Single", () => {
- // details route handler.
- const utxosSingle = bitcoreRoute.testableComponents.utxosSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await utxosSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await utxosSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await utxosSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`
-
- const result = await utxosSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCORE_URL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCORE_URL = "http://fakeurl/api/"
-
- const result = await utxosSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCORE_URL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCORE_URL = savedUrl
- }
- })
-
- it("should get utxos for a single address", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCORE_URL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxos)
- }
-
- // Call the details API.
- const result = await utxosSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "_id",
- "chain",
- "network",
- "coinbase",
- "mintIndex",
- "spentTxid",
- "mintTxid",
- "mintHeight",
- "spentHeight",
- "address",
- "script",
- "value",
- "confirmations"
- ])
- })
- })
-
- describe("#UTXO Bulk", () => {
- // details route handler.
- const utxosBulk = bitcoreRoute.testableComponents.utxosBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await utxosBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await utxosBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await utxosBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await utxosBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`]
- }
-
- const result = await utxosBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await utxosBulk(req, res)
- //console.log(`network issue result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(res.statusCode, 499, "HTTP status code 500 expected.")
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- assert.include(
- result.error,
- "Network error: Could not communicate",
- "Error message expected"
- )
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxos)
- }
-
- // Call the details API.
- const result = await utxosBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.isArray(result[0])
- assert.hasAnyKeys(result[0][0], [
- "_id",
- "chain",
- "network",
- "coinbase",
- "mintIndex",
- "spentTxid",
- "mintTxid",
- "mintHeight",
- "spentHeight",
- "address",
- "script",
- "value",
- "confirmations"
- ])
- })
-
- it("should get details for multiple addresses", async () => {
- req.body = {
- addresses: [
- `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`,
- `bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockUtxos)
- }
-
- // Call the details API.
- const result = await utxosBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.isArray(result[0])
- assert.hasAnyKeys(result[0][0], [
- "_id",
- "chain",
- "network",
- "coinbase",
- "mintIndex",
- "spentTxid",
- "mintTxid",
- "mintHeight",
- "spentHeight",
- "address",
- "script",
- "value",
- "confirmations"
- ])
- })
- })
-})
From 20b7425945d5ed76d63bf97560a452ca6a08d1d0 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Sat, 7 Dec 2019 19:47:35 -0800
Subject: [PATCH 31/49] fix(homepage): Updated the static page served by
api.bchjs.cash
---
src/public/index.html | 191 ++++++++++++++++++++++++++++++++++++------
1 file changed, 164 insertions(+), 27 deletions(-)
diff --git a/src/public/index.html b/src/public/index.html
index 28ed44e..be807b4 100644
--- a/src/public/index.html
+++ b/src/public/index.html
@@ -1,35 +1,172 @@
-
+
-
-
+
+
- BCH API
-
-
+ BCH API
+
+
-
+
+
-
+
+ BCH API
+ The REST API for the Bitcoin Cash blockchain.
+
-
- BCH API
-
- This web server is based on rest.bitcoin.com .
- Go there to view an interactive UI of the REST API endpoints.
-
-
+
+ bch-api is a
+ REST API , allowing modern applications to interact with the Bitcoin Cash (BCH)
+ blockchain. New to the BCH blockchain? Start by reading more about
+ building full stack applications on BCH .
+
+
+ A REST API can work with any programming language, but bch-api is intended
+ to be paired with the
+ npm bch-js
+ JavaScript library.
+ Here is example code
+ for common BCH use cases.
+
+ slp-cli-wallet
+ is another npm library that provides common wallet functionality, to get
+ your apps up and running as quickly as possible.
+
+
+ While you'll be able to run through the examples without one, you should
+ sign-up for a free API key
+ in order to unlock higher rate limits.
+
-
-
+
+ Quick Links
+
+
+ bch-api
+
+
+
+
+
+ Bitcoin Cash
+
+
+
+
+
+ bch-js
+
+
+
+
+
+ Credit
+
+ This web server is based on
+ rest.bitcoin.com . Most endpoints
+ are common between the two projects. You may want to plan with their
+ interactive UI to explore the API endpoints.
+
+
+
+
+
From 708c1e1935993c05600e14a5eb831aa00e999c21 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Sat, 7 Dec 2019 19:49:51 -0800
Subject: [PATCH 32/49] Added a few more links
---
src/public/index.html | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/src/public/index.html b/src/public/index.html
index be807b4..29c3616 100644
--- a/src/public/index.html
+++ b/src/public/index.html
@@ -71,6 +71,7 @@
+
bch-api documentation
@@ -78,6 +79,13 @@
+
+
+ testnet REST API
+
+
+
+
bch-api GitHub repository
@@ -118,6 +126,13 @@
+
+
+
+ Testnet Faucet
+
+
+
From d4c356f2c0c0cc5d9c9cd69d083323120c3042e8 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Sat, 7 Dec 2019 19:54:32 -0800
Subject: [PATCH 33/49] Adding a little more space on the homepage
---
src/public/index.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/public/index.html b/src/public/index.html
index 29c3616..a42f0b9 100644
--- a/src/public/index.html
+++ b/src/public/index.html
@@ -29,7 +29,7 @@
target="_blank"
>building full stack applications on BCH.
-
+
A REST API can work with any programming language, but bch-api is intended
to be paired with the
@@ -50,7 +50,7 @@
>
is another npm library that provides common wallet functionality, to get
your apps up and running as quickly as possible.
-
+
While you'll be able to run through the examples without one, you should
Date: Sun, 8 Dec 2019 08:07:07 -0800
Subject: [PATCH 34/49] Adding link to telegram channel
---
src/public/index.html | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/public/index.html b/src/public/index.html
index a42f0b9..563dbd3 100644
--- a/src/public/index.html
+++ b/src/public/index.html
@@ -92,6 +92,13 @@
+
+
+
+ Community Telegram Channel
+
+
+
From 592510559b8c6a1bd9cb72d5061c6ede898c797b Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Sun, 8 Dec 2019 08:28:00 -0800
Subject: [PATCH 35/49] fix(READMEs): updating readmes
---
README.md | 32 ++++++++++++++++-----------
docker/mainnet/start-local-mainnet.sh | 14 ++++--------
docker/testnet/start-local-testnet.sh | 14 ++++--------
start-dev-example.sh | 12 +++-------
4 files changed, 30 insertions(+), 42 deletions(-)
diff --git a/README.md b/README.md
index 9eaf9ee..02d68a9 100644
--- a/README.md
+++ b/README.md
@@ -9,12 +9,14 @@ the [rest.bitcoin.com](https://github.com/Bitcoin-com/rest.bitcoin.com) reposito
The purpose of this code is to create a REST API server that provides a common
interface for working with a Bitcoin Cash full node and various indexers.
-This repository is intended to be paired with my alternative implementation
-of [BITBOX SDK](https://github.com/Bitcoin-com/bitbox-sdk):
-[bch-js](https://github.com/christroutner/bch-js), and is part of the product
-offering at [bchjs.cash](https://bchjs.cash).
+This repository is intended to be paired with [bch-js](https://github.com/christroutner/bch-js),
+an npm JavaScript library, and an alternative implementation
+of [BITBOX SDK](https://github.com/Bitcoin-com/bitbox-sdk).
-- [API Documentation](https://bchjs.cash/bch-api/index.html)
+Both bch-api and bch-js are part of the
+[full stack of BCH software](https://troutsblog.com/research/bitcoin-cash/how-to-bch-full-stack-developer).
+
+- [API Documentation](https://api.bchjs.cash/docs/)
- Video: [Basic Concepts](https://www.youtube.com/watch?v=o0FfW5rZPFs)
- Video: [Application Stack](https://youtu.be/8w0CpQ8oydA)
- [bchjs.cash](https://bchjs.cash): Buy a turn-key REST API microserver.
@@ -25,8 +27,11 @@ Have questions? Need help? Join our community support
## Features
The following features set this repository apart from rest.bitcoin.com:
-- Address balance and UTXO queries for [Blockbook](https://github.com/trezor/blockbook) and [Bitcore](https://github.com/bitpay/bitcore/tree/master/packages/bitcore-node) added.
-- Rate limits are set to 10 RPM by default, and 60 RPM if Basic Authentiction header is used.
+- Address balance and UTXO queries use the [Blockbook](https://github.com/trezor/blockbook)
+indexer instead of Insight.
+- Fine grain access is controlled with a JWT token using
+[this back end auth server](https://github.com/Permissionless-Software-Foundation/jwt-bch-api) and [this front end](https://github.com/Permissionless-Software-Foundation/jwt-bch-frontend).
+- Default rate limits are set to 3 RPM for anonymous connections, up to 100 RPM for a full-access JWT token is used.
- Typescript removed and ES8 JavaScript used instead.
- npm audit run on all dependencies.
- [Greenkeeper](https://greenkeeper.io/) implemented for automatic dependency management
@@ -34,15 +39,16 @@ and security updates.
## Live Demo
You can test a live demo of the REST API by running the
-[bch-js examples](https://github.com/christroutner/bch-js/tree/master/examples).
-Rate limits are 10 requests per minute. This is fast enough to try out the examples
+[bch-js examples](https://github.com/Permissionless-Software-Foundation/bch-js-examples).
+Rate limits are 3 requests per minute, but you can increase them to 10 with a free
+account at [account.bchjs.cash](https://account.bchjs.cash).
+This is fast enough to try out the examples
but these servers are not intended as a freemium service. You can run your own
REST server by purchasing the hard drive at [bchjs.cash](https://bchjs.cash).
-- Mainnet REST API server: http://decatur.hopto.org:12400/v3/
- - Check server status: http://decatur.hopto.org:12401
-- Testnet REST API server: http://decatur.hopto.org:13400/v3/
- - Check server status: http://decatur.hopto.org:13401
+- Mainnet REST API server: https://api.bchjs.cash/v3/
+- Testnet REST API server: https://tapi.bchjs.cash/v3/
+- Check server status: https://metrics.bchjs.cash
## Installation
There are two installation paths, depending if you want a *development* or
diff --git a/docker/mainnet/start-local-mainnet.sh b/docker/mainnet/start-local-mainnet.sh
index c9a3809..6573614 100755
--- a/docker/mainnet/start-local-mainnet.sh
+++ b/docker/mainnet/start-local-mainnet.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-# Harddrive Mainnet full node
+# Full node
export RPC_BASEURL=http://172.17.0.1:8332/
export RPC_USERNAME=bitcoin
export RPC_PASSWORD=password
@@ -8,17 +8,11 @@ export ZEROMQ_PORT=28332
export ZEROMQ_URL=172.17.0.1
export NETWORK=mainnet
-# Team DO QA Testnet Insight Server
-export BITCOINCOM_BASEURL=http://172.17.0.1:12100/api/
-
-# Testnet SLPDB
-#export SLPDB_URL=https://slpdb.bchdata.cash/
+# SLPDB
+#export SLPDB_URL=https://slpdb.bitcoin.com/
export SLPDB_URL=http://172.17.0.1:12300/
-# Testnet Bitcore Node API
-export BITCORE_URL=http://172.17.0.1:12200/
-
-# Testnet Blockbook
+# Blockbook Indexer
export BLOCKBOOK_URL=https://172.17.0.1:9131/
# Allow node.js to make network calls to https using self-signed certificate.
export NODE_TLS_REJECT_UNAUTHORIZED=0
diff --git a/docker/testnet/start-local-testnet.sh b/docker/testnet/start-local-testnet.sh
index 71a4741..3a2e033 100755
--- a/docker/testnet/start-local-testnet.sh
+++ b/docker/testnet/start-local-testnet.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-# Harddrive Mainnet full node
+# Full node
export RPC_BASEURL=http://172.17.0.1:18332/
export RPC_USERNAME=bitcoin
export RPC_PASSWORD=password
@@ -8,17 +8,11 @@ export ZEROMQ_PORT=38332
export ZEROMQ_URL=172.17.0.1
export NETWORK=testnet
-# Team DO QA Testnet Insight Server
-export BITCOINCOM_BASEURL=http://172.17.0.1:13100/api/
-
-# Testnet SLPDB
-#export SLPDB_URL=https://slpdb.bchdata.cash/
+# SLPDB
+#export SLPDB_URL=https://tslpdb.bitcoin.com/
export SLPDB_URL=http://172.17.0.1:13300/
-# Testnet Bitcore Node API
-export BITCORE_URL=http://172.17.0.1:13200/
-
-# Testnet Blockbook
+# Blockbook
export BLOCKBOOK_URL=https://172.17.0.1:19131/
# Allow node.js to make network calls to https using self-signed certificate.
export NODE_TLS_REJECT_UNAUTHORIZED=0
diff --git a/start-dev-example.sh b/start-dev-example.sh
index 50934c5..4d0ae09 100755
--- a/start-dev-example.sh
+++ b/start-dev-example.sh
@@ -1,21 +1,15 @@
#!/bin/bash
-# Harddrive Mainnet full node
+# Full node
export RPC_BASEURL=http://:8332/
export RPC_USERNAME=
export RPC_PASSWORD=
export NETWORK=mainnet
-# Team DO QA Testnet Insight Server
-export BITCOINCOM_BASEURL=http://:12100/api/
-
-# Testnet SLPDB
+# SLPDB
export SLPDB_URL=http://:12300/
-# Testnet Bitcore Node API
-export BITCORE_URL=http://:12200/
-
-# Testnet Blockbook
+# Blockbook
export BLOCKBOOK_URL=https://:9131/
# Allow node.js to make network calls to https using self-signed certificate.
export NODE_TLS_REJECT_UNAUTHORIZED=0
From 280c8a80724b40d5fd2140691a89a55d47c6d718 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Tue, 10 Dec 2019 06:54:24 -0800
Subject: [PATCH 36/49] fix(rate limit): Fixed free 10 RPM tier
---
src/middleware/route-ratelimit.js | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/middleware/route-ratelimit.js b/src/middleware/route-ratelimit.js
index b67c045..8d92413 100644
--- a/src/middleware/route-ratelimit.js
+++ b/src/middleware/route-ratelimit.js
@@ -6,8 +6,8 @@
Current rate limiting rules in requests-per-minute:
- anonymous access: 3
- - free access: 10
- - any paid tier: 100
+ - free access: 10, apiLevel = 0
+ - any paid tier: 100, apiLevel > 0
*/
"use strict"
@@ -103,9 +103,9 @@ const routeRateLimit = async function(req, res, next) {
const proRateLimits = req.locals.proLimit
// Pro level rate limits
- if (proRateLimits) {
+ if (proRateLimits !== undefined) {
// TODO: replace the console.logs with calls to our logging system.
- //console.log(`applying pro-rate limits`)
+ console.log(`applying pro-rate limits`)
let PRO_RPM = 10 // Default value for free tier
if (req.locals.apiLevel > 0) PRO_RPM = 100 // RPM for paid tiers.
@@ -130,7 +130,7 @@ const routeRateLimit = async function(req, res, next) {
// Freemium level rate limits
} else {
// TODO: replace the console.logs with calls to our logging system.
- //console.log(`applying freemium limits`)
+ console.log(`applying freemium limits`)
// Create new RateLimit if none exists for this route
if (!uniqueRateLimits[route]) {
From 17a2bbe3922faebef86f308d8325f7becc55c04f Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Tue, 10 Dec 2019 06:56:04 -0800
Subject: [PATCH 37/49] Commenting out debugging console logs
---
src/middleware/route-ratelimit.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/middleware/route-ratelimit.js b/src/middleware/route-ratelimit.js
index 8d92413..5b78ff9 100644
--- a/src/middleware/route-ratelimit.js
+++ b/src/middleware/route-ratelimit.js
@@ -105,7 +105,7 @@ const routeRateLimit = async function(req, res, next) {
// Pro level rate limits
if (proRateLimits !== undefined) {
// TODO: replace the console.logs with calls to our logging system.
- console.log(`applying pro-rate limits`)
+ // console.log(`applying pro-rate limits`)
let PRO_RPM = 10 // Default value for free tier
if (req.locals.apiLevel > 0) PRO_RPM = 100 // RPM for paid tiers.
@@ -130,7 +130,7 @@ const routeRateLimit = async function(req, res, next) {
// Freemium level rate limits
} else {
// TODO: replace the console.logs with calls to our logging system.
- console.log(`applying freemium limits`)
+ // console.log(`applying freemium limits`)
// Create new RateLimit if none exists for this route
if (!uniqueRateLimits[route]) {
From 7ff381c3d06cdba98fa364cc074d1a3e822622b3 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Tue, 10 Dec 2019 08:33:39 -0800
Subject: [PATCH 38/49] fix(rate limits): fixing rate limits
---
src/middleware/route-ratelimit.js | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/middleware/route-ratelimit.js b/src/middleware/route-ratelimit.js
index 5b78ff9..172d0d1 100644
--- a/src/middleware/route-ratelimit.js
+++ b/src/middleware/route-ratelimit.js
@@ -102,8 +102,10 @@ const routeRateLimit = async function(req, res, next) {
// This boolean value is passed from the auth.js middleware.
const proRateLimits = req.locals.proLimit
+ // console.log(`proRateLimits: ${proRateLimits}`)
+
// Pro level rate limits
- if (proRateLimits !== undefined) {
+ if (proRateLimits || proRateLimits === 0) {
// TODO: replace the console.logs with calls to our logging system.
// console.log(`applying pro-rate limits`)
@@ -169,6 +171,9 @@ function evalUserPermissioins(req, authData) {
apiLevel: authData.apiLevel
}
+ // if apiLevel = 0 (free tier), then return the default values.
+ if (retObj.apiLevel === 0) return retObj
+
const level20Routes = ["insight", "bitcore", "blockbook"]
const locals = req.locals
From c1bd8fbe37e9daca101678e925d47098dd8b612f Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Tue, 10 Dec 2019 12:56:49 -0800
Subject: [PATCH 39/49] fix(rate limits): Fixed corner case with JWT token
handling
---
src/middleware/route-ratelimit.js | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/middleware/route-ratelimit.js b/src/middleware/route-ratelimit.js
index 172d0d1..7c75acf 100644
--- a/src/middleware/route-ratelimit.js
+++ b/src/middleware/route-ratelimit.js
@@ -93,12 +93,15 @@ const routeRateLimit = async function(req, res, next) {
const route =
rateLimitTier +
req.method +
+ req.locals.apiLevel + // Generates new rate limit when user upgrades JWT token.
path
.split("/")
.slice(0, 4)
.join("/")
//console.log(`route identifier: ${JSON.stringify(route, null, 2)}`)
+ console.log(`req.locals: ${JSON.stringify(req.locals, null, 2)}`)
+
// This boolean value is passed from the auth.js middleware.
const proRateLimits = req.locals.proLimit
@@ -112,6 +115,8 @@ const routeRateLimit = async function(req, res, next) {
let PRO_RPM = 10 // Default value for free tier
if (req.locals.apiLevel > 0) PRO_RPM = 100 // RPM for paid tiers.
+ // console.log(`PRO_RPM: ${PRO_RPM}, apiLevel: ${req.locals.apiLevel}`)
+
// Create new RateLimit if none exists for this route
if (!uniqueRateLimits[route]) {
uniqueRateLimits[route] = new RateLimit({
@@ -123,7 +128,7 @@ const routeRateLimit = async function(req, res, next) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
- error: `Too many requests. Limits are ${PRO_RPM} requests per minute.`
+ error: `Too many requests. Limits are ${PRO_RPM} requests per minute. Increase rate limits at https://account.bchjs.cash`
})
}
})
@@ -145,7 +150,7 @@ const routeRateLimit = async function(req, res, next) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
- error: `Too many requests. Your limits are currently ${maxRequests} requests per minute.`
+ error: `Too many requests. Your limits are currently ${maxRequests} requests per minute. Increase rate limits at https://account.bchjs.cash`
})
}
})
From c982c247f71171edd30f335d05362077fc7188c7 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Tue, 10 Dec 2019 13:10:37 -0800
Subject: [PATCH 40/49] Cleaning up code comments
---
src/middleware/route-ratelimit.js | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/src/middleware/route-ratelimit.js b/src/middleware/route-ratelimit.js
index 7c75acf..cdad7a6 100644
--- a/src/middleware/route-ratelimit.js
+++ b/src/middleware/route-ratelimit.js
@@ -8,6 +8,11 @@
- anonymous access: 3
- free access: 10, apiLevel = 0
- any paid tier: 100, apiLevel > 0
+
+ If a person signs up for full node access but not indexer access, then the
+ apiLevel will be 10. If they call an endpoint that uses an indexer, the apiLevel
+ will be downgraded to 0 on-the-fly. Indexer endpoints will effectively be
+ downgraded to the anonymous access tier.
*/
"use strict"
@@ -72,15 +77,6 @@ const routeRateLimit = async function(req, res, next) {
req.locals.proLimit = userPermissions.proLimit
req.locals.apiLevel = userPermissions.apiLevel
-
- // const locals = req.locals
- // console.log(`locals: ${JSON.stringify(locals, null, 2)}`)
- // const url = req.url
- // console.log(`url: ${JSON.stringify(url, null, 2)}`)
- //
- // // console.log(`JWT is valid. Enabling pro-tier rate limits.`)
- // req.locals.proLimit = true
- // req.locals.apiLevel = jwtInfo.apiLevel
}
}
}
@@ -100,7 +96,7 @@ const routeRateLimit = async function(req, res, next) {
.join("/")
//console.log(`route identifier: ${JSON.stringify(route, null, 2)}`)
- console.log(`req.locals: ${JSON.stringify(req.locals, null, 2)}`)
+ // console.log(`req.locals: ${JSON.stringify(req.locals, null, 2)}`)
// This boolean value is passed from the auth.js middleware.
const proRateLimits = req.locals.proLimit
From 010dceeb99fb021a45df1fd02c24f39eaff6f1aa Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com>
Date: Sun, 22 Dec 2019 16:33:29 +0000
Subject: [PATCH 41/49] chore(package): update sinon to version 8.0.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index bad4f7f..1a5113f 100644
--- a/package.json
+++ b/package.json
@@ -66,7 +66,7 @@
"request": "^2.88.0",
"request-promise": "^4.2.2",
"semantic-release": "^15.13.19",
- "sinon": "^7.3.2",
+ "sinon": "^8.0.0",
"typescript": "^3.1.4"
},
"release": {
From 59963a40c9ae00cba73759676583a7b216987806 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com>
Date: Sun, 22 Dec 2019 16:33:33 +0000
Subject: [PATCH 42/49] chore(package): update lockfile package-lock.json
---
package-lock.json | 93 ++++++++++++++++++++++++++++++-----------------
1 file changed, 60 insertions(+), 33 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index f5b6bb3..070034c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -607,33 +607,33 @@
}
},
"@sinonjs/commons": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.6.0.tgz",
- "integrity": "sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg==",
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.0.tgz",
+ "integrity": "sha512-qbk9AP+cZUsKdW1GJsBpxPKFmCJ0T8swwzVje3qFd+AkQb74Q/tiuzrdfFg8AD2g5HH/XbE/I8Uc1KYHVYWfhg==",
"dev": true,
"requires": {
"type-detect": "4.0.8"
}
},
"@sinonjs/formatio": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz",
- "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-4.0.1.tgz",
+ "integrity": "sha512-asIdlLFrla/WZybhm0C8eEzaDNNrzymiTqHMeJl6zPW2881l3uuVRpm0QlRQEjqYWv6CcKMGYME3LbrLJsORBw==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1",
- "@sinonjs/samsam": "^3.1.0"
+ "@sinonjs/samsam": "^4.2.0"
}
},
"@sinonjs/samsam": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz",
- "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==",
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-4.2.0.tgz",
+ "integrity": "sha512-yG7QbUz38ZPIegfuSMEcbOo0kkLGmPa8a0Qlz4dk7+cXYALDScWjIZzAm/u2+Frh+bcdZF6wZJZwwuJjY0WAjA==",
"dev": true,
"requires": {
- "@sinonjs/commons": "^1.3.0",
+ "@sinonjs/commons": "^1.6.0",
"array-from": "^2.1.1",
- "lodash": "^4.17.15"
+ "lodash.get": "^4.4.2"
}
},
"@sinonjs/text-encoding": {
@@ -7031,10 +7031,13 @@
}
},
"lolex": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz",
- "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==",
- "dev": true
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz",
+ "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==",
+ "dev": true,
+ "requires": {
+ "@sinonjs/commons": "^1.7.0"
+ }
},
"loose-envify": {
"version": "1.4.0",
@@ -7656,15 +7659,16 @@
"dev": true
},
"nise": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.2.tgz",
- "integrity": "sha512-/6RhOUlicRCbE9s+94qCUsyE+pKlVJ5AhIv+jEE7ESKwnbXqulKZ1FYU+XAtHHWE9TinYvAxDUJAb912PwPoWA==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/nise/-/nise-3.0.0.tgz",
+ "integrity": "sha512-EObFx5tioBMePHpU/gGczaY2YDqL255iwjmZwswu2CiwEW8xIGrr3E2xij+efIppS1nLQo9NyXSIUySGHUOhHQ==",
"dev": true,
"requires": {
- "@sinonjs/formatio": "^3.2.1",
+ "@sinonjs/commons": "^1.7.0",
+ "@sinonjs/formatio": "^4.0.1",
"@sinonjs/text-encoding": "^0.7.1",
"just-extend": "^4.0.2",
- "lolex": "^4.1.0",
+ "lolex": "^5.0.1",
"path-to-regexp": "^1.7.0"
},
"dependencies": {
@@ -7675,9 +7679,9 @@
"dev": true
},
"path-to-regexp": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz",
- "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
+ "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
"dev": true,
"requires": {
"isarray": "0.0.1"
@@ -13191,18 +13195,41 @@
}
},
"sinon": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz",
- "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-8.0.0.tgz",
+ "integrity": "sha512-9ugfO9tMrxTzqViG0hGhJoLXj8M01FZwfXMpYSmQT1AuV2jyXDJZUMpbENHBY9/2c2u6RKkHOcbYINx2FttUkg==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.4.0",
- "@sinonjs/formatio": "^3.2.1",
- "@sinonjs/samsam": "^3.3.3",
- "diff": "^3.5.0",
- "lolex": "^4.2.0",
- "nise": "^1.5.2",
- "supports-color": "^5.5.0"
+ "@sinonjs/formatio": "^4.0.1",
+ "@sinonjs/samsam": "^4.0.1",
+ "diff": "^4.0.1",
+ "lolex": "^5.1.2",
+ "nise": "^3.0.0",
+ "supports-color": "^7.1.0"
+ },
+ "dependencies": {
+ "diff": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
+ "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+ "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
}
},
"slice-ansi": {
From cb20efc068660aca2c78b936ffb55da233a5624f Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com>
Date: Mon, 23 Dec 2019 01:22:30 +0000
Subject: [PATCH 43/49] chore(package): update nyc to version 15.0.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index bad4f7f..35214a9 100644
--- a/package.json
+++ b/package.json
@@ -60,7 +60,7 @@
"nock": "^11.1.0",
"node-mocks-http": "^1.7.0",
"nodemon": "^1.18.1",
- "nyc": "^14.1.1",
+ "nyc": "^15.0.0",
"prettier": "^1.18.2",
"proxyquire": "^2.1.0",
"request": "^2.88.0",
From cdc753f86976b75523746059dbfbe707bfe9ab58 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com>
Date: Mon, 23 Dec 2019 01:22:37 +0000
Subject: [PATCH 44/49] chore(package): update lockfile package-lock.json
---
package-lock.json | 860 +++++++++++++++++++++++++++++++++-------------
1 file changed, 630 insertions(+), 230 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index f5b6bb3..d4fc8d2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,41 +12,79 @@
"@babel/highlight": "^7.0.0"
}
},
- "@babel/generator": {
- "version": "7.6.4",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz",
- "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==",
+ "@babel/core": {
+ "version": "7.7.7",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.7.tgz",
+ "integrity": "sha512-jlSjuj/7z138NLZALxVgrx13AOtqip42ATZP7+kYl53GvDV6+4dCek1mVUo8z8c8Xnw/mx2q3d9HWh3griuesQ==",
"requires": {
- "@babel/types": "^7.6.3",
+ "@babel/code-frame": "^7.5.5",
+ "@babel/generator": "^7.7.7",
+ "@babel/helpers": "^7.7.4",
+ "@babel/parser": "^7.7.7",
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "json5": "^2.1.0",
+ "lodash": "^4.17.13",
+ "resolve": "^1.3.2",
+ "semver": "^5.4.1",
+ "source-map": "^0.5.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ }
+ }
+ },
+ "@babel/generator": {
+ "version": "7.7.7",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz",
+ "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==",
+ "requires": {
+ "@babel/types": "^7.7.4",
"jsesc": "^2.5.1",
"lodash": "^4.17.13",
"source-map": "^0.5.0"
}
},
"@babel/helper-function-name": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz",
- "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==",
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz",
+ "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==",
"requires": {
- "@babel/helper-get-function-arity": "^7.0.0",
- "@babel/template": "^7.1.0",
- "@babel/types": "^7.0.0"
+ "@babel/helper-get-function-arity": "^7.7.4",
+ "@babel/template": "^7.7.4",
+ "@babel/types": "^7.7.4"
}
},
"@babel/helper-get-function-arity": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz",
- "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==",
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz",
+ "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==",
"requires": {
- "@babel/types": "^7.0.0"
+ "@babel/types": "^7.7.4"
}
},
"@babel/helper-split-export-declaration": {
- "version": "7.4.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz",
- "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==",
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz",
+ "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==",
"requires": {
- "@babel/types": "^7.4.4"
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helpers": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.7.4.tgz",
+ "integrity": "sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg==",
+ "requires": {
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4"
}
},
"@babel/highlight": {
@@ -60,40 +98,40 @@
}
},
"@babel/parser": {
- "version": "7.6.4",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz",
- "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A=="
+ "version": "7.7.7",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz",
+ "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw=="
},
"@babel/template": {
- "version": "7.6.0",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz",
- "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==",
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz",
+ "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==",
"requires": {
"@babel/code-frame": "^7.0.0",
- "@babel/parser": "^7.6.0",
- "@babel/types": "^7.6.0"
+ "@babel/parser": "^7.7.4",
+ "@babel/types": "^7.7.4"
}
},
"@babel/traverse": {
- "version": "7.6.3",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz",
- "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==",
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz",
+ "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==",
"requires": {
"@babel/code-frame": "^7.5.5",
- "@babel/generator": "^7.6.3",
- "@babel/helper-function-name": "^7.1.0",
- "@babel/helper-split-export-declaration": "^7.4.4",
- "@babel/parser": "^7.6.3",
- "@babel/types": "^7.6.3",
+ "@babel/generator": "^7.7.4",
+ "@babel/helper-function-name": "^7.7.4",
+ "@babel/helper-split-export-declaration": "^7.7.4",
+ "@babel/parser": "^7.7.4",
+ "@babel/types": "^7.7.4",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.13"
}
},
"@babel/types": {
- "version": "7.6.3",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz",
- "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==",
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz",
+ "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==",
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.13",
@@ -148,6 +186,59 @@
"wif": "^2.0.6"
}
},
+ "@istanbuljs/load-nyc-config": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz",
+ "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==",
+ "requires": {
+ "camelcase": "^5.3.1",
+ "find-up": "^4.1.0",
+ "js-yaml": "^3.13.1",
+ "resolve-from": "^5.0.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
+ },
+ "resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="
+ }
+ }
+ },
+ "@istanbuljs/schema": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz",
+ "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw=="
+ },
"@nodelib/fs.scandir": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
@@ -642,6 +733,11 @@
"integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
"dev": true
},
+ "@types/color-name": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
+ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
+ },
"@types/events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
@@ -754,7 +850,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
"integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==",
- "dev": true,
"requires": {
"clean-stack": "^2.0.0",
"indent-string": "^4.0.0"
@@ -763,8 +858,7 @@
"indent-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
- "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
- "dev": true
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="
}
}
},
@@ -934,11 +1028,11 @@
}
},
"append-transform": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz",
- "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz",
+ "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==",
"requires": {
- "default-require-extensions": "^2.0.0"
+ "default-require-extensions": "^3.0.0"
}
},
"archy": {
@@ -1820,14 +1914,27 @@
}
},
"caching-transform": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz",
- "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
+ "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==",
"requires": {
- "hasha": "^3.0.0",
- "make-dir": "^2.0.0",
- "package-hash": "^3.0.0",
- "write-file-atomic": "^2.4.2"
+ "hasha": "^5.0.0",
+ "make-dir": "^3.0.0",
+ "package-hash": "^4.0.0",
+ "write-file-atomic": "^3.0.0"
+ },
+ "dependencies": {
+ "write-file-atomic": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.1.tgz",
+ "integrity": "sha512-JPStrIyyVJ6oCSz/691fAjFtefZ6q+fP6tm+OS4Qw6o+TGQxNp1ziY2PgS+X/m0V8OWhZiO/m4xSj+Pr4RrZvw==",
+ "requires": {
+ "imurmurhash": "^0.1.4",
+ "is-typedarray": "^1.0.0",
+ "signal-exit": "^3.0.2",
+ "typedarray-to-buffer": "^3.1.5"
+ }
+ }
}
},
"callback-stream": {
@@ -2081,8 +2188,7 @@
"clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
- "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
- "dev": true
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="
},
"clear": {
"version": "0.1.0",
@@ -2517,9 +2623,9 @@
}
},
"convert-source-map": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
- "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
+ "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
"requires": {
"safe-buffer": "~5.1.1"
},
@@ -2692,12 +2798,41 @@
}
},
"cross-spawn": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz",
- "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz",
+ "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==",
"requires": {
- "lru-cache": "^4.0.1",
- "which": "^1.2.9"
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "dependencies": {
+ "path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
+ },
+ "shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "requires": {
+ "shebang-regex": "^3.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
}
},
"crypto-random-string": {
@@ -2812,11 +2947,18 @@
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
},
"default-require-extensions": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz",
- "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz",
+ "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==",
"requires": {
- "strip-bom": "^3.0.0"
+ "strip-bom": "^4.0.0"
+ },
+ "dependencies": {
+ "strip-bom": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="
+ }
}
},
"deferred-leveldown": {
@@ -4676,13 +4818,13 @@
}
},
"find-cache-dir": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
- "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.2.0.tgz",
+ "integrity": "sha512-1JKclkYYsf1q9WIJKLZa9S9muC+08RIjzAlLrK4QcYLJMS6mk9yombQ9qf+zJ7H9LS800k0s44L4sDq9VYzqyg==",
"requires": {
"commondir": "^1.0.1",
- "make-dir": "^2.0.0",
- "pkg-dir": "^3.0.0"
+ "make-dir": "^3.0.0",
+ "pkg-dir": "^4.1.0"
}
},
"find-root": {
@@ -4781,12 +4923,12 @@
"dev": true
},
"foreground-child": {
- "version": "1.5.6",
- "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz",
- "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
+ "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
"requires": {
- "cross-spawn": "^4",
- "signal-exit": "^3.0.0"
+ "cross-spawn": "^7.0.0",
+ "signal-exit": "^3.0.2"
}
},
"forever-agent": {
@@ -4872,6 +5014,11 @@
}
}
},
+ "fromentries": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz",
+ "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ=="
+ },
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
@@ -5669,6 +5816,7 @@
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
+ "dev": true,
"requires": {
"neo-async": "^2.6.0",
"optimist": "^0.6.1",
@@ -5679,7 +5827,8 @@
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
}
}
},
@@ -5835,11 +5984,24 @@
}
},
"hasha": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz",
- "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.1.0.tgz",
+ "integrity": "sha512-OFPDWmzPN1l7atOV1TgBVmNtBxaIysToK6Ve9DK+vT6pYuklw/nPNT+HJbZi0KDcI6vWB+9tgvZ5YD7fA3CXcA==",
"requires": {
- "is-stream": "^1.0.1"
+ "is-stream": "^2.0.0",
+ "type-fest": "^0.8.0"
+ },
+ "dependencies": {
+ "is-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
+ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw=="
+ },
+ "type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
+ }
}
},
"he": {
@@ -5949,6 +6111,11 @@
}
}
},
+ "html-escaper": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.0.tgz",
+ "integrity": "sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig=="
+ },
"http-errors": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
@@ -6507,8 +6674,7 @@
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
- "dev": true
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"is-unc-path": {
"version": "1.0.0",
@@ -6559,30 +6725,30 @@
}
},
"istanbul-lib-coverage": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
- "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA=="
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz",
+ "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg=="
},
"istanbul-lib-hook": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz",
- "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz",
+ "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==",
"requires": {
- "append-transform": "^1.0.0"
+ "append-transform": "^2.0.0"
}
},
"istanbul-lib-instrument": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz",
- "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.0.tgz",
+ "integrity": "sha512-Nm4wVHdo7ZXSG30KjZ2Wl5SU/Bw7bDx1PdaiIFzEStdjs0H12mOTncn1GVYuqQSaZxpg87VGBRsVRPGD2cD1AQ==",
"requires": {
- "@babel/generator": "^7.4.0",
- "@babel/parser": "^7.4.3",
- "@babel/template": "^7.4.0",
- "@babel/traverse": "^7.4.3",
- "@babel/types": "^7.4.0",
- "istanbul-lib-coverage": "^2.0.5",
- "semver": "^6.0.0"
+ "@babel/core": "^7.7.5",
+ "@babel/parser": "^7.7.5",
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-coverage": "^3.0.0",
+ "semver": "^6.3.0"
},
"dependencies": {
"semver": {
@@ -6592,35 +6758,62 @@
}
}
},
- "istanbul-lib-report": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz",
- "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==",
+ "istanbul-lib-processinfo": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz",
+ "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==",
"requires": {
- "istanbul-lib-coverage": "^2.0.5",
- "make-dir": "^2.1.0",
- "supports-color": "^6.1.0"
+ "archy": "^1.0.0",
+ "cross-spawn": "^7.0.0",
+ "istanbul-lib-coverage": "^3.0.0-alpha.1",
+ "make-dir": "^3.0.0",
+ "p-map": "^3.0.0",
+ "rimraf": "^3.0.0",
+ "uuid": "^3.3.3"
},
"dependencies": {
- "supports-color": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
- "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "p-map": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
+ "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
"requires": {
- "has-flag": "^3.0.0"
+ "aggregate-error": "^3.0.0"
+ }
+ }
+ }
+ },
+ "istanbul-lib-report": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+ "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
+ "requires": {
+ "istanbul-lib-coverage": "^3.0.0",
+ "make-dir": "^3.0.0",
+ "supports-color": "^7.1.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+ },
+ "supports-color": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+ "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+ "requires": {
+ "has-flag": "^4.0.0"
}
}
}
},
"istanbul-lib-source-maps": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz",
- "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz",
+ "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==",
"requires": {
"debug": "^4.1.1",
- "istanbul-lib-coverage": "^2.0.5",
- "make-dir": "^2.1.0",
- "rimraf": "^2.6.3",
+ "istanbul-lib-coverage": "^3.0.0",
"source-map": "^0.6.1"
},
"dependencies": {
@@ -6632,11 +6825,12 @@
}
},
"istanbul-reports": {
- "version": "2.2.6",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz",
- "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+ "integrity": "sha512-2osTcC8zcOSUkImzN2EWQta3Vdi4WjjKw99P2yWx5mLnigAM0Rd5uYFn1cf2i/Ois45GkNjaoTqc5CxgMSX80A==",
"requires": {
- "handlebars": "^4.1.2"
+ "html-escaper": "^2.0.0",
+ "istanbul-lib-report": "^3.0.0"
}
},
"java-properties": {
@@ -6702,6 +6896,21 @@
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
"dev": true
},
+ "json5": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz",
+ "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==",
+ "requires": {
+ "minimist": "^1.2.0"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ }
+ }
+ },
"jsonfile": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz",
@@ -7081,18 +7290,17 @@
"dev": true
},
"make-dir": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
- "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz",
+ "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==",
"requires": {
- "pify": "^4.0.1",
- "semver": "^5.6.0"
+ "semver": "^6.0.0"
},
"dependencies": {
"semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
@@ -7252,21 +7460,6 @@
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
},
- "merge-source-map": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz",
- "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==",
- "requires": {
- "source-map": "^0.6.1"
- },
- "dependencies": {
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
- }
- }
- },
"merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -7354,7 +7547,8 @@
"minimist": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
- "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
+ "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
+ "dev": true
},
"minimist-options": {
"version": "3.0.2",
@@ -7631,7 +7825,8 @@
"neo-async": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
- "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw=="
+ "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
+ "dev": true
},
"nerf-dart": {
"version": "1.0.0",
@@ -7761,6 +7956,14 @@
"type-is": "^1.6.18"
}
},
+ "node-preload": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
+ "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==",
+ "requires": {
+ "process-on-spawn": "^1.0.0"
+ }
+ },
"nodemon": {
"version": "1.19.4",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.4.tgz",
@@ -11322,47 +11525,196 @@
}
},
"nyc": {
- "version": "14.1.1",
- "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz",
- "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==",
+ "version": "15.0.0",
+ "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.0.0.tgz",
+ "integrity": "sha512-qcLBlNCKMDVuKb7d1fpxjPR8sHeMVX0CHarXAVzrVWoFrigCkYR8xcrjfXSPi5HXM7EU78L6ywO7w1c5rZNCNg==",
"requires": {
- "archy": "^1.0.0",
- "caching-transform": "^3.0.2",
- "convert-source-map": "^1.6.0",
- "cp-file": "^6.2.0",
- "find-cache-dir": "^2.1.0",
- "find-up": "^3.0.0",
- "foreground-child": "^1.5.6",
- "glob": "^7.1.3",
- "istanbul-lib-coverage": "^2.0.5",
- "istanbul-lib-hook": "^2.0.7",
- "istanbul-lib-instrument": "^3.3.0",
- "istanbul-lib-report": "^2.0.8",
- "istanbul-lib-source-maps": "^3.0.6",
- "istanbul-reports": "^2.2.4",
+ "@istanbuljs/load-nyc-config": "^1.0.0",
+ "@istanbuljs/schema": "^0.1.2",
+ "caching-transform": "^4.0.0",
+ "convert-source-map": "^1.7.0",
+ "decamelize": "^1.2.0",
+ "find-cache-dir": "^3.2.0",
+ "find-up": "^4.1.0",
+ "foreground-child": "^2.0.0",
+ "glob": "^7.1.6",
+ "istanbul-lib-coverage": "^3.0.0",
+ "istanbul-lib-hook": "^3.0.0",
+ "istanbul-lib-instrument": "^4.0.0",
+ "istanbul-lib-processinfo": "^2.0.2",
+ "istanbul-lib-report": "^3.0.0",
+ "istanbul-lib-source-maps": "^4.0.0",
+ "istanbul-reports": "^3.0.0",
"js-yaml": "^3.13.1",
- "make-dir": "^2.1.0",
- "merge-source-map": "^1.1.0",
- "resolve-from": "^4.0.0",
- "rimraf": "^2.6.3",
+ "make-dir": "^3.0.0",
+ "node-preload": "^0.2.0",
+ "p-map": "^3.0.0",
+ "process-on-spawn": "^1.0.0",
+ "resolve-from": "^5.0.0",
+ "rimraf": "^3.0.0",
"signal-exit": "^3.0.2",
- "spawn-wrap": "^1.4.2",
- "test-exclude": "^5.2.3",
- "uuid": "^3.3.2",
- "yargs": "^13.2.2",
- "yargs-parser": "^13.0.0"
+ "spawn-wrap": "^2.0.0",
+ "test-exclude": "^6.0.0",
+ "uuid": "^3.3.3",
+ "yargs": "^15.0.2"
},
"dependencies": {
- "cp-file": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz",
- "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==",
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
+ },
+ "ansi-styles": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.0.tgz",
+ "integrity": "sha512-7kFQgnEaMdRtwf6uSfUnVr9gSGC7faurn+J/Mv90/W+iTtN0405/nLdopfMWwchyxhbGYl6TC4Sccn9TUkGAgg==",
"requires": {
- "graceful-fs": "^4.1.2",
- "make-dir": "^2.0.0",
- "nested-error-stacks": "^2.0.0",
- "pify": "^4.0.1",
- "safe-buffer": "^5.0.1"
+ "@types/color-name": "^1.1.1",
+ "color-convert": "^2.0.1"
+ }
+ },
+ "cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ },
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "p-map": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
+ "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
+ "requires": {
+ "aggregate-error": "^3.0.0"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
+ },
+ "resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ },
+ "wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "yargs": {
+ "version": "15.0.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.0.2.tgz",
+ "integrity": "sha512-GH/X/hYt+x5hOat4LMnCqMd8r5Cv78heOMIJn1hr7QPPBqfeC6p89Y78+WB9yGDvfpCvgasfmWLzNzEioOUD9Q==",
+ "requires": {
+ "cliui": "^6.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^4.1.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^4.2.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^16.1.0"
+ }
+ },
+ "yargs-parser": {
+ "version": "16.1.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz",
+ "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==",
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
}
}
}
@@ -11538,6 +11890,7 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+ "dev": true,
"requires": {
"minimist": "~0.0.1",
"wordwrap": "~0.0.2"
@@ -11600,11 +11953,6 @@
}
}
},
- "os-homedir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
- "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
- },
"os-name": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz",
@@ -11700,12 +12048,12 @@
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
},
"package-hash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz",
- "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz",
+ "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==",
"requires": {
"graceful-fs": "^4.1.15",
- "hasha": "^3.0.0",
+ "hasha": "^5.0.0",
"lodash.flattendeep": "^4.4.0",
"release-zalgo": "^1.0.0"
}
@@ -11850,6 +12198,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "dev": true,
"requires": {
"pify": "^3.0.0"
},
@@ -11857,7 +12206,8 @@
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
- "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
}
}
},
@@ -11960,11 +12310,6 @@
"integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==",
"dev": true
},
- "pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
- },
"pkg-conf": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz",
@@ -12025,11 +12370,43 @@
}
},
"pkg-dir": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
- "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
"requires": {
- "find-up": "^3.0.0"
+ "find-up": "^4.0.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
+ }
}
},
"pluralize": {
@@ -12102,6 +12479,14 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
+ "process-on-spawn": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
+ "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==",
+ "requires": {
+ "fromentries": "^1.2.0"
+ }
+ },
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@@ -12307,21 +12692,13 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
"integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
+ "dev": true,
"requires": {
"load-json-file": "^4.0.0",
"normalize-package-data": "^2.3.2",
"path-type": "^3.0.0"
}
},
- "read-pkg-up": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz",
- "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==",
- "requires": {
- "find-up": "^3.0.0",
- "read-pkg": "^3.0.0"
- }
- },
"readable-stream": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
@@ -12563,7 +12940,8 @@
"resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
},
"resolve-url": {
"version": "0.2.1",
@@ -12607,9 +12985,9 @@
"dev": true
},
"rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz",
+ "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==",
"requires": {
"glob": "^7.1.3"
}
@@ -13460,16 +13838,26 @@
"dev": true
},
"spawn-wrap": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz",
- "integrity": "sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz",
+ "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==",
"requires": {
- "foreground-child": "^1.5.6",
- "mkdirp": "^0.5.0",
- "os-homedir": "^1.0.1",
- "rimraf": "^2.6.2",
+ "foreground-child": "^2.0.0",
+ "is-windows": "^1.0.2",
+ "make-dir": "^3.0.0",
+ "rimraf": "^3.0.0",
"signal-exit": "^3.0.2",
- "which": "^1.3.0"
+ "which": "^2.0.1"
+ },
+ "dependencies": {
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
}
},
"spdx-correct": {
@@ -13972,14 +14360,13 @@
}
},
"test-exclude": {
- "version": "5.2.3",
- "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz",
- "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
"requires": {
- "glob": "^7.1.3",
- "minimatch": "^3.0.4",
- "read-pkg-up": "^4.0.0",
- "require-main-filename": "^2.0.0"
+ "@istanbuljs/schema": "^0.1.2",
+ "glob": "^7.1.4",
+ "minimatch": "^3.0.4"
}
},
"text-extensions": {
@@ -14245,6 +14632,14 @@
"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"
+ }
+ },
"typeforce": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
@@ -14265,6 +14660,7 @@
"version": "3.6.5",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.5.tgz",
"integrity": "sha512-7L3W+Npia1OCr5Blp4/Vw83tK1mu5gnoIURtT1fUVfQ3Kf8WStWV6NJz0fdoBJZls0KlweruRTLVe6XLafmy5g==",
+ "dev": true,
"optional": true,
"requires": {
"commander": "~2.20.3",
@@ -14275,12 +14671,14 @@
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true,
"optional": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
"optional": true
}
}
@@ -14825,7 +15223,8 @@
"wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
- "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
+ "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
+ "dev": true
},
"wrap-ansi": {
"version": "5.1.0",
@@ -14854,6 +15253,7 @@
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
"integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
+ "dev": true,
"requires": {
"graceful-fs": "^4.1.11",
"imurmurhash": "^0.1.4",
From 6efcd9d80459b2e2ea0c1522bfb1d11b654d4940 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Mon, 23 Dec 2019 10:45:09 -0800
Subject: [PATCH 45/49] Adding script to gitignore
---
.gitignore | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.gitignore b/.gitignore
index ef6da67..15e6fa1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@ start-decatur-main
start-decatur-test
start-bitcoincom.sh
test-remote-server.sh
+start-bitcoincom-testnet.sh
coverage
start-my-infra
@@ -16,3 +17,4 @@ nohup.out
slp-tx-db/
logs/
docs/*
+
From 22245c47c8721a1b7781168a327994c9ac7e7320 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Mon, 23 Dec 2019 12:11:37 -0800
Subject: [PATCH 46/49] Updating gitignore
---
.gitignore | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.gitignore b/.gitignore
index 15e6fa1..dfc88cb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,8 @@ start-decatur-test
start-bitcoincom.sh
test-remote-server.sh
start-bitcoincom-testnet.sh
+start-local-server.sh
+start-local-testnet-server.sh
coverage
start-my-infra
From 09ee4e4de084b66dd103533bf2d4480b16a5bd7d Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com>
Date: Thu, 9 Jan 2020 21:00:58 +0000
Subject: [PATCH 47/49] chore(package): update semantic-release to version
16.0.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index bad4f7f..cf9a3d6 100644
--- a/package.json
+++ b/package.json
@@ -65,7 +65,7 @@
"proxyquire": "^2.1.0",
"request": "^2.88.0",
"request-promise": "^4.2.2",
- "semantic-release": "^15.13.19",
+ "semantic-release": "^16.0.0",
"sinon": "^7.3.2",
"typescript": "^3.1.4"
},
From 8c28a53b3a65a186b7e6287c1c732008c6886460 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com>
Date: Thu, 9 Jan 2020 21:01:07 +0000
Subject: [PATCH 48/49] chore(package): update lockfile package-lock.json
---
package-lock.json | 766 +++++++++++++++++++++++++---------------------
1 file changed, 419 insertions(+), 347 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index f5b6bb3..5800567 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -64,6 +64,15 @@
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz",
"integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A=="
},
+ "@babel/runtime": {
+ "version": "7.7.7",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.7.tgz",
+ "integrity": "sha512-uCnC2JEVAu8AKB5do1WRIsvrdJ0flYx/A/9f/6chdacnEZ7LmavjdsDXr5ksYBegxtuTPR5Va9/+13QF/kFkCA==",
+ "dev": true,
+ "requires": {
+ "regenerator-runtime": "^0.13.2"
+ }
+ },
"@babel/template": {
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz",
@@ -175,12 +184,12 @@
}
},
"@octokit/endpoint": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.0.tgz",
- "integrity": "sha512-TXYS6zXeBImNB9BVj+LneMDqXX+H0exkOpyXobvp92O3B1348QsKnNioISFKgOMsb3ibZvQGwCdpiwQd3KAjIA==",
+ "version": "5.5.1",
+ "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.1.tgz",
+ "integrity": "sha512-nBFhRUb5YzVTCX/iAK1MgQ4uWo89Gu0TH00qQHoYRCsE12dWcG1OiLd7v2EIo2+tpUKPMOQ62QFy9hy9Vg2ULg==",
"dev": true,
"requires": {
- "@octokit/types": "^1.0.0",
+ "@octokit/types": "^2.0.0",
"is-plain-object": "^3.0.0",
"universal-user-agent": "^4.0.0"
},
@@ -203,14 +212,14 @@
}
},
"@octokit/request": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.0.tgz",
- "integrity": "sha512-mMIeNrtYyNEIYNsKivDyUAukBkw0M5ckyJX56xoFRXSasDPCloIXaQOnaKNopzQ8dIOvpdq1ma8gmrS+h6O2OQ==",
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.1.tgz",
+ "integrity": "sha512-5/X0AL1ZgoU32fAepTfEoggFinO3rxsMLtzhlUX+RctLrusn/CApJuGFCd0v7GMFhF+8UiCsTTfsu7Fh1HnEJg==",
"dev": true,
"requires": {
"@octokit/endpoint": "^5.5.0",
"@octokit/request-error": "^1.0.1",
- "@octokit/types": "^1.0.0",
+ "@octokit/types": "^2.0.0",
"deprecation": "^2.0.0",
"is-plain-object": "^3.0.0",
"node-fetch": "^2.3.0",
@@ -236,19 +245,20 @@
}
},
"@octokit/request-error": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.0.4.tgz",
- "integrity": "sha512-L4JaJDXn8SGT+5G0uX79rZLv0MNJmfGa4vb4vy1NnpjSnWDLJRy6m90udGwvMmavwsStgbv2QNkPzzTCMmL+ig==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.0.tgz",
+ "integrity": "sha512-DNBhROBYjjV/I9n7A8kVkmQNkqFAMem90dSxqvPq57e2hBr7mNTX98y3R2zDpqMQHVRpBDjsvsfIGgBzy+4PAg==",
"dev": true,
"requires": {
+ "@octokit/types": "^2.0.0",
"deprecation": "^2.0.0",
"once": "^1.4.0"
}
},
"@octokit/rest": {
- "version": "16.34.0",
- "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.34.0.tgz",
- "integrity": "sha512-EBe5qMQQOZRuezahWCXCnSe0J6tAqrW2hrEH9U8esXzKor1+HUDf8jgImaZf5lkTyWCQA296x9kAH5c0pxEgVQ==",
+ "version": "16.36.0",
+ "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.36.0.tgz",
+ "integrity": "sha512-zoZj7Ya4vWBK4fjTwK2Cnmu7XBB1p9ygSvTk2TthN6DVJXM4hQZQoAiknWFLJWSTix4dnA3vuHtjPZbExYoCZA==",
"dev": true,
"requires": {
"@octokit/request": "^5.2.0",
@@ -266,34 +276,27 @@
}
},
"@octokit/types": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@octokit/types/-/types-1.1.0.tgz",
- "integrity": "sha512-t4ZD74UnNVMq6kZBDZceflRKK3q4o5PoCKMAGht0RK84W57tqonqKL3vCxJHtbGExdan9RwV8r7VJBZxIM1O7Q==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.0.2.tgz",
+ "integrity": "sha512-StASIL2lgT3TRjxv17z9pAqbnI7HGu9DrJlg3sEBFfCLaMEqp+O3IQPUF6EZtQ4xkAu2ml6kMBBCtGxjvmtmuQ==",
"dev": true,
"requires": {
- "@types/node": "^12.11.1"
- },
- "dependencies": {
- "@types/node": {
- "version": "12.12.3",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.3.tgz",
- "integrity": "sha512-opgSsy+cEF9N8MgaVPnWVtdJ3o4mV2aMHvDq7thkQUFt0EuOHJon4rQpJfhjmNHB+ikl0Cd6WhWIErOyQ+f7tw==",
- "dev": true
- }
+ "@types/node": ">= 8"
}
},
"@semantic-release/commit-analyzer": {
- "version": "6.3.2",
- "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-6.3.2.tgz",
- "integrity": "sha512-TezpOODuMcdDuGcGsI2QRqkH3sT7ffhsxid9J8OyspXDe8E4tshekJESJ6Pq8jTrggluKd3tCK26Vsyu6SkeSg==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-7.0.0.tgz",
+ "integrity": "sha512-t5wMGByv+SknjP2m3rhWN4vmXoQ16g5VFY8iC4/tcbLPvzxK+35xsTIeUsrVFZv3ymdgAQKIr5J3lKjhF/VZZQ==",
"dev": true,
"requires": {
"conventional-changelog-angular": "^5.0.0",
"conventional-commits-filter": "^2.0.0",
- "conventional-commits-parser": "^3.0.0",
+ "conventional-commits-parser": "^3.0.7",
"debug": "^4.0.0",
"import-from": "^3.0.0",
- "lodash": "^4.17.4"
+ "lodash": "^4.17.4",
+ "micromatch": "^3.1.10"
}
},
"@semantic-release/error": {
@@ -303,9 +306,9 @@
"dev": true
},
"@semantic-release/github": {
- "version": "5.5.5",
- "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-5.5.5.tgz",
- "integrity": "sha512-Wo9OIULMRydbq+HpFh9yiLvra1XyEULPro9Tp4T5MQJ0WZyAQ3YQm74IdT8Pe/UmVDq2nfpT1oHrWkwOc4loHg==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-6.0.0.tgz",
+ "integrity": "sha512-lqRpCHxPAWTcl9QtDMH3c6UaB6vh3WDd7MqbmBubeHyVw4Nhxb1EpoWAlTMbUn1LEG9JzVZWez13ZFCjIdY6bA==",
"dev": true,
"requires": {
"@octokit/rest": "^16.27.0",
@@ -316,8 +319,8 @@
"dir-glob": "^3.0.0",
"fs-extra": "^8.0.0",
"globby": "^10.0.0",
- "http-proxy-agent": "^2.1.0",
- "https-proxy-agent": "^3.0.0",
+ "http-proxy-agent": "^3.0.0",
+ "https-proxy-agent": "^4.0.0",
"issue-parser": "^5.0.0",
"lodash": "^4.17.4",
"mime": "^2.4.3",
@@ -335,14 +338,14 @@
}
},
"@semantic-release/npm": {
- "version": "5.3.4",
- "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-5.3.4.tgz",
- "integrity": "sha512-XjITNRA/oOpJ7BfHk/WaOHs1WniYBszTde/bwADjjk1Luacpxg87jbDQVVt/oA3Zlx+MelxACRIEuRiPC5gu8g==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-6.0.0.tgz",
+ "integrity": "sha512-aqODzbtWpVHO/keinbBMnZEaN/TkdwQvyDWcT0oNbKFpZwLjNjn+QVItoLekF62FLlXXziu2y6V4wnl9FDnujA==",
"dev": true,
"requires": {
"@semantic-release/error": "^2.2.0",
"aggregate-error": "^3.0.0",
- "execa": "^3.2.0",
+ "execa": "^4.0.0",
"fs-extra": "^8.0.0",
"lodash": "^4.17.15",
"nerf-dart": "^1.0.0",
@@ -351,6 +354,7 @@
"rc": "^1.2.8",
"read-pkg": "^5.0.0",
"registry-auth-token": "^4.0.0",
+ "semver": "^6.3.0",
"tempy": "^0.3.0"
},
"dependencies": {
@@ -366,9 +370,9 @@
}
},
"execa": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz",
- "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.0.tgz",
+ "integrity": "sha512-JbDUxwV3BoT5ZVXQrSVbAiaXhXUkIwvbhPIwZ0N13kX+5yCzOhUNdocxB/UQRuYOHRYYwAxKYwJYc0T4D12pDA==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.0",
@@ -378,7 +382,6 @@
"merge-stream": "^2.0.0",
"npm-run-path": "^4.0.0",
"onetime": "^5.1.0",
- "p-finally": "^2.0.0",
"signal-exit": "^3.0.2",
"strip-final-newline": "^2.0.0"
}
@@ -405,9 +408,9 @@
"dev": true
},
"npm-run-path": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.0.tgz",
- "integrity": "sha512-8eyAOAH+bYXFPSnNnKr3J+yoybe8O87Is5rtAQ8qRczJz1ajcsjg8l2oZqP+Ppx15Ii3S1vUTjQN2h4YO2tWWQ==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
"dev": true,
"requires": {
"path-key": "^3.0.0"
@@ -422,12 +425,6 @@
"mimic-fn": "^2.1.0"
}
},
- "p-finally": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz",
- "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==",
- "dev": true
- },
"parse-json": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz",
@@ -468,6 +465,12 @@
"safe-buffer": "^5.0.1"
}
},
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ },
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -495,9 +498,9 @@
}
},
"@semantic-release/release-notes-generator": {
- "version": "7.3.2",
- "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-7.3.2.tgz",
- "integrity": "sha512-vYGydZPoQqL4aJOsaqXTZIekRb3aa/OlxlEVUvyrWWlNGqmQ1T7NUOos9eoN5DBCEuk6PwDrxPbhzgswxcvprQ==",
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-7.3.5.tgz",
+ "integrity": "sha512-LGjgPBGjjmjap/76O0Md3wc04Y7IlLnzZceLsAkcYRwGQdRPTTFUJKqDQTuieWTs7zfHzQoZqsqPfFxEN+g2+Q==",
"dev": true,
"requires": {
"conventional-changelog-angular": "^5.0.0",
@@ -588,9 +591,9 @@
}
},
"read-pkg-up": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.0.tgz",
- "integrity": "sha512-t2ODkS/vTTcRlKwZiZsaLGb5iwfx9Urp924aGzVyboU6+7Z2i6eGr/G1Z4mjvwLLQV3uFOBKobNRGM3ux2PD/w==",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+ "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
"dev": true,
"requires": {
"find-up": "^4.1.0",
@@ -642,6 +645,12 @@
"integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
"dev": true
},
+ "@types/color-name": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
+ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
+ "dev": true
+ },
"@types/events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
@@ -676,6 +685,12 @@
"integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
"dev": true
},
+ "@types/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+ "dev": true
+ },
"@types/retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
@@ -742,13 +757,10 @@
"integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
},
"agent-base": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
- "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
- "dev": true,
- "requires": {
- "es6-promisify": "^5.0.0"
- }
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
+ "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==",
+ "dev": true
},
"aggregate-error": {
"version": "3.0.1",
@@ -1016,12 +1028,6 @@
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true
},
- "array-uniq": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-2.1.0.tgz",
- "integrity": "sha512-bdHxtev7FN6+MXI1YFW0Q8mQ8dTJc2S8AMfju+ZR77pbg2yAdVyDlwkaUI7Har0LyOMRFPHrJ9lYdyjZZswdlQ==",
- "dev": true
- },
"array-unique": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
@@ -1868,23 +1874,6 @@
}
}
},
- "caller-callsite": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
- "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
- "dev": true,
- "requires": {
- "callsites": "^2.0.0"
- },
- "dependencies": {
- "callsites": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
- "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
- "dev": true
- }
- }
- },
"caller-path": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
@@ -2385,9 +2374,9 @@
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"conventional-changelog-angular": {
- "version": "5.0.5",
- "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.5.tgz",
- "integrity": "sha512-RrkdWnL/TVyWV1ayWmSsrWorsTDqjL/VwG5ZSEneBQrd65ONcfeA1cW7FLtNweQyMiKOyriCMTKRSlk18DjTrw==",
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz",
+ "integrity": "sha512-QDEmLa+7qdhVIv8sFZfVxU1VSyVvnXPsxq8Vam49mKUcO1Z8VTLEJk9uI21uiJUsnmm0I4Hrsdc9TgkOQo9WSA==",
"dev": true,
"requires": {
"compare-func": "^1.3.1",
@@ -2395,9 +2384,9 @@
}
},
"conventional-changelog-writer": {
- "version": "4.0.9",
- "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.9.tgz",
- "integrity": "sha512-2Y3QfiAM37WvDMjkVNaRtZgxVzWKj73HE61YQ/95T53yle+CRwTVSl6Gbv/lWVKXeZcM5af9n9TDVf0k7Xh+cw==",
+ "version": "4.0.11",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.11.tgz",
+ "integrity": "sha512-g81GQOR392I+57Cw3IyP1f+f42ME6aEkbR+L7v1FBBWolB0xkjKTeCWVguzRrp6UiT1O6gBpJbEy2eq7AnV1rw==",
"dev": true,
"requires": {
"compare-func": "^1.3.1",
@@ -2405,8 +2394,8 @@
"dateformat": "^3.0.0",
"handlebars": "^4.4.0",
"json-stringify-safe": "^5.0.1",
- "lodash": "^4.2.1",
- "meow": "^4.0.0",
+ "lodash": "^4.17.15",
+ "meow": "^5.0.0",
"semver": "^6.0.0",
"split": "^1.0.0",
"through2": "^3.0.0"
@@ -2440,24 +2429,24 @@
}
},
"conventional-commits-parser": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.5.tgz",
- "integrity": "sha512-qVz9+5JwdJzsbt7JbJ6P7NOXBGt8CyLFJYSjKAuPSgO+5UGfcsbk9EMR+lI8Unlvx6qwIc2YDJlrGIfay2ehNA==",
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.8.tgz",
+ "integrity": "sha512-YcBSGkZbYp7d+Cr3NWUeXbPDFUN6g3SaSIzOybi8bjHL5IJ5225OSCxJJ4LgziyEJ7AaJtE9L2/EU6H7Nt/DDQ==",
"dev": true,
"requires": {
"JSONStream": "^1.0.4",
- "is-text-path": "^2.0.0",
- "lodash": "^4.2.1",
- "meow": "^4.0.0",
+ "is-text-path": "^1.0.1",
+ "lodash": "^4.17.15",
+ "meow": "^5.0.0",
"split2": "^2.0.0",
"through2": "^3.0.0",
"trim-off-newlines": "^1.0.0"
},
"dependencies": {
"readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -2571,40 +2560,34 @@
}
},
"cosmiconfig": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
- "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
+ "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
"dev": true,
"requires": {
- "import-fresh": "^2.0.0",
- "is-directory": "^0.3.1",
- "js-yaml": "^3.13.1",
- "parse-json": "^4.0.0"
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.1.0",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.7.2"
},
"dependencies": {
- "caller-path": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
- "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
+ "parse-json": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz",
+ "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==",
"dev": true,
"requires": {
- "caller-callsite": "^2.0.0"
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1",
+ "lines-and-columns": "^1.1.6"
}
},
- "import-fresh": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
- "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
- "dev": true,
- "requires": {
- "caller-path": "^2.0.0",
- "resolve-from": "^3.0.0"
- }
- },
- "resolve-from": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
- "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true
}
}
@@ -3006,9 +2989,9 @@
},
"dependencies": {
"readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -3217,9 +3200,9 @@
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
},
"env-ci": {
- "version": "4.5.1",
- "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-4.5.1.tgz",
- "integrity": "sha512-Xtmr+ordf8POu3NcNzx3eOa2zHyfD4h3fPHX5fLklkWa86ck35n1c9oZmyUnVPUl9zHnpZWdWtCUBPSWEagjCQ==",
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-4.5.2.tgz",
+ "integrity": "sha512-lS+edpNp2+QXEPkx6raEMIjKxKKWnJ4+VWzovYJ2NLYiJAYenSAXotFfVdgaFxdbVnvAbUI8epQDa1u12ERxfQ==",
"dev": true,
"requires": {
"execa": "^3.2.0",
@@ -3238,9 +3221,9 @@
}
},
"execa": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-3.2.0.tgz",
- "integrity": "sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw==",
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz",
+ "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.0",
@@ -3277,9 +3260,9 @@
"dev": true
},
"npm-run-path": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.0.tgz",
- "integrity": "sha512-8eyAOAH+bYXFPSnNnKr3J+yoybe8O87Is5rtAQ8qRczJz1ajcsjg8l2oZqP+Ppx15Ii3S1vUTjQN2h4YO2tWWQ==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
"dev": true,
"requires": {
"path-key": "^3.0.0"
@@ -3301,9 +3284,9 @@
"dev": true
},
"path-key": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz",
- "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true
},
"shebang-command": {
@@ -3322,9 +3305,9 @@
"dev": true
},
"which": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.1.tgz",
- "integrity": "sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
@@ -3430,21 +3413,6 @@
"resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz",
"integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw="
},
- "es6-promise": {
- "version": "4.2.8",
- "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
- "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
- "dev": true
- },
- "es6-promisify": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
- "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
- "dev": true,
- "requires": {
- "es6-promise": "^4.0.3"
- }
- },
"es6-set": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
@@ -4469,9 +4437,9 @@
"dev": true
},
"fast-glob": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.0.tgz",
- "integrity": "sha512-TrUz3THiq2Vy3bjfQUB2wNyPdGBeGmdjbzzBLhfHN4YFurYptCKwGq/TfiRavbGywFRzY6U2CdmQ1zmsY5yYaw==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.1.tgz",
+ "integrity": "sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "^2.0.2",
@@ -4699,12 +4667,11 @@
}
},
"find-versions": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.1.0.tgz",
- "integrity": "sha512-NCTfNiVzeE/xL+roNDffGuRbrWI6atI18lTJ22vKp7rs2OhYzMK3W1dIdO2TUndH/QMcacM4d1uWwgcZcHK69Q==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz",
+ "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==",
"dev": true,
"requires": {
- "array-uniq": "^2.1.0",
"semver-regex": "^2.0.0"
}
},
@@ -4841,9 +4808,9 @@
},
"dependencies": {
"readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -5607,9 +5574,9 @@
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
},
"globby": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz",
- "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==",
+ "version": "10.0.2",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz",
+ "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==",
"dev": true,
"requires": {
"@types/glob": "^7.1.1",
@@ -5627,12 +5594,6 @@
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz",
"integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==",
"dev": true
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
}
}
},
@@ -5969,30 +5930,13 @@
}
},
"http-proxy-agent": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
- "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-3.0.0.tgz",
+ "integrity": "sha512-uGuJaBWQWDQCJI5ip0d/VTYZW0nRrlLWXA4A7P1jrsa+f77rW2yXz315oBt6zGCF6l8C2tlMxY7ffULCj+5FhA==",
"dev": true,
"requires": {
- "agent-base": "4",
- "debug": "3.1.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
- "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
- "dev": true
- }
+ "agent-base": "5",
+ "debug": "4"
}
},
"http-signature": {
@@ -6007,24 +5951,13 @@
}
},
"https-proxy-agent": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz",
- "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
+ "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
"dev": true,
"requires": {
- "agent-base": "^4.3.0",
- "debug": "^3.1.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
- "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
- }
- }
+ "agent-base": "5",
+ "debug": "4"
}
},
"human-signals": {
@@ -6318,12 +6251,6 @@
}
}
},
- "is-directory": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
- "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
- "dev": true
- },
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
@@ -6496,12 +6423,12 @@
}
},
"is-text-path": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz",
- "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz",
+ "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=",
"dev": true,
"requires": {
- "text-extensions": "^2.0.0"
+ "text-extensions": "^1.0.0"
}
},
"is-typedarray": {
@@ -7170,22 +7097,28 @@
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"meow": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz",
- "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz",
+ "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==",
"dev": true,
"requires": {
"camelcase-keys": "^4.0.0",
"decamelize-keys": "^1.0.0",
"loud-rejection": "^1.0.0",
- "minimist": "^1.1.3",
"minimist-options": "^3.0.1",
"normalize-package-data": "^2.3.4",
"read-pkg-up": "^3.0.0",
"redent": "^2.0.0",
- "trim-newlines": "^2.0.0"
+ "trim-newlines": "^2.0.0",
+ "yargs-parser": "^10.0.0"
},
"dependencies": {
+ "camelcase": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
+ "dev": true
+ },
"find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
@@ -7205,12 +7138,6 @@
"path-exists": "^3.0.0"
}
},
- "minimist": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
- "dev": true
- },
"p-limit": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
@@ -7244,6 +7171,15 @@
"find-up": "^2.0.0",
"read-pkg": "^3.0.0"
}
+ },
+ "yargs-parser": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz",
+ "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^4.1.0"
+ }
}
}
},
@@ -7828,9 +7764,9 @@
"dev": true
},
"npm": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/npm/-/npm-6.13.2.tgz",
- "integrity": "sha512-TG7AFkKpjBNJh8OVJYcGaAbW0PZxEkjew51Lc6TRdhQpNjSSEnAOEpidApqEuciB7cs09C8mxbo8NbuPs4QDzg==",
+ "version": "6.13.4",
+ "resolved": "https://registry.npmjs.org/npm/-/npm-6.13.4.tgz",
+ "integrity": "sha512-vTcUL4SCg3AzwInWTbqg1OIaOXlzKSS8Mb8kc5avwrJpcvevDA5J9BhYSuei+fNs3pwOp4lzA5x2FVDXACvoXA==",
"dev": true,
"requires": {
"JSONStream": "^1.3.5",
@@ -7839,7 +7775,7 @@
"ansistyles": "~0.1.3",
"aproba": "^2.0.0",
"archy": "~1.0.0",
- "bin-links": "^1.1.3",
+ "bin-links": "^1.1.6",
"bluebird": "^3.5.5",
"byte-size": "^5.0.1",
"cacache": "^12.0.3",
@@ -7860,7 +7796,7 @@
"find-npm-prefix": "^1.0.2",
"fs-vacuum": "~1.2.10",
"fs-write-stream-atomic": "~1.0.10",
- "gentle-fs": "^2.2.1",
+ "gentle-fs": "^2.3.0",
"glob": "^7.1.4",
"graceful-fs": "^4.2.3",
"has-unicode": "~2.0.1",
@@ -7909,7 +7845,7 @@
"npm-install-checks": "^3.0.2",
"npm-lifecycle": "^3.1.4",
"npm-package-arg": "^6.1.1",
- "npm-packlist": "^1.4.6",
+ "npm-packlist": "^1.4.7",
"npm-pick-manifest": "^3.0.2",
"npm-profile": "^4.0.2",
"npm-registry-fetch": "^4.0.2",
@@ -7918,7 +7854,7 @@
"once": "~1.4.0",
"opener": "^1.5.1",
"osenv": "^0.1.5",
- "pacote": "^9.5.9",
+ "pacote": "^9.5.11",
"path-is-inside": "~1.0.2",
"promise-inflight": "~1.0.1",
"qrcode-terminal": "^0.12.0",
@@ -7927,7 +7863,7 @@
"read": "~1.0.7",
"read-cmd-shim": "^1.0.5",
"read-installed": "~4.0.3",
- "read-package-json": "^2.1.0",
+ "read-package-json": "^2.1.1",
"read-package-tree": "^5.3.1",
"readable-stream": "^3.4.0",
"readdir-scoped-modules": "^1.1.0",
@@ -8121,14 +8057,15 @@
}
},
"bin-links": {
- "version": "1.1.3",
+ "version": "1.1.6",
"bundled": true,
"dev": true,
"requires": {
"bluebird": "^3.5.3",
"cmd-shim": "^3.0.0",
- "gentle-fs": "^2.0.1",
+ "gentle-fs": "^2.3.0",
"graceful-fs": "^4.1.15",
+ "npm-normalize-package-bin": "^1.0.0",
"write-file-atomic": "^2.3.0"
}
},
@@ -8987,12 +8924,13 @@
"dev": true
},
"gentle-fs": {
- "version": "2.2.1",
+ "version": "2.3.0",
"bundled": true,
"dev": true,
"requires": {
"aproba": "^1.1.2",
"chownr": "^1.1.2",
+ "cmd-shim": "^3.0.3",
"fs-vacuum": "^1.2.10",
"graceful-fs": "^4.1.11",
"iferr": "^0.1.5",
@@ -9959,9 +9897,12 @@
}
},
"npm-bundled": {
- "version": "1.0.6",
+ "version": "1.1.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "npm-normalize-package-bin": "^1.0.1"
+ }
},
"npm-cache-filename": {
"version": "1.0.2",
@@ -9996,6 +9937,11 @@
"bundled": true,
"dev": true
},
+ "npm-normalize-package-bin": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true
+ },
"npm-package-arg": {
"version": "6.1.1",
"bundled": true,
@@ -10008,7 +9954,7 @@
}
},
"npm-packlist": {
- "version": "1.4.6",
+ "version": "1.4.7",
"bundled": true,
"dev": true,
"requires": {
@@ -10190,7 +10136,7 @@
}
},
"pacote": {
- "version": "9.5.9",
+ "version": "9.5.11",
"bundled": true,
"dev": true,
"requires": {
@@ -10208,6 +10154,7 @@
"mississippi": "^3.0.0",
"mkdirp": "^0.5.1",
"normalize-package-data": "^2.4.0",
+ "npm-normalize-package-bin": "^1.0.0",
"npm-package-arg": "^6.1.0",
"npm-packlist": "^1.1.12",
"npm-pick-manifest": "^3.0.0",
@@ -10481,7 +10428,7 @@
}
},
"read-package-json": {
- "version": "2.1.0",
+ "version": "2.1.1",
"bundled": true,
"dev": true,
"requires": {
@@ -10489,7 +10436,7 @@
"graceful-fs": "^4.1.2",
"json-parse-better-errors": "^1.0.1",
"normalize-package-data": "^2.0.0",
- "slash": "^1.0.0"
+ "npm-normalize-package-bin": "^1.0.0"
}
},
"read-package-tree": {
@@ -10664,11 +10611,6 @@
"bundled": true,
"dev": true
},
- "slash": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
"slide": {
"version": "1.1.6",
"bundled": true,
@@ -11620,6 +11562,12 @@
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
},
+ "p-each-series": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz",
+ "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==",
+ "dev": true
+ },
"p-event": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-event/-/p-event-4.1.0.tgz",
@@ -11677,9 +11625,9 @@
"dev": true
},
"p-retry": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.1.0.tgz",
- "integrity": "sha512-oepllyG9gX1qH4Sm20YAKxg1GA7L7puhvGnTfimi31P07zSIj7SDV6YtuAx9nbJF51DES+2CIIRkXs8GKqWJxA==",
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.2.0.tgz",
+ "integrity": "sha512-jPH38/MRh263KKcq0wBNOGFJbm+U6784RilTmHjB/HM9kH9V8WlCpVUcdOmip9cjXOh6MxZ5yk1z2SjDUJfWmA==",
"dev": true,
"requires": {
"@types/retry": "^0.12.0",
@@ -11955,9 +11903,9 @@
}
},
"picomatch": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz",
- "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==",
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz",
+ "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==",
"dev": true
},
"pify": {
@@ -12399,6 +12347,12 @@
"resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz",
"integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA=="
},
+ "regenerator-runtime": {
+ "version": "0.13.3",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
+ "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==",
+ "dev": true
+ },
"regex-not": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
@@ -12706,18 +12660,18 @@
}
},
"semantic-release": {
- "version": "15.13.28",
- "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-15.13.28.tgz",
- "integrity": "sha512-TqmRAsTFPq+hi0LjccUIHIknpW2wBPqVZWc/fVBBeeokuZ+wfGcP/Vo8nKci7VTHBl0D/EAu6gNvo343dKjWUA==",
+ "version": "16.0.0",
+ "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-16.0.0.tgz",
+ "integrity": "sha512-mwoZEIUXJPvRZFsUrPGDjr3weKMGFmO+b5wNdBbVKCMQArKZpWi99bqPJvAv7encTo9MIPPOKENB5SefEiv8xA==",
"dev": true,
"requires": {
- "@semantic-release/commit-analyzer": "^6.1.0",
+ "@semantic-release/commit-analyzer": "^7.0.0",
"@semantic-release/error": "^2.2.0",
- "@semantic-release/github": "^5.1.0",
- "@semantic-release/npm": "^5.0.5",
+ "@semantic-release/github": "^6.0.0",
+ "@semantic-release/npm": "^6.0.0",
"@semantic-release/release-notes-generator": "^7.1.2",
"aggregate-error": "^3.0.0",
- "cosmiconfig": "^5.0.1",
+ "cosmiconfig": "^6.0.0",
"debug": "^4.0.0",
"env-ci": "^4.0.0",
"execa": "^3.2.0",
@@ -12730,15 +12684,68 @@
"lodash": "^4.17.15",
"marked": "^0.7.0",
"marked-terminal": "^3.2.0",
- "p-locate": "^4.0.0",
+ "micromatch": "^4.0.2",
+ "p-each-series": "^2.1.0",
"p-reduce": "^2.0.0",
"read-pkg-up": "^7.0.0",
"resolve-from": "^5.0.0",
"semver": "^6.0.0",
+ "semver-diff": "^3.1.1",
"signale": "^1.2.1",
- "yargs": "^14.0.0"
+ "yargs": "^15.0.1"
},
"dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+ "dev": true,
+ "requires": {
+ "@types/color-name": "^1.1.1",
+ "color-convert": "^2.0.1"
+ }
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
"cross-spawn": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz",
@@ -12750,10 +12757,16 @@
"which": "^2.0.1"
}
},
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
"execa": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-3.2.0.tgz",
- "integrity": "sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw==",
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz",
+ "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.0",
@@ -12777,6 +12790,15 @@
"escape-string-regexp": "^1.0.5"
}
},
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@@ -12805,6 +12827,18 @@
"lru-cache": "^5.1.1"
}
},
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
"is-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
@@ -12829,6 +12863,16 @@
"yallist": "^3.0.2"
}
},
+ "micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ }
+ },
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
@@ -12836,9 +12880,9 @@
"dev": true
},
"npm-run-path": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.0.tgz",
- "integrity": "sha512-8eyAOAH+bYXFPSnNnKr3J+yoybe8O87Is5rtAQ8qRczJz1ajcsjg8l2oZqP+Ppx15Ii3S1vUTjQN2h4YO2tWWQ==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
"dev": true,
"requires": {
"path-key": "^3.0.0"
@@ -12887,9 +12931,9 @@
"dev": true
},
"path-key": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz",
- "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true
},
"read-pkg": {
@@ -12913,9 +12957,9 @@
}
},
"read-pkg-up": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.0.tgz",
- "integrity": "sha512-t2ODkS/vTTcRlKwZiZsaLGb5iwfx9Urp924aGzVyboU6+7Z2i6eGr/G1Z4mjvwLLQV3uFOBKobNRGM3ux2PD/w==",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+ "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
"dev": true,
"requires": {
"find-up": "^4.1.0",
@@ -12935,6 +12979,15 @@
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
},
+ "semver-diff": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz",
+ "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==",
+ "dev": true,
+ "requires": {
+ "semver": "^6.3.0"
+ }
+ },
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -12950,6 +13003,35 @@
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true
},
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
@@ -12957,14 +13039,25 @@
"dev": true
},
"which": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.1.tgz",
- "integrity": "sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
}
},
+ "wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
@@ -12972,64 +13065,28 @@
"dev": true
},
"yargs": {
- "version": "14.2.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.0.tgz",
- "integrity": "sha512-/is78VKbKs70bVZH7w4YaZea6xcJWOAwkhbR0CFuZBmYtfTYF0xjGJF43AYd8g2Uii1yJwmS5GR2vBmrc32sbg==",
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.1.0.tgz",
+ "integrity": "sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg==",
"dev": true,
"requires": {
- "cliui": "^5.0.0",
+ "cliui": "^6.0.0",
"decamelize": "^1.2.0",
- "find-up": "^3.0.0",
+ "find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
- "string-width": "^3.0.0",
+ "string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
- "yargs-parser": "^15.0.0"
- },
- "dependencies": {
- "find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "dev": true,
- "requires": {
- "locate-path": "^3.0.0"
- }
- },
- "locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
- "dev": true,
- "requires": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
- }
- },
- "p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "dev": true,
- "requires": {
- "p-limit": "^2.0.0"
- }
- },
- "path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
- "dev": true
- }
+ "yargs-parser": "^16.1.0"
}
},
"yargs-parser": {
- "version": "15.0.0",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.0.tgz",
- "integrity": "sha512-xLTUnCMc4JhxrPEPUYD5IBR1mWCK/aT6+RJ/K29JY2y1vD+FhtgKK0AXRWvI262q3QSffAQuTouFIKUuHX89wQ==",
+ "version": "16.1.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz",
+ "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
@@ -13205,6 +13262,12 @@
"supports-color": "^5.5.0"
}
},
+ "slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true
+ },
"slice-ansi": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
@@ -13716,9 +13779,9 @@
},
"dependencies": {
"readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -13983,9 +14046,9 @@
}
},
"text-extensions": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.0.0.tgz",
- "integrity": "sha512-F91ZqLgvi1E0PdvmxMgp+gcf6q8fMH7mhdwWfzXnl1k+GbpQDmi8l7DzLC5JTASKbwpY3TfxajAUzAXcv2NmsQ==",
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz",
+ "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==",
"dev": true
},
"text-hex": {
@@ -14899,6 +14962,15 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
},
+ "yaml": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.7.2.tgz",
+ "integrity": "sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.6.3"
+ }
+ },
"yargs": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",
From cd64b26d5fa30e405b177dc3b6846a280a991898 Mon Sep 17 00:00:00 2001
From: Chris Troutner
Date: Sat, 11 Jan 2020 11:35:49 -0800
Subject: [PATCH 49/49] Removed nodemon
---
package-lock.json | 1182 ---------------------------------------------
package.json | 1 -
2 files changed, 1183 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 430ba6e..0aaba93 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -884,42 +884,6 @@
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz",
"integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I="
},
- "ansi-align": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
- "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=",
- "dev": true,
- "requires": {
- "string-width": "^2.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
- "dev": true
- },
- "string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "requires": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
- }
- },
- "strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "dev": true,
- "requires": {
- "ansi-regex": "^3.0.0"
- }
- }
- }
- },
"ansi-colors": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz",
@@ -949,27 +913,6 @@
"integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=",
"dev": true
},
- "anymatch": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
- "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
- "dev": true,
- "requires": {
- "micromatch": "^3.1.4",
- "normalize-path": "^2.1.1"
- },
- "dependencies": {
- "normalize-path": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
- "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
- "dev": true,
- "requires": {
- "remove-trailing-separator": "^1.0.1"
- }
- }
- }
- },
"apidoc": {
"version": "0.17.7",
"resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.17.7.tgz",
@@ -1185,12 +1128,6 @@
"lodash": "^4.17.14"
}
},
- "async-each": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
- "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
- "dev": true
- },
"async-limiter": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
@@ -1495,12 +1432,6 @@
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
"integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A=="
},
- "binary-extensions": {
- "version": "1.13.1",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
- "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
- "dev": true
- },
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
@@ -1724,54 +1655,6 @@
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.7.0.tgz",
"integrity": "sha512-aIlMvstvu8x+34KEiOHD3AsBgdrzg6sxALYiukOWhFvGMbQI6TRP/iY0LMhUrHs56aD6P1G0Z7h45PUJaa5m9w=="
},
- "boxen": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz",
- "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==",
- "dev": true,
- "requires": {
- "ansi-align": "^2.0.0",
- "camelcase": "^4.0.0",
- "chalk": "^2.0.1",
- "cli-boxes": "^1.0.0",
- "string-width": "^2.0.0",
- "term-size": "^1.2.0",
- "widest-line": "^2.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
- "dev": true
- },
- "camelcase": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
- "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
- "dev": true
- },
- "string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "requires": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
- }
- },
- "strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "dev": true,
- "requires": {
- "ansi-regex": "^3.0.0"
- }
- }
- }
- },
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -2022,12 +1905,6 @@
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz",
"integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs="
},
- "capture-stack-trace": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz",
- "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==",
- "dev": true
- },
"cardinal": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz",
@@ -2094,43 +1971,6 @@
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
"dev": true
},
- "chokidar": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
- "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
- "dev": true,
- "requires": {
- "anymatch": "^2.0.0",
- "async-each": "^1.0.1",
- "braces": "^2.3.2",
- "fsevents": "^1.2.7",
- "glob-parent": "^3.1.0",
- "inherits": "^2.0.3",
- "is-binary-path": "^1.0.0",
- "is-glob": "^4.0.0",
- "normalize-path": "^3.0.0",
- "path-is-absolute": "^1.0.0",
- "readdirp": "^2.2.1",
- "upath": "^1.1.1"
- },
- "dependencies": {
- "is-glob": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
- "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
- "dev": true,
- "requires": {
- "is-extglob": "^2.1.1"
- }
- }
- }
- },
- "ci-info": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz",
- "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==",
- "dev": true
- },
"cipher-base": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
@@ -2178,12 +2018,6 @@
"resolved": "https://registry.npmjs.org/clear/-/clear-0.1.0.tgz",
"integrity": "sha512-qMjRnoL+JDPJHeLePZJuao6+8orzHMGP04A8CdwCNsKhRbOnKRjefxONR7bwILT3MHecxKBjHkKL/tkZ8r4Uzw=="
},
- "cli-boxes": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
- "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=",
- "dev": true
- },
"cli-cursor": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
@@ -2412,37 +2246,6 @@
}
}
},
- "configstore": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz",
- "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==",
- "dev": true,
- "requires": {
- "dot-prop": "^4.1.0",
- "graceful-fs": "^4.1.2",
- "make-dir": "^1.0.0",
- "unique-string": "^1.0.0",
- "write-file-atomic": "^2.0.0",
- "xdg-basedir": "^3.0.0"
- },
- "dependencies": {
- "make-dir": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
- "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
- "dev": true,
- "requires": {
- "pify": "^3.0.0"
- }
- },
- "pify": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
- "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
- "dev": true
- }
- }
- },
"contains-path": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
@@ -2740,15 +2543,6 @@
}
}
},
- "create-error-class": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz",
- "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=",
- "dev": true,
- "requires": {
- "capture-stack-trace": "^1.0.0"
- }
- },
"create-hash": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
@@ -3091,15 +2885,6 @@
"resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz",
"integrity": "sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug=="
},
- "dot-prop": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
- "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==",
- "dev": true,
- "requires": {
- "is-obj": "^1.0.0"
- }
- },
"dotenv": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
@@ -3156,12 +2941,6 @@
}
}
},
- "duplexer3": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
- "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
- "dev": true
- },
"duplexify": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
@@ -4276,34 +4055,6 @@
"safe-buffer": "^5.1.1"
}
},
- "execa": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
- "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
- "dev": true,
- "requires": {
- "cross-spawn": "^5.0.1",
- "get-stream": "^3.0.0",
- "is-stream": "^1.1.0",
- "npm-run-path": "^2.0.0",
- "p-finally": "^1.0.0",
- "signal-exit": "^3.0.0",
- "strip-eof": "^1.0.0"
- },
- "dependencies": {
- "cross-spawn": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
- "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
- "dev": true,
- "requires": {
- "lru-cache": "^4.0.1",
- "shebang-command": "^1.2.0",
- "which": "^1.2.9"
- }
- }
- }
- },
"expand-brackets": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
@@ -5007,554 +4758,6 @@
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
- "fsevents": {
- "version": "1.2.9",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
- "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==",
- "dev": true,
- "optional": true,
- "requires": {
- "nan": "^2.12.1",
- "node-pre-gyp": "^0.12.0"
- },
- "dependencies": {
- "abbrev": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "ansi-regex": {
- "version": "2.1.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "aproba": {
- "version": "1.2.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "are-we-there-yet": {
- "version": "1.1.5",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "delegates": "^1.0.0",
- "readable-stream": "^2.0.6"
- }
- },
- "balanced-match": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "brace-expansion": {
- "version": "1.1.11",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "chownr": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "code-point-at": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "concat-map": {
- "version": "0.0.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "console-control-strings": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "core-util-is": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "debug": {
- "version": "4.1.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "ms": "^2.1.1"
- }
- },
- "deep-extend": {
- "version": "0.6.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "delegates": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "detect-libc": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "fs-minipass": {
- "version": "1.2.5",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "minipass": "^2.2.1"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "gauge": {
- "version": "2.7.4",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "aproba": "^1.0.3",
- "console-control-strings": "^1.0.0",
- "has-unicode": "^2.0.0",
- "object-assign": "^4.1.0",
- "signal-exit": "^3.0.0",
- "string-width": "^1.0.1",
- "strip-ansi": "^3.0.1",
- "wide-align": "^1.1.0"
- }
- },
- "glob": {
- "version": "7.1.3",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "has-unicode": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "iconv-lite": {
- "version": "0.4.24",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "safer-buffer": ">= 2.1.2 < 3"
- }
- },
- "ignore-walk": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "minimatch": "^3.0.4"
- }
- },
- "inflight": {
- "version": "1.0.6",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.3",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "ini": {
- "version": "1.3.5",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "is-fullwidth-code-point": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "number-is-nan": "^1.0.0"
- }
- },
- "isarray": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "minimatch": {
- "version": "3.0.4",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minimist": {
- "version": "0.0.8",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "minipass": {
- "version": "2.3.5",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "safe-buffer": "^5.1.2",
- "yallist": "^3.0.0"
- }
- },
- "minizlib": {
- "version": "1.2.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "minipass": "^2.2.1"
- }
- },
- "mkdirp": {
- "version": "0.5.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "minimist": "0.0.8"
- }
- },
- "ms": {
- "version": "2.1.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "needle": {
- "version": "2.3.0",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "debug": "^4.1.0",
- "iconv-lite": "^0.4.4",
- "sax": "^1.2.4"
- }
- },
- "node-pre-gyp": {
- "version": "0.12.0",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "detect-libc": "^1.0.2",
- "mkdirp": "^0.5.1",
- "needle": "^2.2.1",
- "nopt": "^4.0.1",
- "npm-packlist": "^1.1.6",
- "npmlog": "^4.0.2",
- "rc": "^1.2.7",
- "rimraf": "^2.6.1",
- "semver": "^5.3.0",
- "tar": "^4"
- }
- },
- "nopt": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "abbrev": "1",
- "osenv": "^0.1.4"
- }
- },
- "npm-bundled": {
- "version": "1.0.6",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "npm-packlist": {
- "version": "1.4.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "ignore-walk": "^3.0.1",
- "npm-bundled": "^1.0.1"
- }
- },
- "npmlog": {
- "version": "4.1.2",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "are-we-there-yet": "~1.1.2",
- "console-control-strings": "~1.1.0",
- "gauge": "~2.7.3",
- "set-blocking": "~2.0.0"
- }
- },
- "number-is-nan": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "object-assign": {
- "version": "4.1.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "once": {
- "version": "1.4.0",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "wrappy": "1"
- }
- },
- "os-homedir": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "os-tmpdir": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "osenv": {
- "version": "0.1.5",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "os-homedir": "^1.0.0",
- "os-tmpdir": "^1.0.0"
- }
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "process-nextick-args": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "rc": {
- "version": "1.2.8",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "deep-extend": "^0.6.0",
- "ini": "~1.3.0",
- "minimist": "^1.2.0",
- "strip-json-comments": "~2.0.1"
- },
- "dependencies": {
- "minimist": {
- "version": "1.2.0",
- "bundled": true,
- "dev": true,
- "optional": true
- }
- }
- },
- "readable-stream": {
- "version": "2.3.6",
- "bundled": true,
- "dev": true,
- "optional": true,
- "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"
- }
- },
- "rimraf": {
- "version": "2.6.3",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "safer-buffer": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "sax": {
- "version": "1.2.4",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "semver": {
- "version": "5.7.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "set-blocking": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "signal-exit": {
- "version": "3.0.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "string-width": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "code-point-at": "^1.0.0",
- "is-fullwidth-code-point": "^1.0.0",
- "strip-ansi": "^3.0.0"
- }
- },
- "string_decoder": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- },
- "strip-ansi": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "ansi-regex": "^2.0.0"
- }
- },
- "strip-json-comments": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "tar": {
- "version": "4.4.8",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "chownr": "^1.1.1",
- "fs-minipass": "^1.2.5",
- "minipass": "^2.3.4",
- "minizlib": "^1.1.1",
- "mkdirp": "^0.5.0",
- "safe-buffer": "^5.1.2",
- "yallist": "^3.0.2"
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "wide-align": {
- "version": "1.1.3",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "string-width": "^1.0.2 || 2"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "yallist": {
- "version": "3.0.3",
- "bundled": true,
- "dev": true,
- "optional": true
- }
- }
- },
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -5581,12 +4784,6 @@
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
"integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g=="
},
- "get-stream": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
- "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
- "dev": true
- },
"get-value": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
@@ -5700,15 +4897,6 @@
}
}
},
- "global-dirs": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz",
- "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=",
- "dev": true,
- "requires": {
- "ini": "^1.3.4"
- }
- },
"globals": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
@@ -5738,25 +4926,6 @@
}
}
},
- "got": {
- "version": "6.7.1",
- "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz",
- "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=",
- "dev": true,
- "requires": {
- "create-error-class": "^3.0.0",
- "duplexer3": "^0.1.4",
- "get-stream": "^3.0.0",
- "is-redirect": "^1.0.0",
- "is-retry-allowed": "^1.0.0",
- "is-stream": "^1.0.0",
- "lowercase-keys": "^1.0.0",
- "safe-buffer": "^5.0.1",
- "timed-out": "^4.0.0",
- "unzip-response": "^2.0.1",
- "url-parse-lax": "^1.0.0"
- }
- },
"graceful-fs": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
@@ -6150,12 +5319,6 @@
"resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
"integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug=="
},
- "ignore-by-default": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
- "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=",
- "dev": true
- },
"immediate": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.2.3.tgz",
@@ -6188,12 +5351,6 @@
}
}
},
- "import-lazy": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
- "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=",
- "dev": true
- },
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -6334,15 +5491,6 @@
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
},
- "is-binary-path": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
- "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
- "dev": true,
- "requires": {
- "binary-extensions": "^1.0.0"
- }
- },
"is-buffer": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
@@ -6353,15 +5501,6 @@
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
"integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA=="
},
- "is-ci": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz",
- "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==",
- "dev": true,
- "requires": {
- "ci-info": "^1.5.0"
- }
- },
"is-data-descriptor": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
@@ -6441,16 +5580,6 @@
"is-extglob": "^2.1.0"
}
},
- "is-installed-globally": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz",
- "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=",
- "dev": true,
- "requires": {
- "global-dirs": "^0.1.0",
- "is-path-inside": "^1.0.0"
- }
- },
"is-nan": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.2.1.tgz",
@@ -6464,12 +5593,6 @@
"resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
"integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI="
},
- "is-npm": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz",
- "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=",
- "dev": true
- },
"is-number": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
@@ -6508,15 +5631,6 @@
"integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=",
"dev": true
},
- "is-path-inside": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
- "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
- "dev": true,
- "requires": {
- "path-is-inside": "^1.0.1"
- }
- },
"is-plain-obj": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
@@ -6537,12 +5651,6 @@
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
"integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
},
- "is-redirect": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
- "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=",
- "dev": true
- },
"is-regex": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
@@ -6564,12 +5672,6 @@
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
"integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg=="
},
- "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==",
- "dev": true
- },
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
@@ -6906,15 +6008,6 @@
"colornames": "^1.1.1"
}
},
- "latest-version": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz",
- "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=",
- "dev": true,
- "requires": {
- "package-json": "^4.0.0"
- }
- },
"lcov-parse": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz",
@@ -7187,12 +6280,6 @@
"signal-exit": "^3.0.0"
}
},
- "lowercase-keys": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
- "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
- "dev": true
- },
"lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
@@ -7898,41 +6985,6 @@
"process-on-spawn": "^1.0.0"
}
},
- "nodemon": {
- "version": "1.19.4",
- "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.4.tgz",
- "integrity": "sha512-VGPaqQBNk193lrJFotBU8nvWZPqEZY2eIzymy2jjY0fJ9qIsxA0sxQ8ATPl0gZC645gijYEc1jtZvpS8QWzJGQ==",
- "dev": true,
- "requires": {
- "chokidar": "^2.1.8",
- "debug": "^3.2.6",
- "ignore-by-default": "^1.0.1",
- "minimatch": "^3.0.4",
- "pstree.remy": "^1.1.7",
- "semver": "^5.7.1",
- "supports-color": "^5.5.0",
- "touch": "^3.1.0",
- "undefsafe": "^2.0.2",
- "update-notifier": "^2.5.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
- "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
- }
- },
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true
- }
- }
- },
"nopt": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
@@ -7952,12 +7004,6 @@
"validate-npm-package-license": "^3.0.1"
}
},
- "normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true
- },
"normalize-url": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
@@ -12004,18 +11050,6 @@
"release-zalgo": "^1.0.0"
}
},
- "package-json": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz",
- "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=",
- "dev": true,
- "requires": {
- "got": "^6.7.1",
- "registry-auth-token": "^3.0.1",
- "registry-url": "^3.0.3",
- "semver": "^5.1.0"
- }
- },
"packet-reader": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
@@ -12399,12 +11433,6 @@
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
},
- "prepend-http": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
- "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
- "dev": true
- },
"prettier": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz",
@@ -12490,12 +11518,6 @@
"integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==",
"dev": true
},
- "pstree.remy": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz",
- "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==",
- "dev": true
- },
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
@@ -12655,49 +11677,6 @@
"util-deprecate": "^1.0.1"
}
},
- "readdirp": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
- "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.11",
- "micromatch": "^3.1.10",
- "readable-stream": "^2.0.2"
- },
- "dependencies": {
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "dev": true,
- "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"
- }
- },
- "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==",
- "dev": true
- },
- "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==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- }
- }
- },
"redent": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz",
@@ -12744,25 +11723,6 @@
"integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
"dev": true
},
- "registry-auth-token": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz",
- "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==",
- "dev": true,
- "requires": {
- "rc": "^1.1.6",
- "safe-buffer": "^5.0.1"
- }
- },
- "registry-url": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
- "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
- "dev": true,
- "requires": {
- "rc": "^1.0.1"
- }
- },
"reinterval": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz",
@@ -13476,15 +12436,6 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8="
},
- "semver-diff": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz",
- "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=",
- "dev": true,
- "requires": {
- "semver": "^5.0.3"
- }
- },
"semver-regex": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz",
@@ -14434,15 +13385,6 @@
}
}
},
- "term-size": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz",
- "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=",
- "dev": true,
- "requires": {
- "execa": "^0.7.0"
- }
- },
"test-exclude": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
@@ -14521,12 +13463,6 @@
"xtend": "~4.0.0"
}
},
- "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=",
- "dev": true
- },
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -14777,32 +13713,6 @@
"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
"integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo="
},
- "undefsafe": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz",
- "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=",
- "dev": true,
- "requires": {
- "debug": "^2.2.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
- "dev": true
- }
- }
- },
"underscore": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz",
@@ -14902,36 +13812,6 @@
}
}
},
- "unzip-response": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
- "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=",
- "dev": true
- },
- "upath": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
- "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
- "dev": true
- },
- "update-notifier": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz",
- "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==",
- "dev": true,
- "requires": {
- "boxen": "^1.2.1",
- "chalk": "^2.0.1",
- "configstore": "^3.0.0",
- "import-lazy": "^2.1.0",
- "is-ci": "^1.0.10",
- "is-installed-globally": "^0.1.0",
- "is-npm": "^1.0.0",
- "latest-version": "^3.0.0",
- "semver-diff": "^2.0.0",
- "xdg-basedir": "^3.0.0"
- }
- },
"uri-js": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
@@ -14953,15 +13833,6 @@
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
"dev": true
},
- "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=",
- "dev": true,
- "requires": {
- "prepend-http": "^1.0.1"
- }
- },
"use": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
@@ -15141,42 +14012,6 @@
}
}
},
- "widest-line": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz",
- "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==",
- "dev": true,
- "requires": {
- "string-width": "^2.1.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
- "dev": true
- },
- "string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "requires": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
- }
- },
- "strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "dev": true,
- "requires": {
- "ansi-regex": "^3.0.0"
- }
- }
- }
- },
"wif": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
@@ -15333,17 +14168,6 @@
"mkdirp": "^0.5.1"
}
},
- "write-file-atomic": {
- "version": "2.4.3",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
- "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.11",
- "imurmurhash": "^0.1.4",
- "signal-exit": "^3.0.2"
- }
- },
"ws": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.2.0.tgz",
@@ -15357,12 +14181,6 @@
"resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.3.0.tgz",
"integrity": "sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg=="
},
- "xdg-basedir": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz",
- "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=",
- "dev": true
- },
"xmlhttprequest-ssl": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
diff --git a/package.json b/package.json
index f1493d8..b566ce2 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,6 @@
"fs-extra": "^8.0.1",
"nock": "^11.1.0",
"node-mocks-http": "^1.7.0",
- "nodemon": "^1.18.1",
"nyc": "^15.0.0",
"prettier": "^1.18.2",
"proxyquire": "^2.1.0",