Compare commits

..
79 Commits
Author SHA1 Message Date
Chris Troutner fbac18d456 Merge pull request #137 from Permissionless-Software-Foundation/ct-unstable
More connection reset debugging
2021-03-26 17:32:23 -08:00
Chris Troutner 62ae67ceab Logging axios options in decodeOpReturn 2021-03-26 18:29:48 -07:00
Chris Troutner 8e64d854cf fix(hydrateUtxos): Adding debugging info for axiosOptions 2021-03-26 18:26:18 -07:00
Chris Troutner 5fe8e515ff Merge pull request #136 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Adding debugging information
2021-03-26 16:30:50 -08:00
Chris Troutner f11297339b fix(decodeOpReturn): Adding debugging information 2021-03-26 17:27:57 -07:00
Chris Troutner 61d52c8ebe Merge pull request #135 from Permissionless-Software-Foundation/ct-unstable
fix(debugging): Adding additional debugging info to SLP utils
2021-03-26 12:53:35 -08:00
Chris Troutner d89bbe0bf6 fix(debugging): Adding additional debugging info to SLP utils 2021-03-26 13:51:29 -07:00
Chris Troutner 2a1c2500e6 Merge pull request #134 from Permissionless-Software-Foundation/ct-unstable
fix(slp): Adding more verbose error messages for SLP utility functions
2021-03-26 12:16:55 -08:00
Chris Troutner 8879a5170a fix(slp): Adding more verbose error messages for SLP utility functions 2021-03-26 13:11:40 -07:00
Chris Troutner b29cb7c12b Merge pull request #133 from Permissionless-Software-Foundation/ct-unstable
fix(integration tests): slowing down integration tests for the sake o…
2021-03-26 08:28:46 -07:00
Chris Troutner 69fa10d3a6 fix(integration tests): slowing down integration tests for the sake of rate limits 2021-03-26 08:25:39 -07:00
Chris Troutner d16431d165 Merge pull request #132 from Permissionless-Software-Foundation/ct-unstable
Adding Transaction.get()
2021-03-24 07:30:48 -07:00
Chris Troutner faa2972460 fix(Transaction.get()): Added documentation 2021-03-24 07:28:38 -07:00
Chris Troutner 5d3ea2b559 fix(Transaction.get()): Added unit tests 2021-03-24 07:24:08 -07:00
Chris Troutner 40fa6440f4 feat(Transactions.get()): Added tx hydration method 2021-03-23 18:49:27 -07:00
Chris Troutner ce951afddb fix(RawTransactions.getTxData): Adding BCH value to tx inputs 2021-03-23 17:37:00 -07:00
Chris Troutner d2e847d3fb feat(transactions): Created transaction library 2021-03-23 17:11:37 -07:00
Chris Troutner fe697455c0 Merge branch 'master' into ct-unstable 2021-03-09 08:09:01 -08:00
Chris Troutner 25832d52fd fix(raw-transactions): Adding proper axios header for Basic Auth 2021-03-09 08:04:14 -08:00
Chris Troutner 9d0840c2fe Merge pull request #131 from Permissionless-Software-Foundation/ct-unstable
fix(tokenUtxoDetailsWL): Adding usrObj input variable
2021-03-08 17:37:31 -08:00
Chris Troutner 74dc3e7e1d Merge branch 'master' into ct-unstable 2021-03-08 17:33:25 -08:00
Chris Troutner 171786a470 fix(tokenUtxoDetailsWL): Adding usrObj input variable 2021-03-08 17:32:33 -08:00
Chris Troutner 5cbd685060 Merge pull request #130 from Permissionless-Software-Foundation/dh-bch-price
feat(price): Created getBchUsd() for bch-js
2021-03-05 07:51:32 -08:00
Daniel Gonzalez ef05aff7a3 feat(price): Created getBchUsd() for bch-js 2021-03-04 15:14:46 -04:00
Chris Troutner 3f01fdba7c Merge pull request #129 from Permissionless-Software-Foundation/ct-unstable
fix(hydrateUtxos): Stringifying bch-api object when passing error
2021-03-02 07:49:14 -08:00
Chris Troutner 232747280e Merge branch 'master' into ct-unstable 2021-03-02 07:47:03 -08:00
Chris Troutner e96da1615b fix(hydrateUtxos): Stringifying bch-api object when passing error 2021-03-02 07:46:51 -08:00
Chris Troutner 9538501f01 Merge pull request #128 from Permissionless-Software-Foundation/ct-unstable
fix(hydrateUtxos): Adding better error handler
2021-03-02 07:31:43 -08:00
Chris Troutner 0a4fee5716 fix(hydrateUtxos): Adding better error handler 2021-03-02 07:29:41 -08:00
Chris Troutner cec79be4fa Merge pull request #127 from Permissionless-Software-Foundation/ct-unstable
fix(hydrateUtxos): Adding usrObj input for delaying UTXO processing
2021-03-01 08:21:23 -08:00
Chris Troutner c839f0b891 fix(integration tests): Fixing broken ABC integration test 2021-03-01 08:19:16 -08:00
Chris Troutner 24d629ebe1 fix(hydrateUtxos): Adding usrObj input for delaying UTXO processing 2021-03-01 07:48:08 -08:00
Chris Troutner f729918385 fix(_hydrateUtxo): Adding user-configurable artifical delay 2021-03-01 06:55:35 -08:00
Chris Troutner b7ab02c0ed Merge pull request #126 from Permissionless-Software-Foundation/ct-unstable
fix(docs): Updating docs and commenting out debug logs
2021-02-27 15:40:58 -08:00
Chris Troutner 1c291880e0 fix(docs): Updating docs and commenting out debug logs 2021-02-27 15:38:24 -08:00
Chris Troutner 09b79c4d3e Merge pull request #125 from Permissionless-Software-Foundation/ct-unstable
Adding unit tests for 429 and 503 errors
2021-02-27 14:56:14 -08:00
Chris Troutner 828f6a1b1c fix(_hydrateUtxo): Added unit tests 2021-02-27 14:53:54 -08:00
Chris Troutner 1b8727da55 fix(decodeOpReturn): Adding test cases for 429 and 503 errors 2021-02-27 13:28:53 -08:00
Chris Troutner f84862d875 Merge pull request #124 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Added NFT child test case
2021-02-27 13:12:30 -08:00
Chris Troutner 179d924899 Adding respond.data in error 2021-02-27 13:10:33 -08:00
Chris Troutner 676fb85abf fix(decodeOpReturn): Added NFT child test case 2021-02-27 12:58:40 -08:00
Chris Troutner d59c1fe445 Merge pull request #123 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Trying different error configuration
2021-02-27 10:03:58 -08:00
Chris Troutner 0a34611557 fix(decodeOpReturn): Trying different error configuration 2021-02-27 10:02:12 -08:00
Chris Troutner c13b029e99 Merge pull request #122 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Replacing error message with better one
2021-02-27 09:47:20 -08:00
Chris Troutner b038e9a7fd fix(decodeOpReturn): Replacing error message with better one 2021-02-27 09:45:24 -08:00
Chris Troutner 7b728fb45d Merge pull request #121 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Adding additional debugging for errors
2021-02-27 09:33:00 -08:00
Chris Troutner d4dbce8df0 fix(decodeOpReturn): Adding additional debugging for errors 2021-02-27 09:31:16 -08:00
Chris Troutner 2419aeceaa Merge pull request #120 from Permissionless-Software-Foundation/ct-unstable
fix(_hydrateUtxo): Adding more debugging
2021-02-27 09:09:58 -08:00
Chris Troutner 158b009069 fix(_hydrateUtxo): Adding more debugging 2021-02-27 09:07:50 -08:00
Chris Troutner f3c3250a69 Merge pull request #119 from Permissionless-Software-Foundation/ct-unstable
fix(_hydrateUtxo): Debugging error handling
2021-02-27 09:00:20 -08:00
Chris Troutner 5ae4db88c3 Merge branch 'master' into ct-unstable 2021-02-27 08:58:23 -08:00
Chris Troutner 33e161df26 fix(_hydrateUtxo): Debugging error handling 2021-02-27 08:58:12 -08:00
Chris Troutner 81c910361c Merge pull request #118 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Debugging error handling by decodeOpReturn()
2021-02-27 08:41:57 -08:00
Chris Troutner 9751a39538 Merge branch 'master' into ct-unstable 2021-02-27 08:38:38 -08:00
Chris Troutner 7058f77ee9 fix(decodeOpReturn): Debugging error handling by decodeOpReturn() 2021-02-27 08:37:29 -08:00
Chris Troutner ad580d67a4 Adding decatur test script 2021-02-27 08:23:07 -08:00
Chris Troutner acc0300a44 Merge pull request #117 from Permissionless-Software-Foundation/ct-unstable
fix(bip32-utils): Bumping to v1.0.0 with updated keccak
2021-02-24 18:56:39 -08:00
Chris Troutner 4e1b806230 fix(bip32-utils): Bumping to v1.0.0 with updated keccak 2021-02-24 18:53:20 -08:00
Chris Troutner 357e350176 Merge pull request #116 from Permissionless-Software-Foundation/ct-unstable
fix(electrumx): Adding usrObj to Electrumx.Transactions()
2021-02-24 17:59:35 -08:00
Chris Troutner f6140acc76 fix(electrumx): Adding usrObj to Electrumx.Transactions() 2021-02-24 17:53:53 -08:00
Chris Troutner df65b12aab Merge pull request #115 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): replacing ip with usrObj
2021-02-24 16:44:58 -08:00
Chris Troutner 754b4cd807 fix(decodeOpReturn): replacing ip with usrObj 2021-02-24 16:42:54 -08:00
Chris Troutner 3c6079e54c Merge pull request #114 from Permissionless-Software-Foundation/ct-unstable
fix(usrObj): Fixing typo of usbObj to usrObj
2021-02-24 16:37:09 -08:00
Chris Troutner 18621cd76c fix(usrObj): Fixing typo of usbObj to usrObj 2021-02-24 16:35:09 -08:00
Chris Troutner 456159a4cc Merge pull request #113 from Permissionless-Software-Foundation/ct-unstable
fix(usbObj): Passing a usrObj when bch-api calls bch-js
2021-02-24 16:29:54 -08:00
Chris Troutner 33e723befe fix(usbObj): Passing a usrObj when bch-api calls bch-js 2021-02-24 16:27:49 -08:00
Chris Troutner 30fdee1920 Merge pull request #112 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Switching to POST from GET to getRawTx call
2021-02-24 15:14:51 -08:00
Chris Troutner feb336c331 fix(decodeOpReturn): Switching to POST from GET to getRawTx call 2021-02-24 15:11:58 -08:00
Chris Troutner 8bacc0a991 Merge pull request #111 from Permissionless-Software-Foundation/ct-unstable
fix(ip): Renaming origin to ip
2021-02-24 14:10:07 -08:00
Chris Troutner d22f1ec8a6 fix(ip): Renaming origin to ip 2021-02-24 14:05:25 -08:00
Chris Troutner 7eb3a796b8 Merge pull request #110 from Permissionless-Software-Foundation/ct-unstable
fix(origin): Testing idea around passing origin when bch-api calls bc…
2021-02-24 13:29:05 -08:00
Chris Troutner 9919f811b0 fix(origin): Testing idea around passing origin when bch-api calls bch-js 2021-02-24 13:26:08 -08:00
Chris Troutner e7854481a0 Merge pull request #109 from Permissionless-Software-Foundation/ct-unstable
fix(dependencies): Removing several unused dependencies
2021-02-23 10:29:22 -08:00
Chris Troutner 0b406c467e fix(dependencies): Removing more unnecessary dependencies 2021-02-23 10:26:12 -08:00
Chris Troutner e41217b710 fix(dependencies): Removing several unused dependencies 2021-02-23 09:04:49 -08:00
Chris Troutner c22ce8d57d fix(dependencies): Ran npm audit with 0 vulns 2021-02-23 08:46:27 -08:00
Chris Troutner bf3612583e Merge pull request #108 from Permissionless-Software-Foundation/ct-unstable
Sleep: Adding a Promise-based wait function to Util lib
2021-02-15 15:28:26 -08:00
Chris Troutner ef56452ec9 feat(sleep): Adding sleep function to Util lib 2021-02-15 15:16:30 -08:00
Chris Troutner b3be470c0e fix(utxo.get()): Fixing ABC integration test 2021-02-15 15:12:39 -08:00
24 changed files with 1411 additions and 847 deletions
+36 -556
View File
@@ -478,11 +478,11 @@
}
},
"@psf/bip32-utils": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/@psf/bip32-utils/-/bip32-utils-0.13.1.tgz",
"integrity": "sha512-5yM2o4TXW3gWKI3zxUFj9eeYqMYbA4Q1w+ptcfb+XnGpSZLrmwGtX48q8rApIKtikRceMEFXp1Jq6ed+bS+1nA==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@psf/bip32-utils/-/bip32-utils-1.0.0.tgz",
"integrity": "sha512-cWE+uZsGyS2PsE5+bplNq7w/oE3/wGGP0pZV9TiSNMIQvJguxfu7Ruk2FuzROcaVysBclDaL70A9N3sAnworGA==",
"requires": {
"keccak": "^1.3.0",
"keccak": "^3.0.1",
"nyc": "*",
"standard": "^11.0.1",
"tape": "*"
@@ -1104,11 +1104,6 @@
"through": ">=2.2.7 <3"
}
},
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"abortcontroller-polyfill": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.1.tgz",
@@ -1118,6 +1113,7 @@
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
"dev": true,
"requires": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
@@ -1143,11 +1139,6 @@
}
}
},
"after": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
"integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
},
"agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@@ -1352,11 +1343,6 @@
"function-bind": "^1.1.1"
}
},
"arraybuffer.slice": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
},
"arrify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
@@ -1376,6 +1362,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz",
"integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==",
"dev": true,
"requires": {
"es6-object-assign": "^1.1.0",
"is-nan": "^1.2.1",
@@ -1499,11 +1486,6 @@
}
}
},
"backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -1517,21 +1499,6 @@
"safe-buffer": "^5.0.1"
}
},
"base64-arraybuffer": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
"integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI="
},
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
},
"base64id": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
},
"bc-bip68": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/bc-bip68/-/bc-bip68-1.0.5.tgz",
@@ -1651,11 +1618,6 @@
"varuint-bitcoin": "^1.0.1"
}
},
"blob": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
"integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig=="
},
"bn.js": {
"version": "4.11.9",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
@@ -1727,39 +1689,11 @@
"safe-buffer": "^5.1.2"
}
},
"buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.1.13"
}
},
"buffer-alloc": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
"integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
"requires": {
"buffer-alloc-unsafe": "^1.1.0",
"buffer-fill": "^1.0.0"
}
},
"buffer-alloc-unsafe": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="
},
"buffer-equals": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/buffer-equals/-/buffer-equals-1.0.4.tgz",
"integrity": "sha1-A1O1T9B/2VZBcGca5vZrnPENJ/U="
},
"buffer-fill": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
"integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw="
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
@@ -1923,11 +1857,6 @@
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="
},
"clear": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/clear/-/clear-0.1.0.tgz",
"integrity": "sha512-qMjRnoL+JDPJHeLePZJuao6+8orzHMGP04A8CdwCNsKhRbOnKRjefxONR7bwILT3MHecxKBjHkKL/tkZ8r4Uzw=="
},
"cli-cursor": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
@@ -2033,11 +1962,6 @@
"delayed-stream": "~1.0.0"
}
},
"commander": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz",
"integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow=="
},
"commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -2059,21 +1983,6 @@
"integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==",
"dev": true
},
"component-bind": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
"integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
},
"component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
},
"component-inherit": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
"integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -2163,11 +2072,6 @@
}
}
},
"cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@@ -2219,17 +2123,6 @@
"request": "^2.88.2"
}
},
"cp-file": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz",
"integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==",
"requires": {
"graceful-fs": "^4.1.2",
"make-dir": "^3.0.0",
"nested-error-stacks": "^2.0.0",
"p-event": "^4.1.0"
}
},
"create-hash": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
@@ -2466,11 +2359,6 @@
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
"dev": true
},
"dijkstrajs": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.1.tgz",
"integrity": "sha1-082BIh4+pAdCz83lVtTpnpjdxxs="
},
"dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -2585,74 +2473,6 @@
"once": "^1.4.0"
}
},
"engine.io": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz",
"integrity": "sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==",
"requires": {
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.4.1",
"debug": "~4.1.0",
"engine.io-parser": "~2.2.0",
"ws": "~7.4.2"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
}
}
},
"engine.io-client": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.0.tgz",
"integrity": "sha512-12wPRfMrugVw/DNyJk34GQ5vIVArEcVMXWugQGGuw2XxUSztFNmJggZmv8IZlLyEdnpO1QB9LkcjeWewO2vxtA==",
"requires": {
"component-emitter": "~1.3.0",
"component-inherit": "0.0.3",
"debug": "~3.1.0",
"engine.io-parser": "~2.2.0",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"parseqs": "0.0.6",
"parseuri": "0.0.6",
"ws": "~7.4.2",
"xmlhttprequest-ssl": "~1.5.4",
"yeast": "0.1.2"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"engine.io-parser": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz",
"integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==",
"requires": {
"after": "0.8.2",
"arraybuffer.slice": "~0.0.7",
"base64-arraybuffer": "0.1.4",
"blob": "0.0.5",
"has-binary2": "~1.0.2"
}
},
"enquirer": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
@@ -2804,7 +2624,8 @@
"es6-object-assign": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz",
"integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw="
"integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=",
"dev": true
},
"escalade": {
"version": "3.1.1",
@@ -3586,11 +3407,6 @@
"integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg==",
"dev": true
},
"figlet": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.0.tgz",
"integrity": "sha512-ZQJM4aifMpz6H19AW1VqvZ7l4pOE9p7i/3LyxgO2kp+PO/VcDYNqIHEMtkccqIhTXMKci4kjueJr/iCQEaT/Ww=="
},
"figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
@@ -3850,11 +3666,6 @@
"assert-plus": "^1.0.0"
}
},
"git-clone": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/git-clone/-/git-clone-0.1.0.tgz",
"integrity": "sha1-DXYWN3gJOu9/HDAjjyqe8/B6Lrk="
},
"git-log-parser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz",
@@ -4042,26 +3853,6 @@
}
}
},
"has-binary2": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
"integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
"requires": {
"isarray": "2.0.1"
},
"dependencies": {
"isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
}
}
},
"has-cors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
"integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk="
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@@ -4305,11 +4096,6 @@
"safer-buffer": ">= 2.1.2 < 3"
}
},
"ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
},
"ignore": {
"version": "3.3.10",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
@@ -4352,11 +4138,6 @@
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="
},
"indexof": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
"integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -4511,7 +4292,8 @@
"is-generator-function": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.8.tgz",
"integrity": "sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ=="
"integrity": "sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ==",
"dev": true
},
"is-glob": {
"version": "4.0.1",
@@ -4531,6 +4313,7 @@
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz",
"integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==",
"dev": true,
"requires": {
"call-bind": "^1.0.0",
"define-properties": "^1.1.3"
@@ -4911,14 +4694,12 @@
"dev": true
},
"keccak": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/keccak/-/keccak-1.4.0.tgz",
"integrity": "sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz",
"integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==",
"requires": {
"bindings": "^1.2.1",
"inherits": "^2.0.3",
"nan": "^2.2.1",
"safe-buffer": "^5.1.0"
"node-addon-api": "^2.0.0",
"node-gyp-build": "^4.2.0"
}
},
"kind-of": {
@@ -5092,7 +4873,8 @@
"lodash.toarray": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
"integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE="
"integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=",
"dev": true
},
"lodash.uniqby": {
"version": "4.5.0",
@@ -5507,7 +5289,8 @@
"mime-db": {
"version": "1.45.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz",
"integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w=="
"integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==",
"dev": true
},
"mime-match": {
"version": "1.0.2",
@@ -5521,6 +5304,7 @@
"version": "2.1.28",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz",
"integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==",
"dev": true,
"requires": {
"mime-db": "1.45.0"
}
@@ -5845,7 +5629,8 @@
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
"dev": true
},
"neo-async": {
"version": "2.6.2",
@@ -5862,7 +5647,8 @@
"nested-error-stacks": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz",
"integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug=="
"integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==",
"dev": true
},
"nice-try": {
"version": "1.0.5",
@@ -5894,15 +5680,16 @@
}
}
},
"node-cmd": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/node-cmd/-/node-cmd-3.0.0.tgz",
"integrity": "sha1-OP/3CkqqT2WdID61eGJzcBjiT28="
"node-addon-api": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
"integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA=="
},
"node-emoji": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
"integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==",
"dev": true,
"requires": {
"lodash.toarray": "^4.4.0"
}
@@ -5931,6 +5718,11 @@
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
"dev": true
},
"node-gyp-build": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz",
"integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg=="
},
"node-mocks-http": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/node-mocks-http/-/node-mocks-http-1.10.1.tgz",
@@ -5956,14 +5748,6 @@
"process-on-spawn": "^1.0.0"
}
},
"nopt": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
"integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
"requires": {
"abbrev": "1"
}
},
"normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@@ -10185,14 +9969,6 @@
"integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==",
"dev": true
},
"p-event": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz",
"integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==",
"requires": {
"p-timeout": "^3.1.0"
}
},
"p-filter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz",
@@ -10210,11 +9986,6 @@
}
}
},
"p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
},
"p-is-promise": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz",
@@ -10269,14 +10040,6 @@
}
}
},
"p-timeout": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
"integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
"requires": {
"p-finally": "^1.0.0"
}
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@@ -10318,16 +10081,6 @@
"error-ex": "^1.2.0"
}
},
"parseqs": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
"integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w=="
},
"parseuri": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
"integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow=="
},
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -10535,11 +10288,6 @@
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
"integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow=="
},
"pngjs": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
"integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w=="
},
"preact": {
"version": "8.2.9",
"resolved": "https://registry.npmjs.org/preact/-/preact-8.2.9.tgz",
@@ -10635,136 +10383,6 @@
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
"dev": true
},
"qrcode": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.4.4.tgz",
"integrity": "sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q==",
"requires": {
"buffer": "^5.4.3",
"buffer-alloc": "^1.2.0",
"buffer-from": "^1.1.1",
"dijkstrajs": "^1.0.1",
"isarray": "^2.0.1",
"pngjs": "^3.3.0",
"yargs": "^13.2.4"
},
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"requires": {
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
"wrap-ansi": "^5.1.0"
}
},
"emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"requires": {
"locate-path": "^3.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",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
},
"isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"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==",
"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="
},
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"requires": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
}
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"requires": {
"ansi-regex": "^4.1.0"
}
},
"wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"requires": {
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
"strip-ansi": "^5.0.0"
}
},
"yargs": {
"version": "13.3.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
"integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
"requires": {
"cliui": "^5.0.0",
"find-up": "^3.0.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",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^13.1.2"
}
},
"yargs-parser": {
"version": "13.1.2",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
},
"qs": {
"version": "6.9.6",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz",
@@ -10963,11 +10581,6 @@
"es6-error": "^4.0.1"
}
},
"repl.history": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/repl.history/-/repl.history-0.1.4.tgz",
"integrity": "sha1-gDZxcfN4HW5CmccXWMJTCX9dWDI="
},
"request": {
"version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
@@ -11511,112 +11124,6 @@
"bignumber.js": "^9.0.0"
}
},
"socket.io": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.4.1.tgz",
"integrity": "sha512-Si18v0mMXGAqLqCVpTxBa8MGqriHGQh8ccEOhmsmNS3thNCGBwO8WGrwMibANsWtQQ5NStdZwHqZR3naJVFc3w==",
"requires": {
"debug": "~4.1.0",
"engine.io": "~3.5.0",
"has-binary2": "~1.0.2",
"socket.io-adapter": "~1.1.0",
"socket.io-client": "2.4.0",
"socket.io-parser": "~3.4.0"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
}
}
},
"socket.io-adapter": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
"integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g=="
},
"socket.io-client": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz",
"integrity": "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==",
"requires": {
"backo2": "1.0.2",
"component-bind": "1.0.0",
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
"engine.io-client": "~3.5.0",
"has-binary2": "~1.0.2",
"indexof": "0.0.1",
"parseqs": "0.0.6",
"parseuri": "0.0.6",
"socket.io-parser": "~3.3.0",
"to-array": "0.1.4"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"socket.io-parser": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz",
"integrity": "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==",
"requires": {
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
"isarray": "2.0.1"
}
}
}
},
"socket.io-parser": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz",
"integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==",
"requires": {
"component-emitter": "1.2.1",
"debug": "~4.1.0",
"isarray": "2.0.1"
},
"dependencies": {
"component-emitter": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
},
"isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
}
}
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -12704,11 +12211,6 @@
"os-tmpdir": "~1.0.2"
}
},
"to-array": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
"integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA="
},
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -12723,14 +12225,6 @@
"is-number": "^7.0.0"
}
},
"touch": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
"integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
"requires": {
"nopt": "~1.0.10"
}
},
"tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
@@ -12949,6 +12443,7 @@
"version": "0.12.3",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.3.tgz",
"integrity": "sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog==",
"dev": true,
"requires": {
"inherits": "^2.0.3",
"is-arguments": "^1.0.4",
@@ -13221,22 +12716,12 @@
"typedarray-to-buffer": "^3.1.5"
}
},
"ws": {
"version": "7.4.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.3.tgz",
"integrity": "sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA=="
},
"xdg-basedir": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
"integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
"dev": true
},
"xmlhttprequest-ssl": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
"integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4="
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
@@ -13420,11 +12905,6 @@
}
}
},
"yeast": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
"integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
},
"yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+9 -21
View File
@@ -16,8 +16,12 @@
"test:integration:local:abc": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
"test:integration:local:bchn": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
"test:integration:local:testnet": "RESTURL=http://localhost:4000/v4/ mocha --timeout 30000 test/integration/chains/testnet",
"test:temp": "export RESTURL=https://bchn.fullstack.cash/v4/ && mocha --timeout 30000 -g '#UTXO' test/integration/chains/bchn/",
"test:temp2": "mocha --timeout=30000 -g '#Util' test/unit/",
"test:integration:decatur:bchn": "export RESTURL=http://192.168.0.36:3000/v4/ && mocha --timeout 30000 test/integration/",
"test:integration:temp:bchn": "export RESTURL=http://157.90.174.219:3000/v4/ && mocha --timeout 30000 test/integration/",
"test:temp": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 -g '#Encryption' test/integration/",
"test:temp2": "mocha --timeout=30000 -g '#TransactionLib' test/unit/",
"test:temp3": "export RESTURL=https://bchn.fullstack.cash/v4/ && mocha --timeout 30000 -g '#Transaction' test/integration/",
"test:temp4": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 -g '#decodeOpReturn' test/integration/",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"coverage:report": "nyc --reporter=html mocha --timeout 25000 test/unit/",
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
@@ -31,13 +35,12 @@
},
"dependencies": {
"@psf/bip21": "^2.0.1",
"@psf/bip32-utils": "^0.13.1",
"@psf/bip32-utils": "^1.0.0",
"@psf/bitcoincash-ops": "^2.0.0",
"@psf/bitcoincashjs-lib": "^4.0.2",
"@psf/coininfo": "^4.0.0",
"@uppy/core": "^1.10.4",
"@uppy/tus": "^1.5.12",
"assert": "^2.0.0",
"axios": "^0.21.1",
"bc-bip68": "^1.0.5",
"bchaddrjs-slp": "^0.2.5",
@@ -49,33 +52,18 @@
"bip66": "^1.1.5",
"bitcoinjs-message": "^2.0.0",
"bs58": "^4.0.1",
"buffer": "^5.1.0",
"cashaddrjs": "^0.3.3",
"chalk": "^2.3.0",
"clear": "0.1.0",
"commander": "^3.0.0",
"cp-file": "^7.0.0",
"ecurve": "^1.0.6",
"figlet": "^1.2.0",
"git-clone": "^0.1.0",
"ini": "^1.3.8",
"mkdirp": "^0.5.1",
"node-cmd": "^3.0.0",
"node-emoji": "^1.8.1",
"qrcode": "^1.4.1",
"randombytes": "^2.0.6",
"repl.history": "^0.1.4",
"safe-buffer": "^5.1.2",
"satoshi-bitcoin": "^1.0.4",
"slp-mdm": "0.0.6",
"slp-parser": "0.0.4",
"socket.io": "^2.1.1",
"socket.io-client": "^2.1.1",
"touch": "^3.1.0",
"wif": "^2.0.6"
},
"devDependencies": {
"apidoc": "^0.17.7",
"assert": "^2.0.0",
"chai": "^4.1.2",
"coveralls": "^3.0.2",
"eslint": "5.16.0",
@@ -90,7 +78,7 @@
"node-mocks-http": "^1.7.0",
"nyc": "^14.1.0",
"prettier": "^1.18.2",
"semantic-release": "^17.3.1",
"semantic-release": "^17.3.9",
"sinon": "^7.3.2",
"standard": "^16.0.3"
},
+2 -2
View File
@@ -26,12 +26,12 @@ const TransactionBuilder = require('./transaction-builder')
const ECPair = require('./ecpair')
const Script = require('./script')
const Price = require('./price')
const Socket = require('./socket')
const Schnorr = require('./schnorr')
const SLP = require('./slp/slp')
const IPFS = require('./ipfs')
const Encryption = require('./encryption')
const Utxo = require('./utxo')
const Transaction = require('./transaction')
// Indexers
const Ninsight = require('./ninsight')
@@ -107,7 +107,6 @@ class BCHJS {
this.TransactionBuilder = TransactionBuilder
this.TransactionBuilder.setAddress(this.Address)
this.Util = new Util(libConfig)
this.Socket = Socket
this.Schnorr = new Schnorr(libConfig)
this.SLP = new SLP(libConfig)
@@ -115,6 +114,7 @@ class BCHJS {
this.IPFS = new IPFS()
this.Utxo = new Utxo(libConfig)
this.Transaction = new Transaction(libConfig)
}
}
+3 -2
View File
@@ -284,7 +284,7 @@ class ElectrumX {
* }
*
*/
async transactions (address) {
async transactions (address, usrObj = null) {
try {
// Handle single address.
if (typeof address === 'string') {
@@ -299,7 +299,8 @@ class ElectrumX {
const response = await axios.post(
`${this.restURL}electrumx/transactions`,
{
addresses: address
addresses: address,
usrObj // pass user data when making an internal call.
},
_this.axiosOptions
)
+35
View File
@@ -156,6 +156,41 @@ class Price {
else throw err
}
}
/**
* @api price.getBchUsd() getBchUsd()
* @apiName Price getBchUsd()
* @apiGroup Price
* @apiDescription Return current price of BCH in USD.
* This endpoint gets the USD price of BCH from the Coinex API. The price
* comes from bch-api, so it has a better chance of working in Tor.
*
* @apiExample Example usage:
*(async () => {
* try {
* let current = await bchjs.Price.getBchUsd();
* console.log(current);
* } catch(err) {
* console.err(err)
* }
*})()
*
* // 512.81
*/
async getBchUsd () {
try {
const response = await this.axios.get(
`${this.restURL}price/bchusd`,
_this.axiosOptions
)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
return response.data.usd
} catch (err) {
if (err.response && err.response.data) throw err.response.data
else throw err
}
}
}
module.exports = Price
+8 -92
View File
@@ -1,7 +1,5 @@
const axios = require('axios')
const SlpUtils = require('./slp/utils')
let _this
class RawTransactions {
@@ -29,9 +27,6 @@ class RawTransactions {
// Encapsulate dependencies
this.axios = axios
// Dependencies
this.slpUtils = new SlpUtils(config)
_this = this
}
@@ -116,9 +111,7 @@ class RawTransactions {
data: {
hexes: hex
},
headers: {
authorization: `Token ${_this.apiToken}`
}
headers: _this.axiosOptions.headers
}
const response = await axios(options)
@@ -183,9 +176,7 @@ class RawTransactions {
data: {
hexes: script
},
headers: {
authorization: `Token ${this.apiToken}`
}
headers: _this.axiosOptions.headers
}
const response = await axios(options)
@@ -263,7 +254,7 @@ class RawTransactions {
* // time: 1547752564,
* // blocktime: 1547752564 } ]
*/
async getRawTransaction (txid, verbose = false) {
async getRawTransaction (txid, verbose = false, usrObj = null) {
try {
if (typeof txid === 'string') {
const response = await axios.get(
@@ -278,7 +269,8 @@ class RawTransactions {
url: `${this.restURL}rawtransactions/getRawTransaction`,
data: {
txids: txid,
verbose: verbose
verbose: verbose,
usrObj // pass user data when making an internal call.
},
headers: _this.axiosOptions.headers
}
@@ -327,7 +319,8 @@ class RawTransactions {
retArray.push({
vin: i,
address: voutSender.scriptPubKey.addresses[0]
address: voutSender.scriptPubKey.addresses[0],
value: voutSender.value
})
}
@@ -381,84 +374,7 @@ class RawTransactions {
// Add the input address to the transaction data.
for (let i = 0; i < inAddrs.length; i++) {
txDetails.vin[i].address = inAddrs[i].address
}
return txDetails
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
// Wraps getTxData(), but also appends SLP token information to each input
// and output of the transaction. This is a very API-heavy call.
// Returns false if the txid is not an SLP transaction.
//
// Warning! This is a prototype function and the output can change at any time
// without reflecting a change in the semantic version. DO NOT USE IN PRODUCTION.
async getTxDataSlp (txid) {
try {
if (typeof txid !== 'string') {
throw new Error('Input must be a string or array of strings.')
}
const txDetails = await this.getTxData(txid)
// First get the token information for the output. If that fails, then
// this is not an SLP transaction, and this method can return false.
let outTokenData
try {
outTokenData = await this.slpUtils.decodeOpReturn(txid)
// console.log(`outTokenData: ${JSON.stringify(outTokenData, null, 2)}`)
// Add token information to the tx details object.
txDetails.tokenTxType = outTokenData.txType
txDetails.tokenId = outTokenData.tokenId
// Add the token quantity to each output.
for (let i = 0; i < outTokenData.amounts.length; i++) {
txDetails.vout[i + 1].tokenQty = outTokenData.amounts[i]
}
// Loop through each input and retrieve the token data.
for (let i = 0; i < txDetails.vin.length; i++) {
const thisVin = txDetails.vin[i]
try {
// If decodeOpReturn() throws an error, then this input is not
// from an SLP transaction and can be ignored.
const inTokenData = await this.slpUtils.decodeOpReturn(thisVin.txid)
// console.log(
// `vin[${i}] tokenData: ${JSON.stringify(inTokenData, null, 2)}`
// )
// Get the appropriate vout token amount. This may throw an error,
// which means this Vin is not actually a token UTXO, it was just
// associated with a previous token TX.
const tokenQty = inTokenData.amounts[thisVin.vout - 1]
// console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
if (tokenQty) {
thisVin.tokenQty = tokenQty
// txDetails.vin[i].tokenQty = tokenQty
} else {
thisVin.tokenQty = null
}
} catch (err) {
// console.log('catch 2: ', err)
// If decodeOpReturn() throws an error, then this input is not
// from an SLP transaction and can be ignored.
// thisVin.tokenQty = null
thisVin.tokenQty = null
continue
}
// console.log(
// `2: txDetails.vin[i]: ${JSON.stringify(txDetails.vin[i], null, 2)}`
// )
}
} catch (err) {
// console.log('catch 1: ', err)
return false
txDetails.vin[i].value = inAddrs[i].value
}
return txDetails
+198 -64
View File
@@ -1,12 +1,12 @@
/* eslint-disable no-useless-catch */
// Public npm libraries
const axios = require('axios')
const slpParser = require('slp-parser')
const BigNumber = require('bignumber.js')
// const Script = require("../script")
// const scriptLib = new Script()
// const BigNumber = require("bignumber.js")
// Local libraries
const Util = require('../util')
let _this
@@ -37,6 +37,8 @@ class Utils {
_this = this
this.whitelist = []
this.util = new Util(config)
}
/**
@@ -436,10 +438,11 @@ class Utils {
// will be like the examples above. If SLPDB has fallen behind real-time
// processing, it will return this output:
// [ null ]
async validateTxid (txid) {
async validateTxid (txid, usrObj = null) {
const path = `${this.restURL}slp/validateTxid`
// console.log(`txid: ${JSON.stringify(txid, null, 2)}`)
// console.log(`validateTxid usrObj: ${JSON.stringify(usrObj, null, 2)}`)
// Handle a single TXID or an array of TXIDs.
let txids
@@ -450,7 +453,8 @@ class Utils {
const response = await _this.axios.post(
path,
{
txids: txids
txids: txids,
usrObj // pass user data when making an internal call.
},
_this.axiosOptions
)
@@ -649,11 +653,12 @@ class Utils {
* '00ea27261196a411776f81029c0ebe34362936b4a9847deb1f7a40a02b3a1476',
* valid: true } ]
*/
async validateTxid3 (txid) {
async validateTxid3 (txid, usrObj = null) {
const path = `${this.restURL}slp/validateTxid3`
// console.log(`txid: ${JSON.stringify(txid, null, 2)}`)
// console.log(`path: ${JSON.stringify(path, null, 2)}`)
// console.log('validateTxid3 usrObj: ', usrObj)
// Handle a single TXID or an array of TXIDs.
let txids
@@ -664,7 +669,8 @@ class Utils {
const response = await _this.axios.post(
path,
{
txids: txids
txids: txids,
usrObj // pass user data when making an internal call.
},
_this.axiosOptions
)
@@ -893,6 +899,9 @@ class Utils {
* If optional associative array parameter cache is used, will cache and
* reuse responses for the same input.
*
* A third optional input, `usrObj`, is used by bch-api for managing rate limits.
* It can be safely ignored when writing apps using this call.
*
*
* @apiExample Example usage:
*
@@ -922,7 +931,8 @@ class Utils {
*
*/
// Reimplementation of decodeOpReturn() using slp-parser.
async decodeOpReturn (txid, cache = null) {
async decodeOpReturn (txid, cache = null, usrObj = null) {
console.log(`Entering decodeOpReturn with txid ${txid}.`)
// The cache object is an in-memory cache (JS Object) that can be passed
// into this function. It helps if multiple vouts from the same TXID are
// being evaluated. In that case, it can significantly reduce the number
@@ -939,16 +949,29 @@ class Utils {
if (cachedVal) return cachedVal
}
// console.log(`decodeOpReturn usrObj: ${JSON.stringify(usrObj, null, 2)}`)
try {
// Validate the txid input.
if (!txid || txid === '' || typeof txid !== 'string') {
throw new Error('txid string must be included.')
}
console.log(`axiosOptions: ${JSON.stringify(_this.axiosOptions, null, 2)}`)
// CT: 2/24/21 Deprected GET in favor of POST, to pass IP address.
// Retrieve the transaction object from the full node.
const path = `${this.restURL}rawtransactions/getRawTransaction/${txid}?verbose=true`
const response = await _this.axios.get(path, _this.axiosOptions)
const txDetails = response.data
const path = `${this.restURL}rawtransactions/getRawTransaction`
const response = await _this.axios.post(
path,
{
verbose: true,
txids: [txid],
usrObj // pass user data when making an internal call.
},
_this.axiosOptions
)
const txDetails = response.data[0]
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
// SLP spec expects OP_RETURN to be the first output of the transaction.
@@ -993,10 +1016,20 @@ class Utils {
if (cache) cache[txid] = tokenData
console.log('Exiting decodeOpReturn()')
return tokenData
} catch (error) {
// console.log('decodeOpReturn error: ', error)
if (error.response && error.response.data) throw error.response.data
// Used for debugging
console.log('decodeOpReturn error: ', error)
console.log(`decodeOpReturn error.message: ${error.message}`)
if (error.response && error.response.data) {
console.log(
`decodeOpReturn error.response.data: ${JSON.stringify(
error.response.data
)}`
)
}
throw error
}
}
@@ -1009,15 +1042,30 @@ class Utils {
*
* Expects an array of UTXO objects as input. Returns an array of equal size.
* Returns UTXO data hydrated with token information.
* If the
* UTXO does not belong to a SLP transaction, it will return an `isValid` property
* set to false.
* If the UTXO is part of an SLP transaction, it will return the UTXO object
* with additional SLP information attached. An `isValid` property will be included.
* If its value is true, the UTXO is a valid SLP UTXO.
* If the isValid value is null,
* then SLPDB has not yet processed that txid and validity has not been confirmed,
* or a 429 rate-limit error was enountered during the processing of the request.
*
* - If the UTXO does not belong to a SLP transaction, it will return an
* `isValid` property set to `false`.
*
* - If the UTXO is part of an SLP transaction, it will return the UTXO object
* with additional SLP information attached. An `isValid` property will be
* included.
* - If the `isValid` property is `true`, the UTXO is a valid SLP UTXO.
* - If the `isValid` property is `null`, then SLPDB has not yet processed
* that txid and validity has not been confirmed, or a 429 rate-limit error
* was enountered during the processing of the request.
*
* An optional second input object, `usrObj`, allows the user to inject an
* artifical delay while processing UTXOs. If `usrObj.utxoDelay` is set to
* a number, the call will delay by that number of milliseconds between
* processing UTXOs.
*
* This is an API-heavy call. If you get a lot of `null` values, then slow down
* the calls by using the usrObj.utxoDelay property, or request info on fewer
* UTXOs at a
* time. `null` indicates that the UTXO can *not* be safely spent, because
* a judgement as to weather it is a token UTXO has not been made. Spending it
* could burn tokens. It's safest to ignore UTXOs with a value of `null`.
*
*
* @apiExample Example usage:
*
@@ -1025,7 +1073,8 @@ class Utils {
* try {
* const utxos = await bchjs.Electrumx.utxo(`bitcoincash:qpcqs0n5xap26un2828n55gan2ylj7wavvzeuwdx05`)
*
* const utxoInfo = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
* // Delay 100mS between processing UTXOs, to prevent rate-limit errors.
* const utxoInfo = await bchjs.SLP.Utils.tokenUtxoDetails(utxos, { utxoDelay: 100 })
*
* console.log(`utxoInfo: ${JSON.stringify(utxoInfo, null, 2)}`)
* } catch (error) {
@@ -1053,16 +1102,14 @@ class Utils {
* "tokenType": 1
* }
*/
// CT 1/11/20: Refactored to comply with this GitHub Issue:
// https://github.com/Bitcoin-com/slp-sdk/issues/84
// CT 5/31/20: Refactored to use slp-parse library.
async tokenUtxoDetails (utxos) {
async tokenUtxoDetails (utxos, usrObj = null) {
console.log('Entering tokenUtxoDetails()')
try {
// Throw error if input is not an array.
if (!Array.isArray(utxos)) throw new Error('Input must be an array.')
// console.log(`tokenUtxoDetails usrObj: ${JSON.stringify(usrObj, null, 2)}`)
// Loop through each element in the array and validate the input before
// further processing.
for (let i = 0; i < utxos.length; i++) {
@@ -1094,7 +1141,7 @@ class Utils {
}
// Hydrate each UTXO with data from SLP OP_REUTRNs.
const outAry = await this._hydrateUtxo(utxos)
const outAry = await this._hydrateUtxo(utxos, usrObj)
// console.log(`outAry: ${JSON.stringify(outAry, null, 2)}`)
// *After* each UTXO has been hydrated with SLP data,
@@ -1105,18 +1152,21 @@ class Utils {
// *After* the UTXO has been hydrated with SLP data,
// validate the TXID with SLPDB.
if (utxo.tokenType) {
// Only execute this block if the current UTXO has a 'tokenType'
// Only execute this code-path if the current UTXO has a 'tokenType'
// property. i.e. it has been successfully hydrated with SLP
// information.
// Validate using a 'waterfall' of validators.
utxo.isValid = await this.waterfallValidateTxid(utxo.txid)
utxo.isValid = await this.waterfallValidateTxid(utxo.txid, usrObj)
// console.log(`isValid: ${JSON.stringify(utxo.isValid, null, 2)}`)
}
}
console.log('Exiting tokenUtxoDetails()')
return outAry
} catch (error) {
console.log('Error in tokenUtxoDetails()')
if (error.response && error.response.data) throw error.response.data
throw error
}
@@ -1133,8 +1183,20 @@ class Utils {
* but much more performant handling of SLP tokens. Some wallet apps prefer
* the scaling performance over the breadth of supported tokens.
*
* An optional second input object, `usrObj`, allows the user to inject an
* artifical delay while processing UTXOs. If `usrObj.utxoDelay` is set to
* a number, the call will delay by that number of milliseconds between
* processing UTXOs.
*
* This is an API-heavy call. If you get a lot of `null` values, then slow down
* the calls by using the usrObj.utxoDelay property, or request info on fewer
* UTXOs at a
* time. `null` indicates that the UTXO can *not* be safely spent, because
* a judgement as to weather it is a token UTXO has not been made. Spending it
* could burn tokens. It's safest to ignore UTXOs with a value of `null`.
*
*/
async tokenUtxoDetailsWL (utxos) {
async tokenUtxoDetailsWL (utxos, usrObj = null) {
try {
// Throw error if input is not an array.
if (!Array.isArray(utxos)) throw new Error('Input must be an array.')
@@ -1170,7 +1232,7 @@ class Utils {
}
// Hydrate each UTXO with data from SLP OP_REUTRNs.
const outAry = await this._hydrateUtxo(utxos)
const outAry = await this._hydrateUtxo(utxos, usrObj)
// console.log(`outAry: ${JSON.stringify(outAry, null, 2)}`)
// *After* each UTXO has been hydrated with SLP data,
@@ -1186,7 +1248,7 @@ class Utils {
// information.
// Validate against the whitelist SLPDB.
const whitelistResult = await this.validateTxid3(utxo.txid)
const whitelistResult = await this.validateTxid3(utxo.txid, usrObj)
// console.log(
// `whitelist-SLPDB for ${txid}: ${JSON.stringify(
// whitelistResult,
@@ -1214,10 +1276,27 @@ class Utils {
// This is a private function that is called by tokenUtxoDetails().
// It loops through an array of UTXOs and tries to hydrate them with SLP
// token information from the OP_RETURN data.
async _hydrateUtxo (utxos) {
//
// This function makes several calls to decodeOpReturn() to retrieve SLP
// token data. If that call throws an error due to hitting rate limits, this
// function will not throw an error. Instead, it will mark the `isValid`
// property as `null`
//
// Exception to the above: It *will* throw an error if decodeOpReturn() throws
// an error while trying to get the Genesis transaction for a Send or Mint
// transaction. However, that is a rare occurence since the cache of
// decodeOpReturn() will minimize API calls for this case. This behavior
// could be changed, but right now it's a corner case of a corner case.
//
// If the usrObj has a utxoDelay property, then it will delay the loop for
// each UTXO by that many milliseconds.
async _hydrateUtxo (utxos, usrObj = null) {
console.log('Entering _hydrateUtxo()')
try {
const decodeOpReturnCache = {}
// console.log(`_hydrateUtxo usrObj: ${JSON.stringify(usrObj, null, 2)}`)
// Output Array
const outAry = []
@@ -1225,15 +1304,28 @@ class Utils {
for (let i = 0; i < utxos.length; i++) {
const utxo = utxos[i]
// If the user passes in a delay, then wait.
if (usrObj && usrObj.utxoDelay && !isNaN(Number(usrObj.utxoDelay))) {
const delayMs = Number(usrObj.utxoDelay)
await this.util.sleep(delayMs)
}
// Get raw transaction data from the full node and attempt to decode
// the OP_RETURN data.
// If there is no OP_RETURN, mark the UTXO as false.
let slpData = false
try {
slpData = await this.decodeOpReturn(utxo.txid, decodeOpReturnCache)
slpData = await this.decodeOpReturn(
utxo.txid,
decodeOpReturnCache,
usrObj // pass user data when making an internal call.
)
// console.log(`slpData: ${JSON.stringify(slpData, null, 2)}`)
} catch (err) {
// console.log(`error from decodeOpReturn(${utxo.txid}): `, err)
// console.log(
// `error in _hydrateUtxo() from decodeOpReturn(${utxo.txid}): `,
// err
// )
// An error will be thrown if the txid is not SLP.
// If error is for some other reason, like a 429 error, mark utxo as 'null'
@@ -1245,7 +1337,7 @@ class Utils {
err.message.indexOf('trailing data') === -1)
) {
// console.log(
// 'unknown error from decodeOpReturn(). Marking as \'null\'',
// "unknown error from decodeOpReturn(). Marking as 'null'",
// err
// )
@@ -1264,6 +1356,7 @@ class Utils {
// Halt the execution of the loop and increase to the next index.
continue
}
// console.log(`slpData: ${JSON.stringify(slpData, null, 2)}`)
const txType = slpData.txType.toLowerCase()
@@ -1301,6 +1394,10 @@ class Utils {
utxo.decimals = slpData.decimals
utxo.tokenType = slpData.tokenType
// Initial value is null until UTXO can be validated and confirmed
// to be valid (true) or not (false).
utxo.isValid = null
outAry[i] = utxo
}
}
@@ -1320,7 +1417,8 @@ class Utils {
const genesisData = await this.decodeOpReturn(
slpData.tokenId,
decodeOpReturnCache
decodeOpReturnCache,
usrObj // pass user data when making an internal call.
)
// console.log(`genesisData: ${JSON.stringify(genesisData, null, 2)}`)
@@ -1349,6 +1447,10 @@ class Utils {
utxo.mintBatonVout = slpData.mintBatonVout
// Initial value is null until UTXO can be validated and confirmed
// to be valid (true) or not (false).
utxo.isValid = null
outAry[i] = utxo
}
}
@@ -1372,7 +1474,8 @@ class Utils {
const genesisData = await this.decodeOpReturn(
slpData.tokenId,
decodeOpReturnCache
decodeOpReturnCache,
usrObj // pass user data when making an internal call.
)
// console.log(`genesisData: ${JSON.stringify(genesisData, null, 2)}`)
@@ -1389,6 +1492,10 @@ class Utils {
utxo.decimals = genesisData.decimals
utxo.tokenType = slpData.tokenType
// Initial value is null until UTXO can be validated and confirmed
// to be valid (true) or not (false).
utxo.isValid = null
// Calculate the real token quantity.
const tokenQtyBig = new BigNumber(tokenQty).div(
@@ -1404,9 +1511,11 @@ class Utils {
}
}
console.log('Exiting _hydrateUtxo()')
return outAry
} catch (error) {
if (error.response && error.response.data) throw error.response.data
console.log('Error in _hydrateUtxo()')
// console.log('_hydrateUtxo error: ', error)
throw error
}
}
@@ -1447,8 +1556,8 @@ class Utils {
* // returns
* true
*/
async waterfallValidateTxid (txid) {
async waterfallValidateTxid (txid, usrObj = null) {
console.log('Entering waterfallValidateTxid()')
try {
// console.log('txid: ', txid)
@@ -1480,7 +1589,7 @@ class Utils {
// validateTxid2() uses slp-validate, which has a different output format.
// Validate against the whitelist SLPDB first.
const whitelistResult = await this.validateTxid3(txid)
const whitelistResult = await this.validateTxid3(txid, usrObj)
// console.log(
// `whitelist-SLPDB for ${txid}: ${JSON.stringify(
// whitelistResult,
@@ -1501,7 +1610,7 @@ class Utils {
}
// Try the general SLPDB, if the whitelist returned null.
const generalResult = await this.validateTxid(txid)
const generalResult = await this.validateTxid(txid, usrObj)
// console.log(
// `validateTxid() isValid: ${JSON.stringify(generalResult, null, 2)}`
// )
@@ -1538,10 +1647,13 @@ class Utils {
return isValid
}
console.log('Exiting waterfallValidateTxid()')
// If isValid is still null, return that value, signaling that the txid
// could not be validated.
return isValid
} catch (error) {
console.log('Error in waterfallValidateTxid()')
if (error.response && error.response.data) throw error.response.data
throw error
}
@@ -1554,19 +1666,33 @@ class Utils {
* @apiDescription Hydrate a UTXO with SLP token metadata.
*
* The same as tokenUtxoDetails(), but uses bch-api to do the heavy lifting,
* which greatly reduces the number of API calls.
* which greatly increases the speed, since fewer API calls need to be made.
* However, internal API calls are still counted against your rate limits.
*
* Expects an array of UTXO objects as input. Returns an array of equal size.
* Returns UTXO data hydrated with token information.
* If the
* UTXO does not belong to a SLP transaction, it will return an `isValid` property
* set to false.
* If the UTXO is part of an SLP transaction, it will return the UTXO object
* with additional SLP information attached. An `isValid` property will be included.
* If its value is true, the UTXO is a valid SLP UTXO. \
* If the isValid value is null,
* then SLPDB has not yet processed that txid and validity has not been confirmed,
* or a 429 rate-limit error was enountered during the processing of the request.
* This function expects an array of UTXO objects as input. It returns an
* array of equal size. The UTXO data hydrated with token information.
* - If the UTXO does not belong to a SLP transaction, it will return an
* `isValid` property set to `false`.
* - If the UTXO is part of an SLP transaction, it will return the UTXO object
* with additional SLP information attached. An `isValid` property will be
* included.
* - If `isValid` is `true`, the UTXO is a valid SLP UTXO.
* - If `isValid` is `null`, then SLPDB has not yet processed that txid
* and validity has not been confirmed,
* or a 429 rate-limit error was enountered during the processing of the
* request.
*
* An optional second input object, `usrObj`, allows the user to inject an
* artifical delay while processing UTXOs. If `usrObj.utxoDelay` is set to
* a number, the call will delay by that number of milliseconds between
* processing UTXOs.
*
* This is an API-heavy call. If you get a lot of `null` values, then slow down
* the calls by using the usrObj.utxoDelay property, or request info on fewer
* UTXOs at a
* time. `null` indicates that the UTXO can *not* be safely spent, because
* a judgement as to weather it is a token UTXO has not been made. Spending it
* could burn tokens. It's safest to ignore UTXOs with a value of `null`.
*
* @apiExample Example usage:
*
@@ -1578,7 +1704,8 @@ class Utils {
* "bitcoincash:qzygn28zpgeemnptkn26xzyuzzfu9l8f9vfvq7kptk"
* ])
*
* const utxoInfo = await bchjs.SLP.Utils.hydrateUtxos(utxos.utxos)
* // Wait 100mS between processing UTXOs, to prevent rate limit errors.
* const utxoInfo = await bchjs.SLP.Utils.hydrateUtxos(utxos.utxos, { utxoDelay: 100 })
*
* console.log(`${JSON.stringify(utxoInfo, null, 2)}`)
* } catch (error) {
@@ -1712,23 +1839,30 @@ class Utils {
*/
// Same as tokenUtxoDetails(), but reduces API calls by having bch-api server
// do the heavy lifting.
async hydrateUtxos (utxos) {
async hydrateUtxos (utxos, usrObj) {
try {
// Throw error if input is not an array.
if (!Array.isArray(utxos)) throw new Error('Input must be an array.')
console.log(
`axiosOptions: ${JSON.stringify(_this.axiosOptions, null, 2)}`
)
const response = await _this.axios.post(
`${this.restURL}slp/hydrateUtxos`,
{
utxos: utxos
utxos: utxos,
usrObj
},
_this.axiosOptions
)
return response.data
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
if (error.response && error.response.data) {
throw new Error(JSON.stringify(error.response.data, null, 2))
}
throw error
}
}
-28
View File
@@ -1,28 +0,0 @@
const io = require('socket.io-client')
class Socket {
constructor (config = {}) {
if (typeof config === 'string') {
// TODO remove this check in v2.0
this.socket = io(`${config}`)
} else {
if (config.restURL) {
this.socket = io(`${config.restURL}`)
} else {
const restURL = 'https://rest.bitcoin.com'
this.socket = io(`${restURL}`)
}
if (config.callback) config.callback()
}
}
listen (endpoint, cb) {
this.socket.emit(endpoint)
if (endpoint === 'blocks') this.socket.on('blocks', msg => cb(msg))
else if (endpoint === 'transactions') { this.socket.on('transactions', msg => cb(msg)) }
}
}
module.exports = Socket
+145
View File
@@ -0,0 +1,145 @@
/*
High-level functions for working with Transactions
*/
const RawTransaction = require('./raw-transactions')
const SlpUtils = require('./slp/utils')
class Transaction {
constructor (config) {
// Encapsulate dependencies
this.slpUtils = new SlpUtils(config)
this.rawTransaction = new RawTransaction(config)
}
/**
* @api Transaction.get() get()
* @apiName get
* @apiGroup Transaction
* @apiDescription
* Returns an object of transaction data, including addresses for input UTXOs.
* If it is a SLP token transaction, the token information for inputs and
* outputs will also be included.
*
* This is an API heavy call. This function will only work with a single txid.
* It does not yet support an array of TXIDs.
*
* @apiExample Example usage:
* (async () => {
* try {
* let txData = await bchjs.Transaction.get("0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098");
* console.log(txData);
* } catch(error) {
* console.error(error)
* }
* })()
*/
async get (txid) {
try {
if (typeof txid !== 'string') {
throw new Error('Input must be a string or array of strings.')
}
const txDetails = await this.rawTransaction.getTxData(txid)
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
// Setup default SLP properties.
txDetails.isValidSLPTx = false
// First get the token information for the output. If that fails, then
// this is not an SLP transaction, and this method can return false.
let outTokenData
try {
outTokenData = await this.slpUtils.decodeOpReturn(txid)
// console.log(`outTokenData: ${JSON.stringify(outTokenData, null, 2)}`)
// Get Genesis data for this token.
const genesisData = await this.slpUtils.decodeOpReturn(
outTokenData.tokenId
// decodeOpReturnCache
// usrObj // pass user data when making an internal call.
)
// console.log(`genesisData: ${JSON.stringify(genesisData, null, 2)}`)
// Add token information to the tx details object.
txDetails.tokenTxType = outTokenData.txType
txDetails.tokenId = outTokenData.tokenId
txDetails.tokenTicker = genesisData.ticker
txDetails.tokenName = genesisData.name
txDetails.tokenDecimals = genesisData.decimals
txDetails.tokenUri = genesisData.documentUri
txDetails.tokenDocHash = genesisData.documentHash
// Add the token quantity to each output.
for (let i = 0; i < outTokenData.amounts.length; i++) {
const rawQty = outTokenData.amounts[i]
const realQty = Number(rawQty) / Math.pow(10, txDetails.tokenDecimals)
txDetails.vout[i + 1].tokenQty = realQty
}
// Add tokenQty = null to any outputs that don't have a value.
for (let i = 0; i < txDetails.vout.length; i++) {
const thisVout = txDetails.vout[i]
if (!thisVout.tokenQty && thisVout.tokenQty !== 0) {
thisVout.tokenQty = null
}
}
// Loop through each input and retrieve the token data.
for (let i = 0; i < txDetails.vin.length; i++) {
const thisVin = txDetails.vin[i]
try {
// If decodeOpReturn() throws an error, then this input is not
// from an SLP transaction and can be ignored.
const inTokenData = await this.slpUtils.decodeOpReturn(thisVin.txid)
// console.log(
// `vin[${i}] tokenData: ${JSON.stringify(inTokenData, null, 2)}`
// )
// Get the appropriate vout token amount. This may throw an error,
// which means this Vin is not actually a token UTXO, it was just
// associated with a previous token TX.
const tokenQty = inTokenData.amounts[thisVin.vout - 1]
// console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
if (tokenQty) {
const realQty =
Number(tokenQty) / Math.pow(10, txDetails.tokenDecimals)
thisVin.tokenQty = realQty
// txDetails.vin[i].tokenQty = tokenQty
} else {
thisVin.tokenQty = null
}
} catch (err) {
// If decodeOpReturn() throws an error, then this input is not
// from an SLP transaction and can be ignored.
// thisVin.tokenQty = null
thisVin.tokenQty = null
continue
}
}
// Finally, validate the SLP TX.
// this.slpUtils.waterfallValidateTxid(txid, usrObj)
txDetails.isValidSLPTx = await this.slpUtils.waterfallValidateTxid(txid)
} catch (err) {
// console.log('Error: ', err)
// If decoding the op_return fails, then it's not an SLP transaction,
// and the non-hyrated TX details can be returned.
return txDetails
}
return txDetails
} catch (err) {
console.error('Error in transactions.js/get()')
throw err
}
}
}
module.exports = Transaction
+24
View File
@@ -150,6 +150,30 @@ class Util {
}
}
/**
* @api util.sleep() sleep()
* @apiName sleep
* @apiGroup Util
* @apiDescription Promise-based delay.
* Expects an integer as input, which represents milliseconds. This function
* will return a Promise that resolves that many milliseconds later.
*
*
* @apiExample Example usage:
* (async () => {
* try {
* const tenSeconds = 10000
* await bchjs.Util.sleep(tenSeconds)
* } catch(error) {
* console.error(error)
* }
* })()
*
*/
sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
/**
* @api util.validateAddress() validateAddress()
* @apiName Validate Address.
@@ -22,9 +22,13 @@ describe('#UTXO', () => {
const result = await bchjs.Utxo.get(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result.bchUtxos)
assert.isArray(result.slpUtxos)
assert.isArray(result.nullUtxos)
assert.isArray(result)
assert.property(result[0], 'address')
assert.property(result[0], 'bchUtxos')
assert.property(result[0], 'nullUtxos')
assert.property(result[0], 'slpUtxos')
assert.isArray(result[0].bchUtxos)
assert.isArray(result[0].nullUtxos)
})
})
})
@@ -20,7 +20,7 @@ util.inspect.defaultOptions = {
describe('#rawtransaction', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
})
/*
+26 -1
View File
@@ -25,12 +25,37 @@ describe('#SLP', () => {
beforeEach(async () => {
// Introduce a delay so that the BVT doesn't trip the rate limits.
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
bchjs = new BCHJS()
})
describe('#util', () => {
describe('#decodeOpReturn', () => {
it('should decode a NFT Child transaction', async () => {
const txid =
'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b'
const data = await bchjs.SLP.Utils.decodeOpReturn(txid)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.property(data, 'tokenType')
assert.property(data, 'txType')
assert.property(data, 'ticker')
assert.property(data, 'name')
assert.property(data, 'tokenId')
assert.property(data, 'documentUri')
assert.property(data, 'documentHash')
assert.property(data, 'decimals')
assert.property(data, 'mintBatonVout')
assert.property(data, 'qty')
assert.equal(data.tokenType, 65)
assert.equal(data.mintBatonVout, 0)
assert.equal(data.qty, '1')
})
})
describe('#tokenUtxoDetails', () => {
it('should handle a range of UTXO types', async () => {
const utxos = [
@@ -11,7 +11,7 @@ describe('#UTXO', () => {
beforeEach(async () => {
// sandbox = sinon.createSandbox()
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
})
describe('#get', () => {
@@ -112,7 +112,7 @@ describe('#UTXO', () => {
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
const result = bchjs.Utxo.findBiggestUtxo(utxos[0].bchUtxos)
console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'satoshis')
assert.equal(result.satoshis, 800)
+8
View File
@@ -33,6 +33,14 @@ describe('#price', () => {
assert.isNumber(result)
})
})
describe('#getBchUsd', () => {
it('should get the USD price of BCH', async () => {
const result = await bchjs.Price.getBchUsd()
console.log(result)
assert.isNumber(result)
})
})
describe('#rates', () => {
it('should get the price of BCH in several currencies', async () => {
+26 -25
View File
@@ -1,6 +1,5 @@
/*
Integration tests for the bchjs. Only covers calls made to
rest.bitcoin.com.
Integration tests for the bchjs.
TODO
*/
@@ -263,6 +262,7 @@ describe('#rawtransaction', () => {
assert.equal(result.length, 1)
assert.property(result[0], 'vin')
assert.property(result[0], 'address')
assert.property(result[0], 'value')
})
})
@@ -274,32 +274,33 @@ describe('#rawtransaction', () => {
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result.vin[0], 'address')
assert.property(result.vin[0], 'value')
})
})
describe('#getTxDataSlp', () => {
it('should return tx data with SLP information', async () => {
const txid = 'b438855cfcab64516b44097d7212df9cdb99226c8d7c7ab504d35fcfd834cb5b'
const result = await bchjs.RawTransactions.getTxDataSlp(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result.vin[0], 'address')
assert.property(result.vin[0], 'tokenQty')
assert.equal(result.vin[0].tokenQty, null)
assert.equal(result.vin[1].tokenQty, '100000000000')
})
it('should handle non-slp tx', async () => {
const txid = '04a6aca328af2445327015895b8da9766093b1989b52e477559759eb8072fc0a'
const result = await bchjs.RawTransactions.getTxDataSlp(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result, false)
})
})
// describe('#getTxDataSlp', () => {
// it('should return tx data with SLP information', async () => {
// const txid = 'b438855cfcab64516b44097d7212df9cdb99226c8d7c7ab504d35fcfd834cb5b'
//
// const result = await bchjs.RawTransactions.getTxDataSlp(txid)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.property(result.vin[0], 'address')
// assert.property(result.vin[0], 'tokenQty')
//
// assert.equal(result.vin[0].tokenQty, null)
// assert.equal(result.vin[1].tokenQty, '100000000000')
// })
//
// it('should handle non-slp tx', async () => {
// const txid = '04a6aca328af2445327015895b8da9766093b1989b52e477559759eb8072fc0a'
//
// const result = await bchjs.RawTransactions.getTxDataSlp(txid)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.equal(result, false)
// })
// })
})
function sleep (ms) {
+2 -2
View File
@@ -24,7 +24,7 @@ describe('#SLP', () => {
beforeEach(async () => {
// Introduce a delay so that the BVT doesn't trip the rate limits.
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
bchjs = new BCHJS()
})
@@ -639,7 +639,7 @@ describe('#SLP', () => {
})
})
describe('#hydrateUtxos', () => {
describe('#hydrateUtxos-', () => {
it('should hydrate UTXOs', async () => {
const utxos = [
{
@@ -0,0 +1,60 @@
/*
Integration tests for the transaction.js library.
*/
const assert = require('chai').assert
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
describe('#Transaction', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await bchjs.Util.sleep(1000)
})
describe('#get', () => {
it('should get details about a non-SLP transaction', async () => {
const txid =
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7'
const result = await bchjs.Transaction.get(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Assert that there are stanardized properties.
assert.property(result, 'txid')
assert.property(result, 'vin')
assert.property(result, 'vout')
assert.property(result.vout[0], 'value')
assert.property(result.vout[0].scriptPubKey, 'addresses')
// Assert that added properties exist.
assert.property(result.vin[0], 'address')
assert.property(result.vin[0], 'value')
assert.property(result, 'isValidSLPTx')
assert.equal(result.isValidSLPTx, false)
})
it('should get details about a SLP transaction', async () => {
const txid =
'266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1'
const result = await bchjs.Transaction.get(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Assert that there are stanardized properties.
assert.property(result, 'txid')
assert.property(result, 'vin')
assert.property(result, 'vout')
assert.property(result.vout[0], 'value')
assert.property(result.vout[1].scriptPubKey, 'addresses')
// Assert that added properties exist.
assert.property(result.vout[0], 'tokenQty')
assert.equal(result.vout[0].tokenQty, null)
assert.property(result.vin[0], 'address')
assert.property(result.vin[0], 'value')
assert.property(result.vin[0], 'tokenQty')
assert.property(result, 'isValidSLPTx')
assert.equal(result.isValidSLPTx, true)
})
})
})
+98 -1
View File
@@ -1290,6 +1290,100 @@ const slpdbStatus = {
}
}
const txDetailsSLPNftChild = {
txid: 'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b',
hash: 'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b',
version: 2,
size: 453,
locktime: 0,
vin: [
{
txid: 'a9a2458a0f9f0761d5b8725c256f2e7fa35b9de4dec6f47b46e9f20d92d0e395',
vout: 1,
scriptSig: {
asm:
'3045022100890ff2f80f3c184419ba03a575b9d159c0a5edfa817e4548cfdb6c74d16ce8d202205a8237d2139196716c273fe80506896d369a0022bb54401e2eadb364286a9f07[ALL|FORKID] 03136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623b',
hex:
'483045022100890ff2f80f3c184419ba03a575b9d159c0a5edfa817e4548cfdb6c74d16ce8d202205a8237d2139196716c273fe80506896d369a0022bb54401e2eadb364286a9f07412103136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623b'
},
sequence: 4294967295
},
{
txid: 'a9a2458a0f9f0761d5b8725c256f2e7fa35b9de4dec6f47b46e9f20d92d0e395',
vout: 3,
scriptSig: {
asm:
'304402203905a61ec4e3567f7cad7eb514132e5b32d8a1d77c8838baac1b34b735282a5f022044da6130b5cc41b65615b17df6610087fe1baedd1a3a9f37552b56ea8d36d026[ALL|FORKID] 03136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623b',
hex:
'47304402203905a61ec4e3567f7cad7eb514132e5b32d8a1d77c8838baac1b34b735282a5f022044da6130b5cc41b65615b17df6610087fe1baedd1a3a9f37552b56ea8d36d026412103136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623b'
},
sequence: 4294967295
}
],
vout: [
{
value: 0,
n: 0,
scriptPubKey: {
asm:
'OP_RETURN 5262419 65 47454e45534953 4e4654303034 4e4654204368696c64 68747470733a2f2f46756c6c537461636b2e63617368 0 0 0 0000000000000001',
hex:
'6a04534c500001410747454e45534953064e4654303034094e4654204368696c641668747470733a2f2f46756c6c537461636b2e636173684c0001004c00080000000000000001',
type: 'nulldata'
}
},
{
value: 0.00000546,
n: 1,
scriptPubKey: {
asm:
'OP_DUP OP_HASH160 f6fc6bce702ef779d2373aa4356a32113d95e674 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914f6fc6bce702ef779d2373aa4356a32113d95e67488ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qrm0c67wwqh0w7wjxua2gdt2xggnm90xws00a3lezv']
}
},
{
value: 0.0003923,
n: 2,
scriptPubKey: {
asm:
'OP_DUP OP_HASH160 f6fc6bce702ef779d2373aa4356a32113d95e674 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914f6fc6bce702ef779d2373aa4356a32113d95e67488ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qrm0c67wwqh0w7wjxua2gdt2xggnm90xws00a3lezv']
}
}
],
hex:
'020000000295e3d0920df2e9467bf4c6dee49d5ba37f2e6f255c72b8d561079f0f8a45a2a9010000006b483045022100890ff2f80f3c184419ba03a575b9d159c0a5edfa817e4548cfdb6c74d16ce8d202205a8237d2139196716c273fe80506896d369a0022bb54401e2eadb364286a9f07412103136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623bffffffff95e3d0920df2e9467bf4c6dee49d5ba37f2e6f255c72b8d561079f0f8a45a2a9030000006a47304402203905a61ec4e3567f7cad7eb514132e5b32d8a1d77c8838baac1b34b735282a5f022044da6130b5cc41b65615b17df6610087fe1baedd1a3a9f37552b56ea8d36d026412103136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623bffffffff030000000000000000476a04534c500001410747454e45534953064e4654303034094e4654204368696c641668747470733a2f2f46756c6c537461636b2e636173684c0001004c0008000000000000000122020000000000001976a914f6fc6bce702ef779d2373aa4356a32113d95e67488ac3e990000000000001976a914f6fc6bce702ef779d2373aa4356a32113d95e67488ac00000000',
blockhash: '000000000000000001360fe42629f4136e9adec53546b278de0e7ef788eed328',
confirmations: 2113,
time: 1613181364,
blocktime: 1613181364
}
const mock429Error = new Error('Request failed with status code 429')
mock429Error.response = {
status: 429,
statusText: 'Too Many Requests',
data: {
error:
'Too many requests. Your limits are currently 100 requests per minute. Increase rate limits at https://fullstack.cash'
}
}
const mock503Error = new Error('Request failed with status code 503')
mock503Error.response = {
status: 503,
statusText: 'Service Unavailable',
data: {
error: 'Some error message'
}
}
module.exports = {
mockList,
mockToken,
@@ -1311,6 +1405,7 @@ module.exports = {
txDetailsSLPGenesisNoBaton,
txDetailsSLPSendAlt,
txDetailsSLPNftGenesis,
txDetailsSLPNftChild,
mockTxDetails,
mockDualValidation,
mockDualOpData,
@@ -1320,5 +1415,7 @@ module.exports = {
mockValidateTxid3Invalid,
whitelist,
slpdbStatus,
mockValidateTxidArray
mockValidateTxidArray,
mock429Error,
mock503Error
}
+184
View File
@@ -0,0 +1,184 @@
/*
Mocking data used in the transaction-unit.js tests.
*/
const nonSlpTxDetails = {
txid: '2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7',
hash: '2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7',
version: 2,
size: 225,
locktime: 0,
vin: [
{
txid: '5f09d317e24c5d376f737a2711f3bd1d381abdb41743fff3819b4f76382e1eac',
vout: 1,
scriptSig: {
asm:
'3044022000dd11c41a472f2e54348db996e60864d489429f12d1e044d49ff600b880c9590220715a926404bb0e2731a3795afb341ec1dad3f84ead7d27cd31fcc59abb14738c[ALL|FORKID] 038476128287ac37c7a3cf7e8625fd5f024db1bc3d8e37395abe7bf42fda78d0d9',
hex:
'473044022000dd11c41a472f2e54348db996e60864d489429f12d1e044d49ff600b880c9590220715a926404bb0e2731a3795afb341ec1dad3f84ead7d27cd31fcc59abb14738c4121038476128287ac37c7a3cf7e8625fd5f024db1bc3d8e37395abe7bf42fda78d0d9'
},
sequence: 4294967295,
address: 'bitcoincash:qqxy8hycqe89j7wa79gnggq6z3gaqu2uvqy26xehfe',
value: 0.00047504
}
],
vout: [
{
value: 0.00001,
n: 0,
scriptPubKey: {
asm:
'OP_DUP OP_HASH160 2fe2c4c5ef359bb2fe1a849f891cecffbcfb4f77 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a9142fe2c4c5ef359bb2fe1a849f891cecffbcfb4f7788ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9']
}
},
{
value: 0.00046256,
n: 1,
scriptPubKey: {
asm:
'OP_DUP OP_HASH160 2dbf5e1804c39a497b908c876097d63210c84902 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a9142dbf5e1804c39a497b908c876097d63210c8490288ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qqkm7hscqnpe5jtmjzxgwcyh6ceppjzfqg3jdn422e']
}
}
],
hex:
'0200000001ac1e2e38764f9b81f3ff4317b4bd1a381dbdf311277a736f375d4ce217d3095f010000006a473044022000dd11c41a472f2e54348db996e60864d489429f12d1e044d49ff600b880c9590220715a926404bb0e2731a3795afb341ec1dad3f84ead7d27cd31fcc59abb14738c4121038476128287ac37c7a3cf7e8625fd5f024db1bc3d8e37395abe7bf42fda78d0d9ffffffff02e8030000000000001976a9142fe2c4c5ef359bb2fe1a849f891cecffbcfb4f7788acb0b40000000000001976a9142dbf5e1804c39a497b908c876097d63210c8490288ac00000000',
blockhash: '0000000000000000010903a1fc4274499037c9339be9ec7338ee980331c20ce5',
confirmations: 77741,
time: 1569792892,
blocktime: 1569792892
}
const slpTxDetails = {
txid: '266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1',
hash: '266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1',
version: 2,
size: 479,
locktime: 0,
vin: [
{
txid: 'abc685f1f2a95f51e5e05a350f3fb9c74676e9f78c835b2a019c888ac0a2a736',
vout: 2,
scriptSig: {
asm:
'3045022100e5f0f6f1212fcbb10eedb7fdc38fca6e86629b4e7e8356a3ad7371a109fc37a602204bfff37d1a34d2e2908b81c23677706fb59ff4ab639fa3299da6c303de74e1f7[ALL|FORKID] 0245b9b3586fab3cfd46db6d116c4588004fe7fe9798216ccb8e55a89bcebc07ac',
hex:
'483045022100e5f0f6f1212fcbb10eedb7fdc38fca6e86629b4e7e8356a3ad7371a109fc37a602204bfff37d1a34d2e2908b81c23677706fb59ff4ab639fa3299da6c303de74e1f741210245b9b3586fab3cfd46db6d116c4588004fe7fe9798216ccb8e55a89bcebc07ac'
},
sequence: 4294967295,
address: 'bitcoincash:qzv7t2pzn2d0pklnetdjt65crh6fe8vnhuwvhsk2nn',
value: 0.00000546
},
{
txid: '58c8576404c01c23a224053307399483d3a070599b3e9eb6d45be9714b8d6856',
vout: 1,
scriptSig: {
asm:
'30430220784f6d81fa8f54db8a4948259e8c15972a0285f8b1640c433d4e9f606dc38f0c021f14eecc2e8af2efede0867ce459c400dde54186a0e64babdbe89f795db12753[ALL|FORKID] 0209ebe6d9da5043945ed1d81bec0fcace299eba05e5f46b72d6838c790d31c505',
hex:
'4630430220784f6d81fa8f54db8a4948259e8c15972a0285f8b1640c433d4e9f606dc38f0c021f14eecc2e8af2efede0867ce459c400dde54186a0e64babdbe89f795db1275341210209ebe6d9da5043945ed1d81bec0fcace299eba05e5f46b72d6838c790d31c505'
},
sequence: 4294967295,
address: 'bitcoincash:qppzuxemgqyxf07nz3kan33gmc83mf3z3yz295c4s7',
value: 0.68369626
}
],
vout: [
{
value: 0,
n: 0,
scriptPubKey: {
asm:
'OP_RETURN 5262419 1 1145980243 497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7 0000000005f5e100 00005ad7e49d9100',
hex:
'6a04534c500001010453454e4420497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7080000000005f5e1000800005ad7e49d9100',
type: 'nulldata'
}
},
{
value: 0.00000546,
n: 1,
scriptPubKey: {
asm:
'OP_DUP OP_HASH160 36be3b7d185a85b6cf6fc61d63c16f2f10e54260 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a91436be3b7d185a85b6cf6fc61d63c16f2f10e5426088ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qqmtuwmarpdgtdk0dlrp6c7pduh3pe2zvqrkys2ex8']
}
},
{
value: 0.00000546,
n: 2,
scriptPubKey: {
asm:
'OP_DUP OP_HASH160 99e5a8229a9af0dbf3cadb25ea981df49c9d93bf OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a91499e5a8229a9af0dbf3cadb25ea981df49c9d93bf88ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qzv7t2pzn2d0pklnetdjt65crh6fe8vnhuwvhsk2nn']
}
},
{
value: 0.68368564,
n: 3,
scriptPubKey: {
asm:
'OP_DUP OP_HASH160 422e1b3b400864bfd3146dd9c628de0f1da62289 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914422e1b3b400864bfd3146dd9c628de0f1da6228988ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qppzuxemgqyxf07nz3kan33gmc83mf3z3yz295c4s7']
}
}
],
hex:
'020000000236a7a2c08a889c012a5b838cf7e97646c7b93f0f355ae0e5515fa9f2f185c6ab020000006b483045022100e5f0f6f1212fcbb10eedb7fdc38fca6e86629b4e7e8356a3ad7371a109fc37a602204bfff37d1a34d2e2908b81c23677706fb59ff4ab639fa3299da6c303de74e1f741210245b9b3586fab3cfd46db6d116c4588004fe7fe9798216ccb8e55a89bcebc07acffffffff56688d4b71e95bd4b69e3e9b5970a0d383943907330524a2231cc0046457c85801000000694630430220784f6d81fa8f54db8a4948259e8c15972a0285f8b1640c433d4e9f606dc38f0c021f14eecc2e8af2efede0867ce459c400dde54186a0e64babdbe89f795db1275341210209ebe6d9da5043945ed1d81bec0fcace299eba05e5f46b72d6838c790d31c505ffffffff040000000000000000406a04534c500001010453454e4420497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7080000000005f5e1000800005ad7e49d910022020000000000001976a91436be3b7d185a85b6cf6fc61d63c16f2f10e5426088ac22020000000000001976a91499e5a8229a9af0dbf3cadb25ea981df49c9d93bf88acb4381304000000001976a914422e1b3b400864bfd3146dd9c628de0f1da6228988ac00000000',
blockhash: '0000000000000000015284202422a688554b7fc80c54f18122847a99c4f79607',
confirmations: 76722,
time: 1570392893,
blocktime: 1570392893
}
const mockOpReturnData01 = {
tokenType: 1,
txType: 'SEND',
tokenId: '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
amounts: ['100000000', '99883300000000']
}
const mockOpReturnData02 = {
tokenType: 1,
txType: 'GENESIS',
ticker: 'TOK-CH',
name: 'TokyoCash',
tokenId: '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
documentUri: '',
documentHash: '',
decimals: 8,
mintBatonVout: 0,
qty: '2100000000000000'
}
const mockOpReturnData03 = {
tokenType: 1,
txType: 'SEND',
tokenId: '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
amounts: ['1000000000', '99883400000000']
}
module.exports = {
nonSlpTxDetails,
slpTxDetails,
mockOpReturnData01,
mockOpReturnData02,
mockOpReturnData03
}
+22
View File
@@ -67,4 +67,26 @@ describe('#price', () => {
assert.isNumber(result)
})
})
describe('#getBchUsd', () => {
it('should get the USD price of BCH', async () => {
sandbox.stub(bchjs.Price.axios, 'get').resolves({ data: { usd: 510.39 } })
const result = await bchjs.Price.getBchUsd()
// console.log(result)
assert.isNumber(result)
})
it('should handle error', async () => {
try {
sandbox.stub(bchjs.Price.axios, 'get').throws(new Error('test error'))
await bchjs.Price.getBchUsd()
// console.log(result)
assert.equal(false, true, 'unexpected error')
} catch (err) {
assert.include(err.message, 'test error')
}
})
})
})
+1 -2
View File
@@ -1,6 +1,5 @@
/*
TODO:
-Create a mocking library of data to compare unit and integration tests.
Unit tests for raw-transactions.js library.
*/
// Public npm libraries
+395 -45
View File
@@ -273,8 +273,8 @@ describe('#SLP Utils', () => {
try {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.nonSLPTxDetailsWithoutOpReturn })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.nonSLPTxDetailsWithoutOpReturn] })
const txid =
'3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec'
@@ -292,8 +292,8 @@ describe('#SLP Utils', () => {
try {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.nonSLPTxDetailsWithOpReturn })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.nonSLPTxDetailsWithOpReturn] })
const txid =
'2ff74c48a5d657cf45f699601990bffbbe7a2a516d5480674cbf6c6a4497908f'
@@ -310,8 +310,8 @@ describe('#SLP Utils', () => {
it('should decode a genesis transaction', async () => {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.txDetailsSLPGenesis })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPGenesis] })
const txid =
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90'
@@ -336,8 +336,8 @@ describe('#SLP Utils', () => {
it('should decode a mint transaction', async () => {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.txDetailsSLPMint })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPMint] })
const txid =
'65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4'
@@ -357,8 +357,8 @@ describe('#SLP Utils', () => {
it('should decode a send transaction', async () => {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.txDetailsSLPSend })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPSend] })
const txid =
'4f922565af664b6fdf0a1ba3924487344be721b3d8815c62cafc8a51e04a8afa'
@@ -372,8 +372,8 @@ describe('#SLP Utils', () => {
it('should properly decode a Genesis transaction with no minting baton', async () => {
// Mock the call to the REST API.
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.txDetailsSLPGenesisNoBaton })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPGenesisNoBaton] })
const txid =
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
@@ -387,8 +387,8 @@ describe('#SLP Utils', () => {
it('should decode a send transaction with alternate encoding', async () => {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.txDetailsSLPSendAlt })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPSendAlt] })
const txid =
'd94357179775425ebc59c93173bd6dc9854095f090a2eb9dcfe9797398bc8eae'
@@ -411,8 +411,8 @@ describe('#SLP Utils', () => {
try {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.mockInvalidSlpSend })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.mockInvalidSlpSend] })
const txid =
'a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415'
@@ -428,8 +428,8 @@ describe('#SLP Utils', () => {
it('should decode a NFT Parent transaction', async () => {
// Mock the call to the REST API.
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.txDetailsSLPNftGenesis })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPNftGenesis] })
const txid =
'4ef6eb92950a13a69e97c2c02c7967d806aa874c0e2a6b5546a8880f2cd14bc4'
@@ -453,33 +453,383 @@ describe('#SLP Utils', () => {
assert.equal(data.qty, 1)
})
// it("should decode a NFT Child transaction", async () => {
// // Mock the call to the REST API.
// // sandbox
// // .stub(uut.Utils.axios, "get")
// // .resolves({ data: mockData.txDetailsSLPNftGenesis })
//
// const txid =
// "3de3766b10506c9156533f1639979e49d1884521543c13e4af73647df1ed3f76"
//
// const data = await uut.Utils.decodeOpReturn(txid)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
//
// // assert.property(data, "tokenType")
// // assert.property(data, "txType")
// // assert.property(data, "ticker")
// // assert.property(data, "name")
// // assert.property(data, "tokenId")
// // assert.property(data, "documentUri")
// // assert.property(data, "documentHash")
// // assert.property(data, "decimals")
// // assert.property(data, "mintBatonVout")
// // assert.property(data, "qty")
// //
// // assert.equal(data.tokenType, 129)
// // assert.equal(data.mintBatonVout, 2)
// // assert.equal(data.qty, 1)
// })
it('should decode a NFT Child transaction', async () => {
// Mock the call to the REST API.
sandbox
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPNftChild] })
const txid =
'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b'
const data = await uut.Utils.decodeOpReturn(txid)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.property(data, 'tokenType')
assert.property(data, 'txType')
assert.property(data, 'ticker')
assert.property(data, 'name')
assert.property(data, 'tokenId')
assert.property(data, 'documentUri')
assert.property(data, 'documentHash')
assert.property(data, 'decimals')
assert.property(data, 'mintBatonVout')
assert.property(data, 'qty')
assert.equal(data.tokenType, 65)
assert.equal(data.mintBatonVout, 0)
assert.equal(data.qty, '1')
})
// 429 means the user is exceeding the rate limits.
it('should throw error when axios returns 429 status', async () => {
try {
// Mock the call to the REST API
sandbox.stub(uut.Utils.axios, 'post').rejects(mockData.mock429Error)
const txid =
'a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415'
await uut.Utils.decodeOpReturn(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.fail('Unexpect result')
} catch (err) {
// console.log('err: ', err)
assert.property(err, 'message')
assert.property(err, 'response')
assert.equal(err.response.status, 429)
assert.equal(err.response.statusText, 'Too Many Requests')
assert.include(err.response.data.error, 'Too many requests')
}
})
// 503 means the service is down.
it('should throw error when axios returns 503 status', async () => {
try {
// Mock the call to the REST API
sandbox.stub(uut.Utils.axios, 'post').rejects(mockData.mock503Error)
const txid =
'a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415'
await uut.Utils.decodeOpReturn(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.fail('Unexpect result')
} catch (err) {
// console.log('err: ', err)
assert.property(err, 'message')
assert.property(err, 'response')
assert.equal(err.response.status, 503)
assert.equal(err.response.statusText, 'Service Unavailable')
assert.property(err.response, 'data')
}
})
})
describe('#_hydrateUtxo', () => {
// // This captures an important corner-case. When an SLP token is created, the
// // change UTXO will contain the same SLP txid, but it is not an SLP UTXO.
it('should return details on minting baton from genesis transaction', async () => {
// Mock the call to REST API
// sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
// Stub the calls to decodeOpReturn.
sandbox.stub(uut.Utils, 'decodeOpReturn').resolves({
tokenType: 1,
txType: 'GENESIS',
ticker: 'SLPSDK',
name: 'SLP SDK example using BITBOX',
tokenId:
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
documentUri: 'developer.bitcoin.com',
documentHash: '',
decimals: 8,
mintBatonVout: 2,
qty: '50700000000'
})
const utxos = [
{
txid:
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
vout: 3,
amount: 0.00002015,
satoshis: 2015,
height: 594892,
confirmations: 5
},
{
txid:
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
vout: 2,
amount: 0.00000546,
satoshis: 546,
height: 594892,
confirmations: 5
}
]
const data = await uut.Utils._hydrateUtxo(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
// assert.equal(data[0], false, "Change UTXO marked as false.")
assert.property(data[0], 'txid')
assert.property(data[0], 'vout')
assert.property(data[0], 'amount')
assert.property(data[0], 'satoshis')
assert.property(data[0], 'height')
assert.property(data[0], 'confirmations')
assert.property(data[0], 'isValid')
assert.equal(data[0].isValid, false)
assert.property(data[1], 'txid')
assert.property(data[1], 'vout')
assert.property(data[1], 'amount')
assert.property(data[1], 'satoshis')
assert.property(data[1], 'height')
assert.property(data[1], 'confirmations')
assert.property(data[1], 'utxoType')
assert.property(data[1], 'tokenId')
assert.property(data[1], 'tokenTicker')
assert.property(data[1], 'tokenName')
assert.property(data[1], 'tokenDocumentUrl')
assert.property(data[1], 'tokenDocumentHash')
assert.property(data[1], 'decimals')
})
// 429 means the user is exceeding the rate limits.
it('should return isValid=null for 429 rate limit error', async () => {
// Force decodeOpReturn() to throw a 429 error.
sandbox.stub(uut.Utils, 'decodeOpReturn').rejects(mockData.mock429Error)
const utxos = [
{
txid:
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
vout: 3,
amount: 0.00002015,
satoshis: 2015,
height: 594892,
confirmations: 5
},
{
txid:
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
vout: 2,
amount: 0.00000546,
satoshis: 546,
height: 594892,
confirmations: 5
}
]
const result = await uut.Utils._hydrateUtxo(utxos)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result[0].isValid, null)
assert.equal(result[1].isValid, null)
})
// 503 means the server is down or is not responding.
it('should return isValid=null for 503 rate limit error', async () => {
// Force decodeOpReturn() to throw a 429 error.
sandbox.stub(uut.Utils, 'decodeOpReturn').rejects(mockData.mock503Error)
const utxos = [
{
txid:
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
vout: 3,
amount: 0.00002015,
satoshis: 2015,
height: 594892,
confirmations: 5
},
{
txid:
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
vout: 2,
amount: 0.00000546,
satoshis: 546,
height: 594892,
confirmations: 5
}
]
const result = await uut.Utils._hydrateUtxo(utxos)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result[0].isValid, null)
assert.equal(result[1].isValid, null)
})
it('should return details for a simple SEND SLP token utxo', async () => {
// Mock the call to REST API
// Stub the calls to decodeOpReturn.
sandbox
.stub(uut.Utils, 'decodeOpReturn')
.onCall(0)
.resolves({
tokenType: 1,
txType: 'SEND',
tokenId:
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
amounts: ['200000000', '99887500000000']
})
.onCall(1)
.resolves({
tokenType: 1,
txType: 'GENESIS',
ticker: 'TOK-CH',
name: 'TokyoCash',
tokenId:
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
documentUri: '',
documentHash: '',
decimals: 8,
mintBatonVout: 0,
qty: '2100000000000000'
})
// sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
const utxos = [
{
txid:
'fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb',
vout: 1,
amount: 0.00000546,
satoshis: 546,
height: 596089,
confirmations: 748
}
]
const data = await uut.Utils._hydrateUtxo(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.property(data[0], 'txid')
assert.property(data[0], 'vout')
assert.property(data[0], 'amount')
assert.property(data[0], 'satoshis')
assert.property(data[0], 'height')
assert.property(data[0], 'confirmations')
assert.property(data[0], 'utxoType')
assert.property(data[0], 'tokenId')
assert.property(data[0], 'tokenTicker')
assert.property(data[0], 'tokenName')
assert.property(data[0], 'tokenDocumentUrl')
assert.property(data[0], 'tokenDocumentHash')
assert.property(data[0], 'decimals')
assert.property(data[0], 'tokenQty')
assert.property(data[0], 'isValid')
assert.equal(data[0].isValid, null)
})
// I don't know if this is the ideal behavior, but this is the behavior
// that is in production, so I wanted to capture it in a test case. This
// behavior can always be changed in the future.
it('should throw error if 429 when querying Genesis transaction', async () => {
try {
// Mock the call to REST API
// Stub the calls to decodeOpReturn.
sandbox
.stub(uut.Utils, 'decodeOpReturn')
.onCall(0)
.resolves({
tokenType: 1,
txType: 'SEND',
tokenId:
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
amounts: ['200000000', '99887500000000']
})
.onCall(1)
.rejects(mockData.mock429Error)
const utxos = [
{
txid:
'fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb',
vout: 1,
amount: 0.00000546,
satoshis: 546,
height: 596089,
confirmations: 748
}
]
await uut.Utils._hydrateUtxo(utxos)
assert.fail('Unexpected result')
} catch (err) {
// console.log('error: ', err)
assert.property(err, 'message')
assert.property(err, 'response')
assert.equal(err.response.status, 429)
assert.equal(err.response.statusText, 'Too Many Requests')
assert.include(err.response.data.error, 'Too many requests')
}
})
it('should add delay if delay is specified', async () => {
// Mock the call to REST API
// Stub the calls to decodeOpReturn.
sandbox
.stub(uut.Utils, 'decodeOpReturn')
.onCall(0)
.resolves({
tokenType: 1,
txType: 'SEND',
tokenId:
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
amounts: ['200000000', '99887500000000']
})
.onCall(1)
.resolves({
tokenType: 1,
txType: 'GENESIS',
ticker: 'TOK-CH',
name: 'TokyoCash',
tokenId:
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
documentUri: '',
documentHash: '',
decimals: 8,
mintBatonVout: 0,
qty: '2100000000000000'
})
// sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
const utxos = [
{
txid:
'fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb',
vout: 1,
amount: 0.00000546,
satoshis: 546,
height: 596089,
confirmations: 748
}
]
const usrObj = {
utxoDelay: 100
}
await uut.Utils._hydrateUtxo(utxos, usrObj)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
// TODO: This test should realy assert that the test took at least 100mS
// to complete. However, as-is, it exercises the code path, so not
// throwing an error can be considered a pass.
assert.equal(true, true)
})
})
describe('#tokenUtxoDetails', () => {
+119
View File
@@ -0,0 +1,119 @@
/*
Unit tests for the transaction.js library.
*/
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
const mockData = require('./fixtures/transaction-mock.js')
describe('#TransactionLib', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
describe('#get', () => {
it('should throw an error if txid is not specified', async () => {
try {
await bchjs.Transaction.get()
assert.fail('Unexpected code path!')
} catch (err) {
assert.include(
err.message,
'Input must be a string or array of strings.'
)
}
})
it('should get details about a non-SLP transaction', async () => {
const txid =
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7'
// Mock dependencies
sandbox
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
.resolves(mockData.nonSlpTxDetails)
const result = await bchjs.Transaction.get(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Assert that there are stanardized properties.
assert.property(result, 'txid')
assert.property(result, 'vin')
assert.property(result, 'vout')
assert.property(result.vout[0], 'value')
assert.property(result.vout[0].scriptPubKey, 'addresses')
// Assert that added properties exist.
assert.property(result.vin[0], 'address')
assert.property(result.vin[0], 'value')
assert.property(result, 'isValidSLPTx')
assert.equal(result.isValidSLPTx, false)
})
it('should get details about a SLP transaction', async () => {
// Mock dependencies
sandbox
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
.resolves(mockData.slpTxDetails)
sandbox
.stub(bchjs.Transaction.slpUtils, 'decodeOpReturn')
.onCall(0)
.resolves(mockData.mockOpReturnData01)
.onCall(1)
.resolves(mockData.mockOpReturnData02)
.onCall(2)
.resolves(mockData.mockOpReturnData03)
.onCall(3)
.rejects(new Error('No OP_RETURN'))
sandbox
.stub(bchjs.Transaction.slpUtils, 'waterfallValidateTxid')
.resolves(true)
const txid =
'266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1'
const result = await bchjs.Transaction.get(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Assert that there are stanardized properties.
assert.property(result, 'txid')
assert.property(result, 'vin')
assert.property(result, 'vout')
assert.property(result.vout[0], 'value')
assert.property(result.vout[1].scriptPubKey, 'addresses')
// Assert that added properties exist.
assert.property(result.vout[0], 'tokenQty')
assert.equal(result.vout[0].tokenQty, null)
assert.property(result.vin[0], 'address')
assert.property(result.vin[0], 'value')
assert.property(result.vin[0], 'tokenQty')
assert.property(result, 'isValidSLPTx')
assert.equal(result.isValidSLPTx, true)
})
it('should catch and throw error on network error', async () => {
try {
const txid =
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7'
// Force an error
sandbox
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
.rejects(new Error('test error'))
await bchjs.Transaction.get(txid)
assert.fail('Unexpected code path')
} catch (err) {
assert.include(err.message, 'test error')
}
})
})
})