diff --git a/.babelrc b/.babelrc deleted file mode 100644 index f65644ac..00000000 --- a/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["flow", "es2015"] -} diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000..9b0b426a --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,55 @@ +{ + "root": true, + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "plugins": ["prettier"], + "rules": { + "no-debugger": ["warn"], + "no-regex-spaces": ["error"], + "no-unsafe-negation": ["error"], + "curly": ["error", "multi-or-nest", "consistent"], + "dot-location": ["error", "property"], + "dot-notation": ["error"], + "eqeqeq": ["error", "smart"], + "no-else-return": ["error"], + "no-extra-bind": ["error"], + "no-extra-label": ["error"], + "no-floating-decimal": ["error"], + "no-implicit-coercion": ["error", { "allow": ["!!"] }], + "wrap-iife": ["error", "inside"], + "strict": ["error", "global"], + "func-call-spacing": ["error", "never"], + "comma-style": ["error", "last"], + "keyword-spacing": ["error"], + "linebreak-style": ["error", "unix"], + "new-parens": ["error"], + "no-lonely-if": ["error"], + "no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1 }], + "no-whitespace-before-property": ["error"], + "semi": ["error", "never"], + "arrow-body-style": ["error", "as-needed"], + "arrow-parens": ["error", "as-needed"], + "arrow-spacing": ["error"], + "no-useless-computed-key": ["error"], + "no-useless-rename": ["error"], + "no-var": ["off"], + "prefer-spread": ["off"], + "prefer-template": ["error"], + "rest-spread-spacing": ["error", "never"], + "prefer-const": ["warn", { "destructuring": "all" }], + "no-unreachable": ["warn"], + "no-unused-vars": ["warn", { "args": "none" }], + + "prettier/prettier": [ + "warn", + { + "printWidth": 80, + "trailingComma": "none", + "singleQuote": false, + "semi": false + } + ] + } +} diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index 1fed4453..00000000 --- a/.flowconfig +++ /dev/null @@ -1,11 +0,0 @@ -[ignore] - -[include] - -[libs] - -[lints] - -[options] - -[strict] diff --git a/.gitignore b/.gitignore index 7bfff5eb..954c3821 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,18 @@ node_modules/* .nyc_output/* +wallet-info.txt +wallet.json + +package-lock.json +# yarn-lock.json + +# production +/dist +index.js +index.js.map +lib/**/*.js +lib/**/*.js.map +test/**/*.js +test/**/*.js.map + +coverage/ \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..f487f993 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v10.5.3 diff --git a/.nycrc b/.nycrc new file mode 100644 index 00000000..8c07fc31 --- /dev/null +++ b/.nycrc @@ -0,0 +1,4 @@ +{ + "extends": "@istanbuljs/nyc-config-typescript", + "reporter": ["html", "text"] +} \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..dceda2d7 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "semi": false +} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..1bcca6bf --- /dev/null +++ b/.travis.yml @@ -0,0 +1,31 @@ +# This is a node.js v8+ JavaScript project +language: node_js +node_js: + - "10" + +# Build on Ubuntu Xenial (16.04) +# https://docs.travis-ci.com/user/reference/trusty/#javascript-and-nodejs-images +dist: xenial +sudo: required + +# Use Docker +services: + - docker + +before_script: + - npm install -g tsc + - npm run build + #- ./install-mongo + +# https://github.com/greenkeeperio/greenkeeper-lockfile/issues/156 +# install: case $TRAVIS_BRANCH in greenkeeper*) npm i;; *) npm ci;; esac; + +# Send coverage data to Coveralls +after_success: + - npm run coverage + +deploy: + provider: script + skip_cleanup: true + script: + - npx semantic-release diff --git a/LICENSE.md b/LICENSE.md index 3ddbf354..75dafe08 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -2,6 +2,6 @@ Copyright 2018 Carlos Gabriel Cardona Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 033b4bc4..161c0da4 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,58 @@ -# `bitbox-cli` +# BITBOX SDK -## Command line tool for https://www.bitbox.earth +`bitbox-sdk` is a utility for creating great [Bitcoin Cash](https://www.bitcoincash.org) applications. It can be used from the command line or from within client/server apps. -`bitbox-cli` is a utility for creating great [Bitcoin Cash](https://www.bitcoincash.org) applications. If can be used from the command line or from within client/server apps. +Extensive documentation available [in the docs directory](/docs): -Extensive documentation available at: - -* [General docs](https://www.bitbox.earth/docs/gettingstarted) -* [BITBOX API](https://www.bitbox.earth/bitboxcli/bitcoincash) -* [BITBLOG](https://bigearth.github.io/bitblog/) +- [Getting Started](/docs/getting-started.md) +- [New](/docs/new.md) +- [BITBOX Examples](/examples) +- [Console](/docs/console.md) +- [Address](/docs/address.md) +- [BitcoinCash](/docs/bitcoincash.md) +- [BitDB](/docs/bitdb.md) +- [Block](/docs/block.md) +- [Blockchain](/docs/blockchain.md) +- [CashAccounts](/docs/cashAccounts.md) +- [Control](/docs/control.md) +- [Crypto](/docs/crypto.md) +- [ECPair](/docs/ecpair.md) +- [HDNode](/docs/hdnode.md) +- [Mining](/docs/mining.md) +- [Mnemonic](/docs/mnemonic.md) +- [OpCodes](/docs/OpCodes.md) +- [Price](/docs/price.md) +- [RawTransactions](/docs/rawtransactions.md) +- [Schnorr](/docs/schnorr.md) +- [Script](/docs/script.md) +- [Socket](/docs/socket.md) +- [Transaction](/docs/transaction.md) +- [TransactionBuilder](/docs/transactionBuilder.md) +- [Util](/docs/util.md) Open Source / Creative Commons Listings -* [assert](https://www.npmjs.com/package/assert) - MIT -* [axios](https://github.com/axios/axios) - MIT -* [babel](https://babeljs.io/docs/setup/) - MIT -* [bchaddrjs](https://github.com/bitcoincashjs/bchaddrjs/blob/master/LICENSE) - mit -* [bigi](https://www.npmjs.com/package/bigi) - none -* [bip21](https://github.com/bigearth/bip21) - ISC -* [bip39](https://github.com/bitcoinjs/bip39/blob/master/LICENSE) - ISC -* [bitcoin-ops](https://github.com/bigearth/bitcoin-ops) - MIT -* [bitcoinjs-lib](https://github.com/bigearth/bitcoinjs-lib) - MIT -* [bitcoinjs-message](https://github.com/bitcoinjs/bitcoinjs-message) - MIT -* [bs58](https://www.npmjs.com/package/bs58) - MIT -* [buffer](https://www.npmjs.com/package/buffer) - MIT -* [chai](https://www.npmjs.com/package/chai) - MIT -* [chalk](https://www.npmjs.com/package/chalk) - MIT -* [clear](https://www.npmjs.com/package/clear) - none -* [commander](https://www.npmjs.com/package/commander) - MIT -* [corsproxy](https://www.npmjs.com/package/corsproxy) - MIT -* [cp-file](https://www.npmjs.com/package/cp-file) - MIT -* [ecurve](https://www.npmjs.com/package/ecurve) - MIT -* [figlet](https://www.npmjs.com/package/figlet) - MIT -* [flow-bin](https://www.npmjs.com/package/flow-bin) - MIT -* [git-clone](https://www.npmjs.com/package/git-clone) - ICS -* [ini](https://www.npmjs.com/package/ini) - ICS -* [mkdirp](https://www.npmjs.com/package/mkdirp) - MIT -* [mocha](https://www.npmjs.com/package/mocha) - MIT -* [node-cmd](https://www.npmjs.com/package/node-cmd) - DBAD -* [node-emoji](https://www.npmjs.com/package/node-emoji) - MIT -* [nyc](https://www.npmjs.com/package/nyc) - ICS -* [qrcode](https://www.npmjs.com/package/qrcode) - MIT -* [randombytes](https://www.npmjs.com/package/randombytes) - MIT -* [safe-buffer](https://www.npmjs.com/package/safe-buffer) - MIT -* [satoshi-bitcoin](https://www.npmjs.com/package/satoshi-bitcoin) - MIT -* [sinon](https://www.npmjs.com/package/sinon) - BSD-3-Clause -* [touch](https://www.npmjs.com/package/touch) - ISC +- [assert](https://www.npmjs.com/package/assert) - MIT +- [axios](https://github.com/axios/axios) - MIT +- [babel](https://babeljs.io/docs/setup/) - MIT +- [bigi](https://www.npmjs.com/package/bigi) - none +- [bip21](https://github.com/bigearth/bip21) - ISC +- [bip39](https://github.com/bitcoinjs/bip39/blob/master/LICENSE) - ISC +- [bitcoincash-ops](https://github.com/bitcoin-com/bitcoincash-ops) - MIT +- [bitcoinjs-lib](https://github.com/bigearth/bitcoinjs-lib) - MIT +- [bitcoinjs-message](https://github.com/bitcoinjs/bitcoinjs-message) - MIT +- [bs58](https://www.npmjs.com/package/bs58) - MIT +- [buffer](https://www.npmjs.com/package/buffer) - MIT +- [cashaddrjs](https://github.com/bitcoincashjs/cashaddrjs/blob/master/LICENSE) - MIT +- [chai](https://www.npmjs.com/package/chai) - MIT +- [mocha](https://www.npmjs.com/package/mocha) - MIT +- [nyc](https://www.npmjs.com/package/nyc) - ICS +- [qrcode](https://www.npmjs.com/package/qrcode) - MIT +- [randombytes](https://www.npmjs.com/package/randombytes) - MIT +- [safe-buffer](https://www.npmjs.com/package/safe-buffer) - MIT +- [satoshi-bitcoin](https://www.npmjs.com/package/satoshi-bitcoin) - MIT +- [sinon](https://www.npmjs.com/package/sinon) - BSD-3-Clause + +## Font awesome + +[Cube icon](https://fontawesome.com/icons/cube?style=solid) available under [CC v4.0](https://creativecommons.org/licenses/by/4.0/) diff --git a/docs/OpCodes.md b/docs/OpCodes.md new file mode 100644 index 00000000..df9034d3 --- /dev/null +++ b/docs/OpCodes.md @@ -0,0 +1,178 @@ +# OpCodes + +Bitcoin Cash Script OP Codes are available on the `bitbox.Script` object. + +#### Examples + + // list all op codes + bitbox.Script.opcodes; + // { OP_FALSE: 0, + // OP_0: 0, + // OP_PUSHDATA1: 76, + // OP_PUSHDATA2: 77, + // OP_PUSHDATA4: 78, + // OP_1NEGATE: 79, + // OP_RESERVED: 80, + // OP_TRUE: 81, + // OP_1: 81, + // OP_2: 82, + // OP_3: 83, + // OP_4: 84, + // ... + // } + + // get the op code for a word + bitbox.Script.opcodes.OP_SPLIT + // 127 + bitbox.Script.opcodes.OP_NUM2BIN + // 128 + bitbox.Script.opcodes.OP_BIN2NUM + // 129 + +### Constants + +| Word | Opcode | Hex | Inputs | Outputs | Description | +| ------------ | ------ | --------- | --------- | ------------- | ------------------------------------------------------------------------------------------------------- | +| OP_0 | 0 | 0x00 | Nothing | (empty value) | An empty array of bytes is pushed onto the stack. (This is not a no-op: an item is added to the stack.) | +| OP_FALSE | 0 | 0x00 | Nothing | (empty value) | An empty array of bytes is pushed onto the stack. (This is not a no-op: an item is added to the stack.) | +| N/A | 1-75 | 0x01-0x4b | (special) | data | The next opcode bytes is data to be pushed onto the stack | +| OP_PUSHDATA1 | 76 | 0x4c | (special) | data | The next byte contains the number of bytes to be pushed onto the stack. | +| OP_PUSHDATA2 | 77 | 0x4d | (special) | data | The next two bytes contain the number of bytes to be pushed onto the stack in little endian order. | +| OP_PUSHDATA4 | 78 | 0x4e | (special) | data | The next four bytes contain the number of bytes to be pushed onto the stack in little endian order. | +| OP_1NEGATE | 79 | 0x4f | Nothing. | -1 | The number -1 is pushed onto the stack. | +| OP_TRUE | 81 | 0x51 | Nothing. | | The number 1 is pushed onto the stack. | +| OP_1 | 81 | 0x51 | Nothing. | | The number 1 is pushed onto the stack. | +| OP_2-OP_16 | 82-96 | 0x52-0x60 | Nothing. | 2-16 | The number in the word name (2-16) is pushed onto the stack. | + +### Flow control + +| Word | Opcode | Hex | Inputs | Outputs | Description | +| --------- | ------ | ---- | --------------------------------------------------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| OP_NOP | 97 | 0x61 | Nothing | Nothing | Does nothing. | +| OP_IF | 99 | 0x63 | if [statements]else [statements]]\* endif | if [statements]else [statements]]\* endif | If the top stack value is not False, the statements are executed. The top stack value is removed. | +| OP_NOTIF | 100 | 0x64 | notif [statements]else [statements]]\* endif | notif [statements]else [statements]]\* endif | If the top stack value is False, the statements are executed. The top stack value is removed. | +| OP_ELSE | 103 | 0x67 | if [statements]else [statements]]\* endif | if [statements]else [statements]]\* endif | If the preceding OP_IF or OP_NOTIF or OP_ELSE was not executed then these statements are and if the preceding OP_IF or OP_NOTIF or OP_ELSE was executed then these statements are not. | +| OP_ENDIF | 104 | 0x68 | if [statements]else [statements]]\* endif | if [statements]else [statements]]\* endif | Ends an if/else block. All blocks must end, or the transaction is invalid. An OP_ENDIF without OP_IF earlier is also invalid. | +| OP_VERIFY | 105 | 0x69 | True / false | Nothing / fail | Marks transaction as invalid if top stack value is not true. The top stack value is removed. | +| OP_RETURN | 106 | 0x6a | Nothing | fail | Marks transaction as invalid. | + +### Stack + +| Word | Opcode | Hex | Inputs | Outputs | Description | +| --------------- | ------ | ---- | ------------------- | ------------------ | -------------------------------------------------------------------------------------- | +| OP_TOALTSTACK | 107 | 0x6b | x1 | (alt)x1 | Puts the input onto the top of the alt stack. Removes it from the main stack. | +| OP_FROMALTSTACK | 108 | 0x6c | (alt)x1 | x1 | Puts the input onto the top of the main stack. Removes it from the alt stack. | +| OP_IFDUP | 115 | 0x73 | x | x / x x | If the top stack value is not 0, duplicate it. | +| OP_DEPTH | 116 | 0x74 | Nothing | | Puts the number of stack items onto the stack. | +| OP_DROP | 117 | 0x75 | x | Nothing | Removes the top stack item. | +| OP_DUP | 118 | 0x76 | x | x x | Duplicates the top stack item. | +| OP_NIP | 119 | 0x77 | x1 x2 | x2 | Removes the second-to-top stack item. | +| OP_OVER | 120 | 0x78 | x1 x2 | x1 x2 x1 | Copies the second-to-top stack item to the top. | +| OP_PICK | 121 | 0x79 | xn ... x2 x1 x0 | xn ... x2 x1 x0 xn | The item n back in the stack is copied to the top. | +| OP_ROLL | 122 | 0x7a | xn ... x2 x1 x0 | ... x2 x1 x0 xn | The item n back in the stack is moved to the top. | +| OP_ROT | 123 | 0x7b | x1 x2 x3 | x2 x3 x1 | The top three items on the stack are rotated to the left. | +| OP_SWAP | 124 | 0x7c | x1 x2 | x2 x1 | The top two items on the stack are swapped. | +| OP_TUCK | 125 | 0x7d | x1 x2 | x2 x1 x2 | The item at the top of the stack is copied and inserted before the second-to-top item. | +| OP_2DROP | 109 | 0x6d | x1 x2 | Nothing | Removes the top two stack items. | +| OP_2DUP | 110 | 0x6e | x1 x2 | x1 x2 x1 x2 | Duplicates the top two stack items. | +| OP_3DUP | 111 | 0x6f | x1 x2 x3 | x1 x2 x3 x1 x2 x3 | Duplicates the top three stack items. | +| OP_2OVER | 112 | 0x70 | x1 x2 x3 x4 | x1 x2 x3 x4 x1 x2 | Copies the pair of items two spaces back in the stack to the front. | +| OP_2ROT | 113 | 0x71 | x1 x2 x3 x4 x5 x6 | x3 x4 x5 x6 x1 x2 | The fifth and sixth items back are moved to the top of the stack. | +| OP_2SWAP | 114 | 0x72 | x1 x2 x3 x4 | x3 x4 x1 x2 | Swaps the top two pairs of items. | + +### Splice + +| Word | Opcode | Hex | Inputs | Outputs | Description | +| --------- | ------ | ---- | ------------- | ------- | ------------------------------------------------------------------------------ | +| OP_CAT | 126 | 0x7e | x1 x2 | out | Concatenates two strings | +| OP_SUBSTR | 127 | 0x7f | in begin size | out | Returns a section of a string | +| OP_LEFT | 128 | 0x80 | in size | out | Keeps only characters left of the specified point in a string. | +| OP_RIGHT | 129 | 0x81 | in size | out | Keeps only characters right of the specified point in a string. | +| OP_SIZE | 130 | 0x82 | in | in size | Pushes the string length of the top element of the stack (without popping it). | + +### Bitwise logic + +| Word | Opcode | Hex | Inputs | Outputs | Description | +| -------------- | ------ | ---- | ------ | -------------- | ------------------------------------------------------- | +| OP_INVERT | 131 | 0x83 | in | out | Flips all of the bits in the input. | +| OP_AND | 132 | 0x84 | x1 x2 | out | Boolean and between each bit in the inputs. | +| OP_OR | 133 | 0x85 | x1 x2 | out | Boolean or between each bit in the inputs. | +| OP_XOR | 134 | 0x86 | x1 x2 | out | Boolean exclusive or between each bit in the inputs. | +| OP_EQUAL | 135 | 0x87 | x1 x2 | True / false | Returns 1 if the inputs are exactly equal, 0 otherwise. | +| OP_EQUALVERIFY | 136 | 0x88 | x1 x2 | Nothing / fail | Same as OP_EQUAL, but runs OP_VERIFY afterward. | + +### Arithmetic + +| Word | Opcode | Hex | Inputs | Outputs | Description | +| --------------------- | ------ | ---- | --------- | -------------- | --------------------------------------------------------------------------- | +| OP_1ADD | 139 | 0x8b | in | out | 1 is added to the input. | +| OP_1SUB | 140 | 0x8c | in | out | 1 is subtracted from the input. | +| OP_2MUL | 141 | 0x8d | in | out | The input is multiplied by 2. | +| OP_2DIV | 142 | 0x8e | in | out | The input is divided by 2. | +| OP_NEGATE | 143 | 0x8f | in | out | The sign of the input is flipped. | +| OP_ABS | 144 | 0x90 | in | out | The input is made positive. | +| OP_NOT | 145 | 0x91 | in | out | If the input is 0 or 1, it is flipped. Otherwise the output will be 0. | +| OP_0NOTEQUAL | 146 | 0x92 | in | out | Returns 0 if the input is 0. 1 otherwise. | +| OP_ADD | 147 | 0x93 | a b | out | a is added to b. | +| OP_SUB | 148 | 0x94 | a b | out | b is subtracted from a. | +| OP_MUL | 149 | 0x95 | a b | out | a is multiplied by b. | +| OP_DIV | 150 | 0x96 | a b | out | a is divided by b. | +| OP_MOD | 151 | 0x97 | a b | out | Returns the remainder after dividing a by b. | +| OP_LSHIFT | 152 | 0x98 | a b | out | Shifts a left b bits, preserving sign. | +| OP_RSHIFT | 153 | 0x99 | a b | out | Shifts a right b bits, preserving sign. | +| OP_BOOLAND | 154 | 0x9a | a b | out | If both a and b are not "" (null string), the output is 1. Otherwise 0. | +| OP_BOOLOR | 155 | 0x9b | a b | out | If a or b is not "" (null string), the output is 1. Otherwise 0. | +| OP_NUMEQUAL | 156 | 0x9c | a b | out | Returns 1 if the numbers are equal, 0 otherwise. | +| OP_NUMEQUALVERIFY | 157 | 0x9d | a b | Nothing / fail | Same as OP_NUMEQUAL, but runs OP_VERIFY afterward. | +| OP_NUMNOTEQUAL | 158 | 0x9e | a b | out | Returns 1 if the numbers are not equal, 0 otherwise. | +| OP_LESSTHAN | 159 | 0x9f | a b | out | Returns 1 if a is less than b, 0 otherwise. | +| OP_GREATERTHAN | 160 | 0xa0 | a b | out | Returns 1 if a is greater than b, 0 otherwise. | +| OP_LESSTHANOREQUAL | 161 | 0xa1 | a b | out | Returns 1 if a is less than or equal to b, 0 otherwise. | +| OP_GREATERTHANOREQUAL | 162 | 0xa2 | a b | out | Returns 1 if a is greater than or equal to b, 0 otherwise. | +| OP_MIN | 163 | 0xa3 | a b | out | Returns the smaller of a and b. | +| OP_MAX | 164 | 0xa4 | a b | out | Returns the larger of a and b. | +| OP_WITHIN | 165 | 0xa5 | x min max | out | Returns 1 if x is within the specified range (left-inclusive), 0 otherwise. | + +### Crypto + +| Word | Opcode | Hex | Inputs | Outputs | Description | +| ---------------------- | ------ | ---- | ---------------------------------------------------------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| OP_RIPEMD160 | 166 | 0xa6 | in | hash | The input is hashed using RIPEMD-160. | +| OP_SHA1 | 167 | 0xa7 | in | hash | The input is hashed using SHA-1. | +| OP_SHA256 | 168 | 0xa8 | in | hash | The input is hashed using SHA-256. | +| OP_HASH160 | 169 | 0xa9 | in | hash | The input is hashed twice: first with SHA-256 and then with RIPEMD-160. | +| OP_HASH256 | 170 | 0xaa | in | hash | The input is hashed two times with SHA-256. | +| OP_CODESEPARATOR | 171 | 0xab | Nothing | Nothing | All of the signature checking words will only match signatures to the data after the most recently-executed OP_CODESEPARATOR. | +| OP_CHECKSIG | 172 | 0xac | sig pubkey | True / false | The entire transaction's outputs, inputs, and script (from the most recently-executed OP_CODESEPARATOR to the end) are hashed. The signature used by OP_CHECKSIG must be a valid signature for this hash and public key. If it is, 1 is returned, 0 otherwise. | +| OP_CHECKSIGVERIFY | 173 | 0xad | sig pubkey | Nothing / fail | Same as OP_CHECKSIG, but OP_VERIFY is executed afterward. | +| OP_CHECKMULTISIG | 174 | 0xae | x sig1 sig2 ... pub1 pub2 | True / False | Compares the first signature against each public key until it finds an ECDSA match. Starting with the subsequent public key, it compares the second signature against each remaining public key until it finds an ECDSA match. The process is repeated until all signatures have been checked or not enough public keys remain to produce a successful result. All signatures need to match a public key. Because public keys are not checked again if they fail any signature comparison, signatures must be placed in the scriptSig using the same order as their corresponding public keys were placed in the scriptPubKey or redeemScript. If all signatures are valid, 1 is returned, 0 otherwise. Due to a bug, one extra unused value is removed from the stack. | +| OP_CHECKMULTISIGVERIFY | 175 | 0xaf | x sig1 sig2 ... pub1 pub2 ... | Nothing / fail | Same as OP_CHECKMULTISIG, but OP_VERIFY is executed afterward. | + +### Locktime + +| Word | Opcode | Hex | Inputs | Outputs | Description | +| ---------------------- | ------ | ---- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| OP_CHECKLOCKTIMEVERIFY | 177 | 0xb1 | x | x / fail | Marks transaction as invalid if the top stack item is greater than the transaction's nLockTime field, otherwise script evaluation continues as though an OP_NOP was executed. Transaction is also invalid if 1. the stack is empty; or 2. the top stack item is negative; or 3. the top stack item is greater than or equal to 500000000 while the transaction's nLockTime field is less than 500000000, or vice versa; or 4. the input's nSequence field is equal to 0xffffffff. The precise semantics are described in BIP 0065. | +| OP_CHECKSEQUENCEVERIFY | 178 | 0xb2 | x | x / fail | Marks transaction as invalid if the relative lock time of the input (enforced by BIP 0068 with nSequence) is not equal to or longer than the value of the top stack item. The precise semantics are described in BIP 0112. | + +### Pseudo-words + +| Word | Opcode | Hex | Description | +| ---------------- | ------ | ---- | ---------------------------------------------------- | +| OP_PUBKEYHASH | 253 | 0xfd | Represents a public key hashed with OP_HASH160. | +| OP_PUBKEY | 254 | 0xfe | Represents a public key compatible with OP_CHECKSIG. | +| OP_INVALIDOPCODE | 255 | 0xff | Matches any opcode that is not yet assigned. | + +### Reserved words + +| Word | Opcode | Hex | When Used | +| ------------ | ------ | ---- | ----------------------------------------------------------------------- | +| OP_RESERVED | 80 | 0x50 | Transaction is invalid unless occuring in an unexecuted OP_IF branch | +| OP_VER | 98 | 0x62 | Transaction is invalid unless occuring in an unexecuted OP_IF branch | +| OP_VERIF | 101 | 0x65 | Transaction is invalid even when occuring in an unexecuted OP_IF branch | +| OP_VERNOTIF | 102 | 0x66 | Transaction is invalid even when occuring in an unexecuted OP_IF branch | +| OP_RESERVED1 | 137 | 0x89 | Transaction is invalid unless occuring in an unexecuted OP_IF branch | +| OP_RESERVED2 | 138 | 0x8a | Transaction is invalid unless occuring in an unexecuted OP_IF branch | +| OP_NOP1 | 176 | 0xb0 | The word is ignored. Does not mark transaction as invalid. | +| OP_NOP4 | 179 | 0xb3 | The word is ignored. Does not mark transaction as invalid. | +| OP_NOP10 | 185 | 0xb9 | The word is ignored. Does not mark transaction as invalid. | diff --git a/docs/address.md b/docs/address.md new file mode 100644 index 00000000..4862976e --- /dev/null +++ b/docs/address.md @@ -0,0 +1,1252 @@ +# Address + +### `toLegacyAddress` + +Converting cashaddr to legacy address format + +#### Arguments + +1. address `string` cashaddr address to be converted + +#### Result + +legacyAddress `string` legacy base 58 check encoded address + +#### Examples + + // mainnet w/ prefix + bitbox.Address.toLegacyAddress('bitcoincash:qzm47qz5ue99y9yl4aca7jnz7dwgdenl85jkfx3znl') + // 1HiaTupadqQN66Tvgt7QSE5Wg13BUy25eN + + // mainnet w/ no prefix + bitbox.Address.toLegacyAddress('qzm47qz5ue99y9yl4aca7jnz7dwgdenl85jkfx3znl') + // 1HiaTupadqQN66Tvgt7QSE5Wg13BUy25eN + + // testnet w/ prefix + bitbox.Address.toLegacyAddress('bchtest:qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // mqc1tmwY2368LLGktnePzEyPAsgADxbksi + + // testnet w/ no prefix + bitbox.Address.toLegacyAddress('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // mqc1tmwY2368LLGktnePzEyPAsgADxbksi + +### `toCashAddress` + +Converting legacy to cashAddress format + +#### Arguments + +1. address `string` required: legacy address to be converted +2. prefix `boolean` optional: include prefix +3. regtest `boolean` optional: return regtest address + +#### Result + +cashAddress `string` cashAddr encoded address + +#### Examples + + // mainnet + bitbox.Address.toCashAddress('1HiaTupadqQN66Tvgt7QSE5Wg13BUy25eN') + // bitcoincash:qzm47qz5ue99y9yl4aca7jnz7dwgdenl85jkfx3znl + + // mainnet no prefix + bitbox.Address.toCashAddress('1HiaTupadqQN66Tvgt7QSE5Wg13BUy25eN', false) + // qzm47qz5ue99y9yl4aca7jnz7dwgdenl85jkfx3znl + + // tesnet + bitbox.Address.toCashAddress('msDbtTj7kWXPpYaR7PQmMK84i66fJqQMLx') + // bchtest:qzq9je6pntpva3wf6scr7mlnycr54sjgeqxgrr9ku3 + + // testnet no prefix + bitbox.Address.toCashAddress('msDbtTj7kWXPpYaR7PQmMK84i66fJqQMLx', false) + // qzq9je6pntpva3wf6scr7mlnycr54sjgeqxgrr9ku3 + +### `isLegacyAddress` + +Detect if legacy base58check encoded address + +#### Arguments + +1. address `string`: address to determine + +#### Result + +isLegacyAddress `boolean`: true/false if legacy address + +#### Examples + + // cashaddr + bitbox.Address.isLegacyAddress('bitcoincash:qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // false + + // w/ no cashaddr prefix + bitbox.Address.isLegacyAddress('qzm47qz5ue99y9yl4aca7jnz7dwgdenl85jkfx3znl') + // false + + // legacy + bitbox.Address.isLegacyAddress('1HiaTupadqQN66Tvgt7QSE5Wg13BUy25eN') + // true + + // testnet w/ cashaddr prefix + bitbox.Address.isLegacyAddress('bchtest:qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // false + + // testnet w/ no cashaddr prefix + bitbox.Address.isLegacyAddress('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // false + + // legacy testnet + bitbox.Address.isLegacyAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi') + // true + +### `isCashAddress` + +Detect if cashAddr encoded address + +#### Arguments + +1. address `string`: address to determine + +#### Result + +isCashAddress `boolean`: true/false if cashaddress + +#### Examples + + // mainnet cashaddr + bitbox.Address.isCashAddress('bitcoincash:qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // true + + // mainnet w/ no cashaddr prefix + bitbox.Address.isCashAddress('qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // true + + // mainnet legacy + bitbox.Address.isCashAddress('18HEMuar5ZhXDFep1gEiY1eoPPcBLxfDxj') + // false + + // testnet w/ cashaddr prefix + bitbox.Address.isCashAddress('bchtest:qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // true + + // testnet w/ no cashaddr prefix + bitbox.Address.isCashAddress('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // true + + // testnet legacy + bitbox.Address.isCashAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi') + // false + +### `isMainnetAddress` + +Detect if mainnet address + +#### Arguments + +1. address `string`: address to determine + +#### Result + +isMainnetAddress `boolean`: true/false if mainnet address + +#### Examples + + // mainnet cashaddr + bitbox.Address.isMainnetAddress('bitcoincash:qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // true + + // mainnet cashaddr w/ no prefix + bitbox.Address.isMainnetAddress('qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // true + + // mainnet legacy + bitbox.Address.isMainnetAddress('14krEkSaKoTkbFT9iUCfUYARo4EXA8co6M') + // true + + // testnet cashaddr + bitbox.Address.isMainnetAddress('bchtest:qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // false + + // testnet w/ no cashaddr prefix + bitbox.Address.isMainnetAddress('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // false + + // testnet legacy + bitbox.Address.isMainnetAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi') + // false + +### `isTestnetAddress` + +Detect if testnet address + +#### Arguments + +1. addresss `string`: address to determine + +#### Result + +isTestnetAddresss `boolean`: true/false if is testnet address + +#### Examples + + // cashaddr mainnet + bitbox.Address.isTestnetAddress('bitcoincash:qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + //false + + // w/ no cashaddr prefix + bitbox.Address.isTestnetAddress('qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // false + + // legacy mainnet + bitbox.Address.isTestnetAddress('14krEkSaKoTkbFT9iUCfUYARo4EXA8co6M') + // false + + // cashaddr testnet + bitbox.Address.isTestnetAddress('bchtest:qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // true + + // testnet w/ no cashaddr prefix + bitbox.Address.isTestnetAddress('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // true + + // testnet legacy + bitbox.Address.isTestnetAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi') + // true + +### `isRegTestAddress` + +Detect if regtest address + +#### Arguments + +1. addresss `string`: address to determine + +#### Result + +isRegtestAddresss `boolean`: true/false if is regtest address + +#### Examples + + // regtest + bitbox.Address.isRegTestAddress('bchreg:qzq9je6pntpva3wf6scr7mlnycr54sjgequ54zx9lh') + // true + + // regtest w/ no prefix + bitbox.Address.isRegTestAddress('qzq9je6pntpva3wf6scr7mlnycr54sjgequ54zx9lh') + // true + + // cashaddr mainnet + bitbox.Address.isRegTestAddress('bitcoincash:qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + //false + + // w/ no cashaddr prefix + bitbox.Address.isRegTestAddress('qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // false + + // legacy mainnet + bitbox.Address.isRegTestAddress('14krEkSaKoTkbFT9iUCfUYARo4EXA8co6M') + // false + + // cashaddr testnet + bitbox.Address.isRegTestAddress('bchtest:qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // false + + // testnet w/ no cashaddr prefix + bitbox.Address.isRegTestAddress('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // false + +### `isP2PKHAddress` + +Detect if p2pkh address + +#### Arguments + +1. address `string` address to determine + +#### Result + +isP2PKHAddress `boolean` true/false if is p2pkh address + +#### Examples + + // cashaddr + bitbox.Address.isP2PKHAddress('bitcoincash:qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // true + + // w/ no cashaddr prefix + bitbox.Address.isP2PKHAddress('qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // true + + // legacy + bitbox.Address.isP2PKHAddress('14krEkSaKoTkbFT9iUCfUYARo4EXA8co6M') + // true + + // legacy testnet + bitbox.Address.isP2PKHAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi') + // true + + // testnet w/ no cashaddr prefix + bitbox.Address.isP2PKHAddress('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // true + + // legacy testnet + bitbox.Address.isP2PKHAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi') + // true + +### `isP2SHAddress` + +Detect if p2sh address + +#### arguments + +1. address `string` address to determine + +#### Result + +isP2SHAddress `boolean` true/false if is p2sh address + +#### Examples + + // cashaddr + bitbox.Address.isP2SHAddress('bitcoincash:qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // false + + // cashaddr w/ no prefix + bitbox.Address.isP2SHAddress('qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // false + + // legacy + bitbox.Address.isP2SHAddress('1NoYQso5UF6XqC4NbjKAp2EnjJ59yLNn74') + // false + + // cashaddr testnet + bitbox.Address.isP2SHAddress('bchtest:qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // false + + // cashaddr testnet w/ no prefix + bitbox.Address.isP2SHAddress('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // false + + // legacy testnet + bitbox.Address.isP2SHAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi') + // false + +### `detectAddressFormat` + +Detect address format + +#### arguments + +1. address `string` address to determine format + +#### Result + +addressFormat `string` address format + +#### Examples + + // cashaddr + bitbox.Address.detectAddressFormat('bitcoincash:qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // cashaddr + + // cashaddr w/ no prefix + bitbox.Address.detectAddressFormat('qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // cashaddr + + // legacy + bitbox.Address.detectAddressFormat('1NoYQso5UF6XqC4NbjKAp2EnjJ59yLNn74') + // legacy + + // cashaddr testnet + bitbox.Address.detectAddressFormat('bchtest:qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // cashaddr + + // cashaddr testnet w/ no prefix + bitbox.Address.detectAddressFormat('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // cashaddr + + // legacy testnet + bitbox.Address.detectAddressFormat('mqc1tmwY2368LLGktnePzEyPAsgADxbksi') + // legacy + +### `detectAddressNetwork` + +Detect address network + +#### arguments + +1. address `string` address to determine network + +#### Result + +addressNetwork `string` address network + +#### Examples + + // cashaddr + bitbox.Address.detectAddressNetwork('bitcoincash:qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // mainnet + + // cashaddr w/ no prefix + bitbox.Address.detectAddressNetwork('qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s') + // mainnet + + // legacy + bitbox.Address.detectAddressNetwork('1NoYQso5UF6XqC4NbjKAp2EnjJ59yLNn74') + // mainnet + + // cashaddr testnet + bitbox.Address.detectAddressNetwork('bchtest:qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // testnet + + // cashaddr testnet w/ no prefix + bitbox.Address.detectAddressNetwork('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy') + // testnet + + // legacy testnet + bitbox.Address.detectAddressNetwork('mqc1tmwY2368LLGktnePzEyPAsgADxbksi') + // testnet + +### `detectAddressType` + +Detect address network + +#### arguments + +1. address `string` address to determine network + +#### Result + +addressNetwork `string` address network + +#### Examples + + // cashaddr + bitbox.Address.detectAddressType('bitcoincash:qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s'); + // p2pkh + + // cashaddr w/ no prefix + bitbox.Address.detectAddressType('qqfx3wcg8ts09mt5l3zey06wenapyfqq2qrcyj5x0s'); + // p2pkh + + // legacy + bitbox.Address.detectAddressType('1NoYQso5UF6XqC4NbjKAp2EnjJ59yLNn74'); + // p2pkh + + // cashaddr testnet + bitbox.Address.detectAddressType('bchtest:qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy'); + // p2pkh + + // cashaddr testnet w/ no prefix + bitbox.Address.detectAddressType('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy'); + // p2pkh + + // legacy testnet + bitbox.Address.detectAddressType('mqc1tmwY2368LLGktnePzEyPAsgADxbksi'); + // p2pkh + +### `fromXPub` + +Generates an address for an extended public key (xpub) + +#### Arguments + +1. xpub `string`: extended public key to be used +2. path `string` **optional**: derivation path of external change address. Default is `0/0` + +#### Result + +changeAddress `string`: cashaddr encoded change address + +#### Examples + + // generate 5 mainnet external change addresses for xpub6DTNmB7gWa8RtQAfmy8wSDikM5mky4fhsnqQd9AqoCaLcekqNgRZW5JCSXwXkLDkABHTD1qx7kqrbGzT6xBGfAvCJSj2rwvKWP8eZBR2EVA + let xpub = 'xpub6DTNmB7gWa8RtQAfmy8wSDikM5mky4fhsnqQd9AqoCaLcekqNgRZW5JCSXwXkLDkABHTD1qx7kqrbGzT6xBGfAvCJSj2rwvKWP8eZBR2EVA'; + for(let i = 0; i <= 4; i++) { + console.log(bitbox.Address.fromXPub(xpub, "0/" + i)) + } + // bitcoincash:qptnmya5wkly7xf97wm5ak23yqdsz3l2cyj7k9vyyh + // bitcoincash:qrr2suh9yjsrkl2qp3p967uhfg6u0r6xxsn9h5vuvr + // bitcoincash:qpkfg4kck99wksyss6nvaqtafeahfnyrpsj0ed372t + // bitcoincash:qppgmuuwy07g0x39sx2z0x2u8e34tvfdxvy0c2jvx7 + // bitcoincash:qryj8x4s7vfsc864jm0xaak9qfe8qgk245y9ska57l + + // generate 5 testnet external change addresses for tpubDCrnMSKwDMAbxg82yqDt97peMvftCXk3EfBb9WgZh27mPbHGkysU3TW7qX5AwydmnVQfaGeNhUR6okQ3dS5AJTP9gEP7jk2Wcj6Xntc6gNh + let xpub = 'tpubDCrnMSKwDMAbxg82yqDt97peMvftCXk3EfBb9WgZh27mPbHGkysU3TW7qX5AwydmnVQfaGeNhUR6okQ3dS5AJTP9gEP7jk2Wcj6Xntc6gNh'; + for(let i = 0; i <= 4; i++) { + console.log(bitbox.Address.fromXPub(xpub, "0/" + i)) + } + // bchtest:qrth8470sc9scek9u0jj2d0349t62gxzdstw2jukl8 + // bchtest:qpm56zc5re0nhms96r7p985aajthp0vxvg6e4ux3kc + // bchtest:qqtu3tf6yyd73ejhk3a2ylqynpl3mzzhwuzt299jfd + // bchtest:qzd7dvlnfukggjqsf5ju0qqwwltakfumjsck33js6m + // bchtest:qq322ataqeas4n0pdn4gz2sdereh5ae43ylk4qdvus + +### `fromXPriv` + +Generates an address for an extended private key (xpriv) + +#### Arguments + +1. xpriv `string`: extended private key to be used +2. path `string` **optional**: derivation path of change address. Default is `0'/0` + +#### Result + +changeAddress `string`: cashaddr encoded change address + +#### Examples + + // generate 5 mainnet addresses for xprvA2WwD9mk1Qd3rMjQ4ZRHvCWCj47jbXjY9Nf7npNRBmGUJngpRAvJzNpNgt7h2dDQ5huG7yFwYfz4PFJDPzkqfvBNPHnaio4yAbbUuv3EBnL + let xpriv = 'xprvA2WwD9mk1Qd3rMjQ4ZRHvCWCj47jbXjY9Nf7npNRBmGUJngpRAvJzNpNgt7h2dDQ5huG7yFwYfz4PFJDPzkqfvBNPHnaio4yAbbUuv3EBnL'; + for(let i = 0; i <= 4; i++) { + console.log(bitbox.Address.fromXPriv(xpriv, "0'/" + i)) + } + // bitcoincash:qpmcs78tpfvfphhedcczydaddu5wmcx0xvrwf3fjph + // bitcoincash:qppfr7fu4dzxguen85rjwa6ress3sl839qyudganxj + // bitcoincash:qpuaaaseccxyjj04d2l3qv4vd2wxj6gtwvnfe3ckh8 + // bitcoincash:qp46n7a53jvkarp9ps595fjv8czfd045v5zk4xhspm + // bitcoincash:qprjdqx7cnrac4uemp2fza08k875wsgzfcapk76n9n + + // generate 5 testnet addresses for tprv8jBszV65QgT8TAxvj8Go5r8C3BXwq3mYUvaEfEnsfjkx6PRuQYG4W8Bpc4HM2zbiT9S384shi2Zrr6qxXD6nUySxuvztP9o25hLuMcDvMYD + let xpriv = 'tprv8jBszV65QgT8TAxvj8Go5r8C3BXwq3mYUvaEfEnsfjkx6PRuQYG4W8Bpc4HM2zbiT9S384shi2Zrr6qxXD6nUySxuvztP9o25hLuMcDvMYD'; + for(let i = 0; i <= 4; i++) { + console.log(bitbox.Address.fromXPub(xpriv, "0'/" + i)) + } + // bchtest:qpmcs78tpfvfphhedcczydaddu5wmcx0xv8udkt9xt + // bchtest:qppfr7fu4dzxguen85rjwa6ress3sl839qqwf0lypw + // bchtest:qpuaaaseccxyjj04d2l3qv4vd2wxj6gtwvhmak6psm + // bchtest:qp46n7a53jvkarp9ps595fjv8czfd045v5xy3p48x8 + // bchtest:qprjdqx7cnrac4uemp2fza08k875wsgzfcenjecyz0 + +### `fromOutputScript` + +Detect an addess from an OutputScript. + +#### Arguments + +1. scriptPubKey `Buffer`: scriptPubKey +2. network `string` **optional**: defaults to "mainnet" + +#### Result + +changeAddress `string`: cashaddr encoded change address + +#### Examples + + const script = bitbox.Script.encode([ + Buffer.from("BOX", "ascii"), + bitbox.Script.opcodes.OP_CAT, + Buffer.from("BITBOX", "ascii"), + bitbox.Script.opcodes.OP_EQUAL + ]); + const p2sh_hash160 = bitbox.Crypto.hash160(script); + const scriptPubKey = bitbox.Script.scriptHash.output.encode(p2sh_hash160); + + // mainnet address from output script + bitbox.Address.fromOutputScript(scriptPubKey); + // bitcoincash:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqncnufkrl + + // testnet address from output script + bitbox.Address.fromOutputScript(scriptPubKey, 'testnet'); + // bchtest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqh2hmtpyr + +### `isHash160` + +Detect if an addess is a hash160. + +#### Arguments + +1. address `string`: address + +#### Result + +isHash160 `boolean`: true/false if address is hash160 + +#### Examples + + let hash160Address = '428df38e23fc879a25819427995c3e6355b12d33'; + bitbox.Address.isHash160(hash160Address); + // true + + let notHash160Address = 'bitcoincash:pz8a837lttkvjksg0jjmmulqvfkgpqrcdgufy8ns5s'; + bitbox.Address.isHash160(notHash160Address); + // false + +### `legacyToHash160` + +Convert legacy address to hash160. + +#### Arguments + +1. address `string`: legacy address + +#### Result + +hash160 `string`: hash160 + +#### Examples + + // legacy mainnet p2pkh + bitbox.Address.legacyToHash160("18xHZ8g2feo4ceejGpvzHkvXT79fi2ZdTG") + // 573d93b475be4f1925f3b74ed951201b0147eac1 + + // legacy mainnet p2sh + bitbox.Address.legacyToHash160("3DA6RBcFgLwLTpnF6BRAee8w6a9H6JQLCm") + // 7dc85da64d1d93ef01ef62e0221c02f512e3942f + + // legacy testnet p2pkh + bitbox.Address.legacyToHash160("mhTg9sgNgvAGfmJs192oUzQWqAXHH5nqLE") + // 155187a3283b08b30519db50bc23bbba9f4b6657 + +### `cashToHash160` + +Convert cash address to hash160. + +#### Arguments + +1. address `string`: cash address + +#### Result + +hash160 `string`: hash160 + +#### Examples + + // cash address mainnet p2pkh + bitbox.Address.cashToHash160("bitcoincash:qptnmya5wkly7xf97wm5ak23yqdsz3l2cyj7k9vyyh") + // 573d93b475be4f1925f3b74ed951201b0147eac1 + + // cash address mainnet p2sh + bitbox.Address.cashToHash160("bitcoincash:pp7ushdxf5we8mcpaa3wqgsuqt639cu59ur5xu5fug") + // 7dc85da64d1d93ef01ef62e0221c02f512e3942f + + // cash address testnet p2pkh + bitbox.Address.cashToHash160("bchtest:qq24rpar9qas3vc9r8d4p0prhwaf7jmx2u22nzt946") + // 155187a3283b08b30519db50bc23bbba9f4b6657 + +### `hash160ToLegacy` + +Convert hash160 to legacy address. + +#### Arguments + +1. hash160 `string`: hash160 +2. network `number` **optional** + +#### Result + +legacyAddress `string`: the address in legacy format + +#### Examples + + // legacy mainnet p2pkh + bitbox.Address.hash160ToLegacy("573d93b475be4f1925f3b74ed951201b0147eac1") + // 18xHZ8g2feo4ceejGpvzHkvXT79fi2ZdTG + + // legacy mainnet p2sh + bitbox.Address.hash160ToLegacy("7dc85da64d1d93ef01ef62e0221c02f512e3942f", 0x05) + // 3DA6RBcFgLwLTpnF6BRAee8w6a9H6JQLCm + + // legacy testnet p2pkh + bitbox.Address.hash160ToLegacy("155187a3283b08b30519db50bc23bbba9f4b6657", 0x6f) + // mhTg9sgNgvAGfmJs192oUzQWqAXHH5nqLE + +### `hash160ToCash` + +Convert hash160 to cash address. + +#### Arguments + +1. hash160 `string`: hash160 +2. network `number` **optional** + +#### Result + +cashAddress `string`: the address in cash format + +#### Examples + + bitbox.Address.hash160ToCash("573d93b475be4f1925f3b74ed951201b0147eac1") + 'bitcoincash:qptnmya5wkly7xf97wm5ak23yqdsz3l2cyj7k9vyyh' + bitbox.Address.hash160ToCash("7dc85da64d1d93ef01ef62e0221c02f512e3942f", 0x05) + 'bitcoincash:pp7ushdxf5we8mcpaa3wqgsuqt639cu59ur5xu5fug' + bitbox.Address.hash160ToCash("155187a3283b08b30519db50bc23bbba9f4b6657", 0x6f) + 'bchtest:qq24rpar9qas3vc9r8d4p0prhwaf7jmx2u22nzt946' + +### `details` + +Return details about an address including balance. + +#### Arguments + +- addresses (required): + - `string`: A single string containing a legacy or cash address. + - `Array` of strings: Array with maximum of 20 legacy or cash addresses. + +#### Result + +- details: + - `Promise`: containing details about the single address. + - `Promise`: Array of Objects with details about addresses. + +#### Examples + + (async () => { + try { + let details = await bitbox.Address.details('1BFHGm4HzqgXXyNX8n7DsQno5DAC4iLMRA'); + console.log(details) + } catch(error) { + console.error(error) + } + })() + + // { + // "addrStr": "1BFHGm4HzqgXXyNX8n7DsQno5DAC4iLMRA", + // "balance": 0.36781097, + // "balanceSat": 36781097, + // "totalReceived": 0.36781097, + // "totalReceivedSat": 36781097, + // "totalSent": 0, + // "totalSentSat": 0, + // "unconfirmedBalance": 0, + // "unconfirmedBalanceSat": 0, + // "unconfirmedTxAppearances": 0, + // "txAppearances": 7, + // "transactions": [ + // "f737485aaee3c10b13013fa109bb6294b099246134ca9885f4cc332dbc6c9bb4", + // "decd5b9c0c959e4e543182093e8f7f8bc7a6ecd96a8a062daaeff3667f8feca7", + // "94e69a627a34ae27fca81d15fff4323a7ce1f7c275c7485762ce018221017632", + // "e67c70787af7f3506263c9eda007f3d2d24bd750ff95b5c50a120d9118dfd807", + // "8e5e00704a147d54028f94d52df7730e821b9c6cd4bd29494e5636f49c199d6a", + // "15102827c108566ea5daf725c09079c1a3f42ef99d1eb68ea8c584f7b16ab87a", + // "cc27be8846276612dfce5924b7be96556212f0f0e62bd17641732175edb9911e" + // ] + // } + + (async () => { + try { + let details = await bitbox.Address.details(['1BFHGm4HzqgXXyNX8n7DsQno5DAC4iLMRA', "bitcoincash:qp7ekaepv3wf2nq035hevcma4x9sxmp3w56048g6ra"]); + console.log(details) + } catch(error) { + console.error(error) + } + })() + + // [ { balance: 0.36781097, + // balanceSat: 36781097, + // totalReceived: 0.36781097, + // totalReceivedSat: 36781097, + // totalSent: 0, + // totalSentSat: 0, + // unconfirmedBalance: 0, + // unconfirmedBalanceSat: 0, + // unconfirmedTxAppearances: 0, + // txAppearances: 7, + // transactions: + // [ 'f737485aaee3c10b13013fa109bb6294b099246134ca9885f4cc332dbc6c9bb4', + // 'decd5b9c0c959e4e543182093e8f7f8bc7a6ecd96a8a062daaeff3667f8feca7', + // '94e69a627a34ae27fca81d15fff4323a7ce1f7c275c7485762ce018221017632', + // 'e67c70787af7f3506263c9eda007f3d2d24bd750ff95b5c50a120d9118dfd807', + // '8e5e00704a147d54028f94d52df7730e821b9c6cd4bd29494e5636f49c199d6a', + // '15102827c108566ea5daf725c09079c1a3f42ef99d1eb68ea8c584f7b16ab87a', + // 'cc27be8846276612dfce5924b7be96556212f0f0e62bd17641732175edb9911e' ], + // legacyAddress: '1BFHGm4HzqgXXyNX8n7DsQno5DAC4iLMRA', + // cashAddress: 'bitcoincash:qpcxf2sv9hjw08nvpgffpamfus9nmksm3chv5zqtnz' }, + // { balance: 0, + // balanceSat: 0, + // totalReceived: 0, + // totalReceivedSat: 0, + // totalSent: 0, + // totalSentSat: 0, + // unconfirmedBalance: 0, + // unconfirmedBalanceSat: 0, + // unconfirmedTxAppearances: 0, + // txAppearances: 0, + // transactions: [], + // legacyAddress: '1CT9huFgxMFveRvzZ7zPPJNoaMm2Fo64VH', + // cashAddress: 'bitcoincash:qp7ekaepv3wf2nq035hevcma4x9sxmp3w56048g6ra' } ] + +### `utxo` + +Return list of uxto for address. This includes confirmed and unconfirmed utxos. + +#### Arguments + +- addresses (required) - 2 formats allowed: + - `string`: A single string containing a legacy or cash address. + - `Array` of strings: Array with maximum of 20 legacy or cash addresses. + +#### Result + +- utxo (2 formats based on the argument format): + - utxo `Promise` + - utxos `Promise` + +#### Examples + + (async () => { + try { + let utxo = await bitbox.Address.utxo('1M1FYu4zuVaxRPWLZG5CnP8qQrZaqu6c2L'); + console.log(utxo); + } catch(error) { + console.error(error) + } + })() + + // { + // "utxos": [ + // { + // "txid": "27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c", + // "vout": 0, + // "amount": 0.001, + // "satoshis": 100000, + // "height": 560430, + // "confirmations": 5163 + // }, + // { + // "txid": "6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d", + // "vout": 0, + // "amount": 0.0013, + // "satoshis": 130000, + // "height": 560039, + // "confirmations": 5554 + // } + // ], + // "legacyAddress": "1M1FYu4zuVaxRPWLZG5CnP8qQrZaqu6c2L", + // "cashAddress": "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", + // "scriptPubKey": "76a914db6ea94fa26b7272dc5e1487c35f258391e0f38788ac" + // } + + (async () => { + try { + let utxo = await bitbox.Address.utxo([ + "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", + "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v" + ]); + console.log(utxo); + } catch(error) { + console.error(error) + } + })() + + // [ + // { + // "utxos": [ + // { + // "txid": "27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c", + // "vout": 0, + // "amount": 0.001, + // "satoshis": 100000, + // "height": 560430, + // "confirmations": 5163 + // }, + // { + // "txid": "6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d", + // "vout": 0, + // "amount": 0.0013, + // "satoshis": 130000, + // "height": 560039, + // "confirmations": 5554 + // } + // ], + // "legacyAddress": "1M1FYu4zuVaxRPWLZG5CnP8qQrZaqu6c2L", + // "cashAddress": "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", + // "scriptPubKey": "76a914db6ea94fa26b7272dc5e1487c35f258391e0f38788ac" + // }, + // { + // "utxos": [], + // "legacyAddress": "19LXyLnux1tbTdHnMuYAgDZ81ZQDWEi12g", + // "cashAddress": "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v" + // } + // ] + +### `unconfirmed` + +Return list of unconfirmed transactions for address + +#### Arguments + +- addresses (required): + - `string`: A single string containing a legacy or cash address. + - `Array` of strings: Array with maximum of 20 legacy or cash addresses. + +#### Result + +- unconfirmed: + - utxo `Promise`: containing `utxo` array of utxos, plus `legacyAddress` and + `cashAddress` properties. + - utxos `Promise`: Array of utxo Objects. + +#### Examples + + (async () => { + try { + let unconfirmed = await bitbox.Address.unconfirmed('1JCwsMQtiV85fGjps4zXceaCCgxpQ1u84R'); + console.log(unconfirmed); + } catch(error) { + console.error(error) + } + })() + + // { + // "utxos": [ + // { + // "address": "1JCwsMQtiV85fGjps4zXceaCCgxpQ1u84R", + // "txid": "5ddf277cecefab4bb75fb5d6ba21170cec756ef28a045cb4ec45ccffda28cdaf", + // "vout": 0, + // "scriptPubKey": "76a914bcbc83f8fadb704a6aeccf38079e428da445b11e88ac", + // "amount": 0.0001, + // "satoshis": 10000, + // "confirmations": 0, + // "ts": 1547670883 + // } + // ], + // "legacyAddress": "1JCwsMQtiV85fGjps4zXceaCCgxpQ1u84R", + // "cashAddress": "bitcoincash:qz7teqlcltdhqjn2an8nspu7g2x6g3d3rcq8nk4nzs" + // } + + (async () => { + try { + let unconfirmed = await bitbox.Address.unconfirmed(['1JCwsMQtiV85fGjps4zXceaCCgxpQ1u84R', "bitcoincash:qqcp8fw06dmjd2gnfanpwytj7q93w408nv7usdqgsk"]) + console.log(unconfirmed); + } catch(error) { + console.error(error) + } + })() + + // [ + // { + // "utxos": [ + // { + // "address": "1JCwsMQtiV85fGjps4zXceaCCgxpQ1u84R", + // "txid": "5ddf277cecefab4bb75fb5d6ba21170cec756ef28a045cb4ec45ccffda28cdaf", + // "vout": 0, + // "scriptPubKey": "76a914bcbc83f8fadb704a6aeccf38079e428da445b11e88ac", + // "amount": 0.0001, + // "satoshis": 10000, + // "confirmations": 0, + // "ts": 1547670883 + // } + // ], + // "legacyAddress": "1JCwsMQtiV85fGjps4zXceaCCgxpQ1u84R", + // "cashAddress": "bitcoincash:qz7teqlcltdhqjn2an8nspu7g2x6g3d3rcq8nk4nzs" + // }, + // { + // "utxos": [ + // { + // "address": "15PCyMYPK6EX4xGenwG55FwdNnuyoHzYAX", + // "txid": "f15ea5a836165bff9d711e9a1340e23554e28e03239aa3f4f9951c11ca1b6962", + // "vout": 0, + // "scriptPubKey": "76a9143013a5cfd37726a9134f66171172f00b1755e79b88ac", + // "amount": 0.0001, + // "satoshis": 10000, + // "confirmations": 0, + // "ts": 1547670908 + // } + // ], + // "legacyAddress": "15PCyMYPK6EX4xGenwG55FwdNnuyoHzYAX", + // "cashAddress": "bitcoincash:qqcp8fw06dmjd2gnfanpwytj7q93w408nv7usdqgsk" + // } + // ] + +### `transactions` + +Returns decoded transactions for an address + +#### Arguments + +- addresses (required): + - `string`: A single string containing a legacy or cash address. + - `Array` of strings: Array with maximum of 20 legacy or cash addresses. + +#### Result + +- transaction: + - `Object`: containing `txs` array of decoded transactions, plus `legacyAddress` and + `cashAddress` properties. + - `Array`: Array of txs Objects. + +#### Examples + + (async () => { + try { + let transaction = await bitbox.Address.transactions('bitcoincash:qz7teqlcltdhqjn2an8nspu7g2x6g3d3rcq8nk4nzs'); + console.log(transaction); + } catch(error) { + console.error(error) + } + })() + + // { + // "pagesTotal": 1, + // "txs": [ + // { + // "txid": "5ddf277cecefab4bb75fb5d6ba21170cec756ef28a045cb4ec45ccffda28cdaf", + // "version": 2, + // "locktime": 0, + // "vin": [ + // { + // "txid": "d0ff03c2429810991e8e23cfe2f253891eaae391bcbfd61706d340d9d649abea", + // "vout": 0, + // "sequence": 4294967295, + // "n": 0, + // "scriptSig": { + // "hex": "483045022100fc121a12774e7f212f42898ea123ecc03099dc610a48627649f58490f183027b0220113964a117dc5aaed7c76a569a287797ccffad192cc346114340e59a706a1cd841210242faa7cc02f9e6c3a0aec97a946b9d3793fa6ab76362e02dd239bc56393671cd", + // "asm": "3045022100fc121a12774e7f212f42898ea123ecc03099dc610a48627649f58490f183027b0220113964a117dc5aaed7c76a569a287797ccffad192cc346114340e59a706a1cd8[ALL|FORKID] 0242faa7cc02f9e6c3a0aec97a946b9d3793fa6ab76362e02dd239bc56393671cd" + // }, + // "addr": "1GQTe9EdBaF4fCTC2esvPNXewkUZoytADL", + // "valueSat": 3466913, + // "value": 0.03466913, + // "doubleSpentTxID": null + // } + // ], + // "vout": [ + // { + // "value": "0.00010000", + // "n": 0, + // "scriptPubKey": { + // "hex": "76a914bcbc83f8fadb704a6aeccf38079e428da445b11e88ac", + // "asm": "OP_DUP OP_HASH160 bcbc83f8fadb704a6aeccf38079e428da445b11e OP_EQUALVERIFY OP_CHECKSIG", + // "addresses": [ + // "1JCwsMQtiV85fGjps4zXceaCCgxpQ1u84R" + // ], + // "type": "pubkeyhash" + // }, + // "spentTxId": null, + // "spentIndex": null, + // "spentHeight": null + // }, + // { + // "value": "0.03456687", + // "n": 1, + // "scriptPubKey": { + // "hex": "76a914a8f9b1307fa412da6a909f08930e5a502d27a74a88ac", + // "asm": "OP_DUP OP_HASH160 a8f9b1307fa412da6a909f08930e5a502d27a74a OP_EQUALVERIFY OP_CHECKSIG", + // "addresses": [ + // "1GQTe9EdBaF4fCTC2esvPNXewkUZoytADL" + // ], + // "type": "pubkeyhash" + // }, + // "spentTxId": null, + // "spentIndex": null, + // "spentHeight": null + // } + // ], + // "blockheight": -1, + // "confirmations": 0, + // "time": 1547674527, + // "valueOut": 0.03466687, + // "size": 226, + // "valueIn": 0.03466913, + // "fees": 0.00000226 + // } + // ], + // "legacyAddress": "1JCwsMQtiV85fGjps4zXceaCCgxpQ1u84R", + // "cashAddress": "bitcoincash:qz7teqlcltdhqjn2an8nspu7g2x6g3d3rcq8nk4nzs", + // "currentPage": 0 + // } + + (async () => { + try { + let transaction = await bitbox.Address.transactions([ + "bitcoincash:qz7teqlcltdhqjn2an8nspu7g2x6g3d3rcq8nk4nzs", + "bitcoincash:qqcp8fw06dmjd2gnfanpwytj7q93w408nv7usdqgsk" + ]); + console.log(transaction); + } catch(error) { + console.error(error) + } + })() + + // [ + // { + // "pagesTotal": 1, + // "txs": [ + // { + // "txid": "5ddf277cecefab4bb75fb5d6ba21170cec756ef28a045cb4ec45ccffda28cdaf", + // "version": 2, + // "locktime": 0, + // "vin": [ + // { + // "txid": "d0ff03c2429810991e8e23cfe2f253891eaae391bcbfd61706d340d9d649abea", + // "vout": 0, + // "sequence": 4294967295, + // "n": 0, + // "scriptSig": { + // "hex": "483045022100fc121a12774e7f212f42898ea123ecc03099dc610a48627649f58490f183027b0220113964a117dc5aaed7c76a569a287797ccffad192cc346114340e59a706a1cd841210242faa7cc02f9e6c3a0aec97a946b9d3793fa6ab76362e02dd239bc56393671cd", + // "asm": "3045022100fc121a12774e7f212f42898ea123ecc03099dc610a48627649f58490f183027b0220113964a117dc5aaed7c76a569a287797ccffad192cc346114340e59a706a1cd8[ALL|FORKID] 0242faa7cc02f9e6c3a0aec97a946b9d3793fa6ab76362e02dd239bc56393671cd" + // }, + // "addr": "1GQTe9EdBaF4fCTC2esvPNXewkUZoytADL", + // "valueSat": 3466913, + // "value": 0.03466913, + // "doubleSpentTxID": null + // } + // ], + // "vout": [ + // { + // "value": "0.00010000", + // "n": 0, + // "scriptPubKey": { + // "hex": "76a914bcbc83f8fadb704a6aeccf38079e428da445b11e88ac", + // "asm": "OP_DUP OP_HASH160 bcbc83f8fadb704a6aeccf38079e428da445b11e OP_EQUALVERIFY OP_CHECKSIG", + // "addresses": [ + // "1JCwsMQtiV85fGjps4zXceaCCgxpQ1u84R" + // ], + // "type": "pubkeyhash" + // }, + // "spentTxId": null, + // "spentIndex": null, + // "spentHeight": null + // }, + // { + // "value": "0.03456687", + // "n": 1, + // "scriptPubKey": { + // "hex": "76a914a8f9b1307fa412da6a909f08930e5a502d27a74a88ac", + // "asm": "OP_DUP OP_HASH160 a8f9b1307fa412da6a909f08930e5a502d27a74a OP_EQUALVERIFY OP_CHECKSIG", + // "addresses": [ + // "1GQTe9EdBaF4fCTC2esvPNXewkUZoytADL" + // ], + // "type": "pubkeyhash" + // }, + // "spentTxId": null, + // "spentIndex": null, + // "spentHeight": null + // } + // ], + // "blockheight": -1, + // "confirmations": 0, + // "time": 1547674527, + // "valueOut": 0.03466687, + // "size": 226, + // "valueIn": 0.03466913, + // "fees": 0.00000226 + // } + // ], + // "legacyAddress": "1JCwsMQtiV85fGjps4zXceaCCgxpQ1u84R", + // "cashAddress": "bitcoincash:qz7teqlcltdhqjn2an8nspu7g2x6g3d3rcq8nk4nzs", + // "currentPage": 0 + // }, + // { + // "pagesTotal": 1, + // "txs": [ + // { + // "txid": "f15ea5a836165bff9d711e9a1340e23554e28e03239aa3f4f9951c11ca1b6962", + // "version": 2, + // "locktime": 0, + // "vin": [ + // { + // "txid": "5ddf277cecefab4bb75fb5d6ba21170cec756ef28a045cb4ec45ccffda28cdaf", + // "vout": 1, + // "sequence": 4294967295, + // "n": 0, + // "scriptSig": { + // "hex": "47304402206124fca6aecc35e48b5d1293bd97cadb39f830308c75331b3e5fd2e6806efe9b0220014cf3ecf0be1cb1bee7e362257b33e0905451d44f0902b13ada2765d53332d741210242faa7cc02f9e6c3a0aec97a946b9d3793fa6ab76362e02dd239bc56393671cd", + // "asm": "304402206124fca6aecc35e48b5d1293bd97cadb39f830308c75331b3e5fd2e6806efe9b0220014cf3ecf0be1cb1bee7e362257b33e0905451d44f0902b13ada2765d53332d7[ALL|FORKID] 0242faa7cc02f9e6c3a0aec97a946b9d3793fa6ab76362e02dd239bc56393671cd" + // }, + // "addr": "1GQTe9EdBaF4fCTC2esvPNXewkUZoytADL", + // "valueSat": 3456687, + // "value": 0.03456687, + // "doubleSpentTxID": null + // } + // ], + // "vout": [ + // { + // "value": "0.00010000", + // "n": 0, + // "scriptPubKey": { + // "hex": "76a9143013a5cfd37726a9134f66171172f00b1755e79b88ac", + // "asm": "OP_DUP OP_HASH160 3013a5cfd37726a9134f66171172f00b1755e79b OP_EQUALVERIFY OP_CHECKSIG", + // "addresses": [ + // "15PCyMYPK6EX4xGenwG55FwdNnuyoHzYAX" + // ], + // "type": "pubkeyhash" + // }, + // "spentTxId": null, + // "spentIndex": null, + // "spentHeight": null + // }, + // { + // "value": "0.03446461", + // "n": 1, + // "scriptPubKey": { + // "hex": "76a914a8f9b1307fa412da6a909f08930e5a502d27a74a88ac", + // "asm": "OP_DUP OP_HASH160 a8f9b1307fa412da6a909f08930e5a502d27a74a OP_EQUALVERIFY OP_CHECKSIG", + // "addresses": [ + // "1GQTe9EdBaF4fCTC2esvPNXewkUZoytADL" + // ], + // "type": "pubkeyhash" + // }, + // "spentTxId": null, + // "spentIndex": null, + // "spentHeight": null + // } + // ], + // "blockheight": -1, + // "confirmations": 0, + // "time": 1547674527, + // "valueOut": 0.03456461, + // "size": 225, + // "valueIn": 0.03456687, + // "fees": 0.00000226 + // } + // ], + // "legacyAddress": "15PCyMYPK6EX4xGenwG55FwdNnuyoHzYAX", + // "cashAddress": "bitcoincash:qqcp8fw06dmjd2gnfanpwytj7q93w408nv7usdqgsk", + // "currentPage": 0 + // } + // ] + +## Interfaces + +### AddressDetailsResult + + { + balance: number + balanceSat: number + totalReceived: number + totalReceivedSat: number + totalSent: number + totalSentSat: number + unconfirmedBalance: number + unconfirmedBalanceSat: number + unconfirmedTxApperances: number + txApperances: number + transactions: string[] + legacyAddress: string + cashAddress: string + } + +### AddressUtxoResult + + { + legacyAddress: string + cashAddress: string + scriptPubKey: string + utxos: [ + { + txid: string + vout: number + amount: number + satoshis: number + height: number + confirmations: number + } + ] + } + +### AddressUnconfirmedResult + + { + txid: string + vout: number + scriptPubKey: string + amount: number + satoshis: number + confirmations: number + ts: number + legacyAddress: string + cashAddress: string + } diff --git a/docs/bitcoincash.md b/docs/bitcoincash.md new file mode 100644 index 00000000..b794eb80 --- /dev/null +++ b/docs/bitcoincash.md @@ -0,0 +1,517 @@ +# BitcoinCash + +### `toSatoshi` + +Converting Bitcoin Cash units to satoshi units + +#### Arguments + +1. bitcoinCash `number`: unit to be converted + +#### Result + +satoshi `number`: bitcoinCash unit converted to satoshis + +#### Examples + +```javascript +// convert 9 $BCH to satoshis +bitbox.BitcoinCash.toSatoshi(9) +// 900000000 + +// convert 1 $BCH to satoshis +bitbox.BitcoinCash.toSatoshi(1) +// 100000000 + +// convert 100 $BCH to satoshis +bitbox.BitcoinCash.toSatoshi(100) +// 10000000000 + +// convert 42 $BCH to satoshis +bitbox.BitcoinCash.toSatoshi(42) +// 4200000000 + +// convert 507 $BCH to satoshis +bitbox.BitcoinCash.toSatoshi(507) +// 50700000000 +``` + +### `toBitcoinCash` + +Converting satoshi units to Bitcoin Cash units + +#### Arguments + +1. satoshi `number`: unit to be converted + +#### Result + +bitcoinCash `number`: satoshi unit converted to Bitcoin Cash + +#### Examples + +```javascript +// convert 900000000 satoshis to $BCH +bitbox.BitcoinCash.toBitcoinCash(900000000) +// 9 + +// convert 100000000 satoshis to $BCH +bitbox.BitcoinCash.toBitcoinCash(100000000) +// 1 + +// convert 10000000000 satoshis to $BCH +bitbox.BitcoinCash.toBitcoinCash(10000000000) +// 100 + +// convert 4200000000 satoshis to $BCH +bitbox.BitcoinCash.toBitcoinCash(4200000000) +// 42 + +// convert 50700000000 satoshis to $BCH +bitbox.BitcoinCash.toBitcoinCash(50700000000) +// 507 +``` + +### `toBits` + +Converting satoshi units to Bits denomination + +#### Arguments + +1. satoshi `Number`: unit to be converted + +#### Result + +bits `Number`: satoshi unit converted to Bits + +#### Examples + +```javascript +// convert 4242323400 satoshis to 42423.234 bits +BITBOX.BitcoinCash.toBits(4242323400) +// 42423.234 +// convert 100000000 satoshis to 1000 bits +BITBOX.BitcoinCash.toBits(100000000) +// 1000 +// convert 314000000 satoshis to 3140 bits +BITBOX.BitcoinCash.toBits(314000000) +// 3140 +// convert 987600000000 satoshis to 9876000 bits +BITBOX.BitcoinCash.toBits(987600000000) +// 9876000 +// convert 12300 satoshis to 0.123 bits +BITBOX.BitcoinCash.toBits(12300) +// 0.123 +``` + +### `fromBits` + +Converting bits units to satoshi denomination + +#### Arguments + +1. bits `Number`: unit to be converted + +#### Result + +satoshi `Number`: bits unit converted to satoshi + +#### Examples + +```javascript +// convert 42423.234 bits to 4242323400 satoshis +BITBOX.BitcoinCash.fromBits(42423.234) +// 4242323400 +// convert 1000 bits to 100000000 satoshis +BITBOX.BitcoinCash.fromBits(1000) +// 100000000 +// convert 3140 bits to 314000000 satoshis +BITBOX.BitcoinCash.fromBits(3140) +// 314000000 +// convert 9876000 bits to 987600000000 satoshis +BITBOX.BitcoinCash.fromBits(9876000) +// 987600000000 +// convert 0.123 bits to 12300 satoshis +BITBOX.BitcoinCash.fromBits(0.123) +// 12300 +``` + +### `signMessageWithPrivKey` + +Sign message with private key + +#### Arguments + +1. privateKeyWIF `string`: private key in wallet import format +2. message `string`: message to sign + +#### Result + +signature `string`: cryptographic signature + +#### Examples + +```javascript +bitbox.BitcoinCash.signMessageWithPrivKey( + "KxtpRDUJDiutLaTV8Vuavhb6h7zq9YV9ZKA3dU79PCgYmNVmkkvS", + "EARTH" +) +// IIYVhlo2Z6TWFjYX1+YM+7vQKz0m+zYdSe4eYpFLuAQDEZXqll7lZC8Au22VI2LLP5x+IerZckVk3QQPsA3e8/8= +``` + +### `verifyMessage` + +Verify message + +#### Arguments + +1. address `string`: public cashaddr or legacy address which signed the message +2. signature `string`: cryptographic signature +3. message `string`: to verify + +#### Result + +isVerified `boolean`: if message is verified or not + +#### Examples + +```javascript +bitbox.BitcoinCash.verifyMessage( + "bitcoincash:qp2zvw3zpk5xx43w4tve7mtekd9kaxwj4uenq9eupv", + "IIYVhlo2Z6TWFjYX1+YM+7vQKz0m+zYdSe4eYpFLuAQDEZXqll7lZC8Au22VI2LLP5x+IerZckVk3QQPsA3e8/8=", + "EARTH" +) +// true +``` + +### `encodeBase58Check` + +Encodes hex string as base58Check + +#### Arguments + +1. hex `string`: hex encoded bytes to encode as base58check + +#### Result + +base58check `string`: base58check encoded string + +#### Examples + +```javascript +// encode 0079bd35d306f648350818470c9f18903df6e06902a026f2a7 as base58check +let hex = "0079bd35d306f648350818470c9f18903df6e06902a026f2a7" +bitbox.BitcoinCash.encodeBase58Check(hex) +// 1C6hRmfzvWst5WA7bFRCVAqHt5gE2g7Qar + +// encode 006da742680accf2282df5fade8e9b7a01a517e779289b52cc as base58check +let hex = "006da742680accf2282df5fade8e9b7a01a517e779289b52cc" +bitbox.BitcoinCash.encodeBase58Check(hex) +// 1Azo2JBz2JswboeY9xSMcp14BAfhjnD9SK + +// encode 00c68a6a07ccdaf1669cfd8d244d80ff36b713551c6208f672 as base58check +let hex = "00c68a6a07ccdaf1669cfd8d244d80ff36b713551c6208f672" +bitbox.BitcoinCash.encodeBase58Check(hex) +// 1K6ncAmMEyQrKUYosZRD9swyZNXECu2aKs + +// encode 00d0a6b5e3dd43d0fb895b3b3df565bb8266c5ab00a25dbeb5 as base58check +let hex = "00d0a6b5e3dd43d0fb895b3b3df565bb8266c5ab00a25dbeb5" +bitbox.BitcoinCash.encodeBase58Check(hex) +// 1L2FG9hH3bwchhxHaCs5cg1QNbhmbaeAs6 + +// encode 00db04c2e6f104997cb04c956bf25da6078e559d303127f08b as base58check +let hex = "00db04c2e6f104997cb04c956bf25da6078e559d303127f08b" +bitbox.BitcoinCash.encodeBase58Check(hex) +// 1Ly4gqPddveYHMNkfjoXHanVszXpD3duKg +``` + +### `decodeBase58Check` + +Decodes base58Check encoded string to hex + +#### Arguments + +1. base58check `string`: base58check encoded string to decode to hex + +#### Result + +hex `string`: hex encoded string + +#### Examples + +```javascript +// decode 1C6hRmfzvWst5WA7bFRCVAqHt5gE2g7Qar to hex +let base58check = "1C6hRmfzvWst5WA7bFRCVAqHt5gE2g7Qar" +bitbox.BitcoinCash.decodeBase58Check(base58check) +// 0079bd35d306f648350818470c9f18903df6e06902a026f2a7 + +// decode 1Azo2JBz2JswboeY9xSMcp14BAfhjnD9SK to hex +let base58check = "1Azo2JBz2JswboeY9xSMcp14BAfhjnD9SK" +bitbox.BitcoinCash.decodeBase58Check(base58check) +// 006da742680accf2282df5fade8e9b7a01a517e779289b52cc + +// decode 1K6ncAmMEyQrKUYosZRD9swyZNXECu2aKs to hex +let base58check = "1K6ncAmMEyQrKUYosZRD9swyZNXECu2aKs" +bitbox.BitcoinCash.decodeBase58Check(base58check) +// 00c68a6a07ccdaf1669cfd8d244d80ff36b713551c6208f672 + +// decode 1L2FG9hH3bwchhxHaCs5cg1QNbhmbaeAs6 to hex +let base58check = "1L2FG9hH3bwchhxHaCs5cg1QNbhmbaeAs6" +bitbox.BitcoinCash.decodeBase58Check(base58check) +// 00d0a6b5e3dd43d0fb895b3b3df565bb8266c5ab00a25dbeb5 + +// decode 1Ly4gqPddveYHMNkfjoXHanVszXpD3duKg to hex +let base58check = "1Ly4gqPddveYHMNkfjoXHanVszXpD3duKg" +bitbox.BitcoinCash.decodeBase58Check(base58check) +// 00db04c2e6f104997cb04c956bf25da6078e559d303127f08b +``` + +### `encodeBIP21` + +Encodes address and options as BIP21 uri + +#### Arguments + +1. address `string`: cashaddr (w/ or w/out prefix) or legacy base58check encoded address +2. options `EncodeBIP21Options`: options such as amount, label, message etc +3. regtest `boolean` **optional** + +#### Result + +bip21 `string`: bip21 encoded uri + +#### Examples + +```javascript +let address = "bitcoincash:qrdsfshx7yzfjl9sfj2khuja5crcu4vaxqrt2qkz5s" +let options = { + amount: 1, + label: "#BCHForEveryone", +} +bitbox.BitcoinCash.encodeBIP21(address, options) +// bitcoincash:qrdsfshx7yzfjl9sfj2khuja5crcu4vaxqrt2qkz5s?amount=1&label=%23BCHForEveryone + +let address = "1C6hRmfzvWst5WA7bFRCVAqHt5gE2g7Qar" +let options = { + amount: 12.5, + label: "coinbase donation", + message: "and ya don't stop", +} +bitbox.BitcoinCash.encodeBIP21(address, options) +// bitcoincash:qpum6dwnqmmysdggrprse8ccjq7ldcrfqgmmtgcmny?amount=12.5&label=coinbase%20donation&message=and%20ya%20don%27t%20stop + +let address = "qzw6tfrh8p0jh834uf9rhg77pjg5rgnt3qw0e54u03" +let options = { + amount: 42, + label: "no prefix", +} +bitbox.BitcoinCash.encodeBIP21(address, options) +// bitcoincash:qzw6tfrh8p0jh834uf9rhg77pjg5rgnt3qw0e54u03?amount=42&label=no%20prefix +``` + +### `decodeBIP21` + +Decodes BIP21 uri + +#### Arguments + +1. bip21 `string`: bip21 encoded uri + +#### Result + +results `BIP21Object`: decoded bip21 uri + +#### Examples + +```javascript +let bip21 = + "bitcoincash:qrdsfshx7yzfjl9sfj2khuja5crcu4vaxqrt2qkz5s?amount=1&label=%23BCHForEveryone" +bitbox.BitcoinCash.decodeBIP21(bip21) +// { address: 'qrdsfshx7yzfjl9sfj2khuja5crcu4vaxqrt2qkz5s', options: { amount: 1, label: '#BCHForEveryone' } } + +let bip21 = + "bitcoincash:qpum6dwnqmmysdggrprse8ccjq7ldcrfqgmmtgcmny?amount=12.5&label=coinbase%20donation&message=and%20ya%20don%27t%20stop" +bitbox.BitcoinCash.decodeBIP21(bip21) +// { address: 'qpum6dwnqmmysdggrprse8ccjq7ldcrfqgmmtgcmny', +// options: +// { amount: 12.5, +// label: 'coinbase donation', +// message: 'and ya don\'t stop' +// } +// } + +let bip21 = + "bitcoincash:qzw6tfrh8p0jh834uf9rhg77pjg5rgnt3qw0e54u03?amount=42&label=no%20prefix" +bitbox.BitcoinCash.decodeBIP21(bip21) +// { address: 'qzw6tfrh8p0jh834uf9rhg77pjg5rgnt3qw0e54u03', options: { amount: 42, label: 'no prefix' } } +``` + +### `getByteCount` + +Get byte count of transaction + +#### Arguments + +1. inputs `ByteCountInput`: object w/ keys describing input types and counts. 'MULTISIG\-P2SH' and 'P2PKH'. "MULTISIG\-P2SH" also should include the required and total number of signatures. EX: "MULTISIG\-P2SH:2\-4" +2. outputs `ByteCountOutput`: object w/ keys describing output types and counts. 'P2SH' and 'P2PKH' + +#### Result + +byteCount `number`: number of bytes + +#### Examples + +```javascript +// 1 P2PKH input +let inputs = { + P2PKH: 1, +} +// 1 P2SH output +let outputs = { + P2SH: 1, +} +bitbox.BitcoinCash.getByteCount(inputs, outputs) +// 190 + +// 4 MULTISIG-P2SH 2-of-4 and 10 P2PKH inputs +let inputs = { + "MULTISIG-P2SH:2-4": 4, + P2PKH: 10, +} +// 23 P2PKH outputs +let outputs = { + P2PKH: 23, +} +bitbox.BitcoinCash.getByteCount(inputs, outputs) +// 2750 + +// 2 MULTISIG-P2SH 3-of-5 inputs +let inputs = { + "MULTISIG-P2SH:3-5": 2, +} +// 2 P2PKH outputs +let outputs = { + P2PKH: 2, +} +bitbox.BitcoinCash.getByteCount(inputs, outputs) +// 565 + +// 111 P2PKH inputs +let inputs = { + P2PKH: 111, +} +// 2 P2PKH outputs +let outputs = { + P2PKH: 2, +} +bitbox.BitcoinCash.getByteCount(inputs, outputs) +// 16506 + +// 10 P2PKH and 1 MULTISIG-P2SH 1-of-2 input +let inputs = { + P2PKH: 10, + "MULTISIG-P2SH:1-2": 1, +} +// 2 P2PKH and 1 P2SH outputs +let outputs = { + P2PKH: 2, + P2SH: 1, +} +bitbox.BitcoinCash.getByteCount(inputs, outputs) +// 1780 +``` + +### `encryptBIP38` + +[BIP38](https://github.com/bitcoin/bips/blob/master/bip-0038.mediawiki) encrypt privkey WIFs + +#### Arguments + +1. wif `string`: privkey WIF on mainnet or testnet +2. password `string`: password to encrypt wif with + +#### Result + +encryptedKey `string`: privkey WIF encrypted w/ password + +#### Examples + +```javascript +// mainnet +bitbox.BitcoinCash.encryptBIP38( + "L1phBREbhL4vb1uHHHCAse8bdGE5c7ic2PFjRxMawLzQCsiFVbvu", + "9GKVkabAHBMyAf" +) +// 6PYU2fDHRVF2194gKDGkbFbeu4mFgkWtVvg2RPd2Sp6KmZx3RCHFpgBB2G + +// testnet +bitbox.BitcoinCash.encryptBIP38( + "cSx7KzdH9EcvDEireu2WYpGnXdFYpta7sJUNt5kVCJgA7kcAU8Gm", + "1EBPIyj55eR8bVUov9" +) +// 6PYUAPLwLSEjWSAfoe9NTSPkMZXnJA8j8EFJtKaeSnP18RCouutBrS2735 +``` + +### `decryptBIP38` + +[BIP38](https://github.com/bitcoin/bips/blob/master/bip-0038.mediawiki) decrypt privkey WIFs + +#### Arguments + +1. encryptedKey `string`: encrypted privkey WIF +2. password `string`: password to decrypt wif with +3. network `string`: mainnet or testnet. Default: mainnet + +#### Result + +wif `string`: decrypted privkey WIF on mainnet or testnet + +#### Examples + +```javascript +// mainnet +bitbox.BitcoinCash.decryptBIP38( + "6PYU2fDHRVF2194gKDGkbFbeu4mFgkWtVvg2RPd2Sp6KmZx3RCHFpgBB2G", + "9GKVkabAHBMyAf", + "mainnet" +) +// L1phBREbhL4vb1uHHHCAse8bdGE5c7ic2PFjRxMawLzQCsiFVbvu + +// testnet +bitbox.BitcoinCash.decryptBIP38( + "6PYUAPLwLSEjWSAfoe9NTSPkMZXnJA8j8EFJtKaeSnP18RCouutBrS2735", + "1EBPIyj55eR8bVUov9", + "testnet" +) +// cSx7KzdH9EcvDEireu2WYpGnXdFYpta7sJUNt5kVCJgA7kcAU8Gm +``` + +## Interfaces + +### EncodeBIP21Options + + { + amount?: number + label?: string + message?: string + } + +### BIP21Object + + { + address: string + options?: EncodeBIP21Options + } + +### ByteCountInput + + { + P2PKH?: number + } + +### ByteCountOutput + + { + P2PKH?: number + P2SH?: number + } diff --git a/docs/bitdb.md b/docs/bitdb.md new file mode 100644 index 00000000..15feba65 --- /dev/null +++ b/docs/bitdb.md @@ -0,0 +1,47 @@ +# BitDB + +### `get` + +Get BitDB data by `query` + +#### Arguments + +1. query `any`: BitDB Query + +#### Result + +result `any`: BitDB Result + +#### Examples + +```javascript +;(async () => { + let res = await bitbox.BitDB.get({ + v: 3, + q: { + db: ["c"], + find: {}, + limit: 10, + }, + }) + console.log(res) + + // returns + // { c: + // [ { _id: '5d40924a0f265a358b92401a', + // tx: [Object], + // in: [Array], + // out: [Array], + // blk: [Object] }, + // { _id: '5d40924a0f265a358b924019', + // tx: [Object], + // in: [Array], + // out: [Array], + // blk: [Object] }, + // { _id: '5d40924a0f265a358b924018', + // tx: [Object], + // in: [Array], + // out: [Array], + // blk: [Object] }, +})() +``` diff --git a/docs/block.md b/docs/block.md new file mode 100644 index 00000000..1aeec198 --- /dev/null +++ b/docs/block.md @@ -0,0 +1,244 @@ +# Block + +### `detailsByHeight` + +Return details about a Block. Lookup the block with a block height. + +#### Arguments + +- blocks (required): + - `number`: block height + - `number[]` of Numbers: block heights + +#### Result + +- details + - `Promise` + - `Promise` + +#### Examples + + (async () => { + try { + let details = await bitbox.Block.detailsByHeight(500000); + console.log(details); + } catch(error) { + console.error(error) + } + })() + + // { + // "hash": "000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0", + // "size": 216, + // "height": 507, + // "version": 1, + // "merkleroot": "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8", + // "tx": [ + // "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8" + // ], + // "time": 1231973656, + // "nonce": 330467862, + // "bits": "1d00ffff", + // "difficulty": 1, + // "chainwork": "000000000000000000000000000000000000000000000000000001fc01fc01fc", + // "confirmations": 528404, + // "previousblockhash": "00000000a99525c043fd7e323414b60add43c254c44860094048f9c01e9a5fdd", + // "nextblockhash": "000000000d550f4161f2702165fdd782ec72ff9c541f864ebb8256b662b7e51a", + // "reward": 50, + // "isMainChain": true, + // "poolInfo": { + // "poolName": "ViaBTC", + // "url": "https://viabtc.com/" + // } + // } + + + (async () => { + try { + let details = await bitbox.Block.detailsByHeight([500000, 500001]); + console.log(details); + } catch(error) { + console.error(error) + } + })() + + // [{ + // "hash": "000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0", + // "size": 216, + // "height": 507, + // "version": 1, + // "merkleroot": "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8", + // "tx": [ + // "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8" + // ], + // "time": 1231973656, + // "nonce": 330467862, + // "bits": "1d00ffff", + // "difficulty": 1, + // "chainwork": "000000000000000000000000000000000000000000000000000001fc01fc01fc", + // "confirmations": 528404, + // "previousblockhash": "00000000a99525c043fd7e323414b60add43c254c44860094048f9c01e9a5fdd", + // "nextblockhash": "000000000d550f4161f2702165fdd782ec72ff9c541f864ebb8256b662b7e51a", + // "reward": 50, + // "isMainChain": true, + // "poolInfo": { + // "poolName": "ViaBTC", + // "url": "https://viabtc.com/" + // } + // }, + // { + // "hash": "000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0", + // "size": 216, + // "height": 507, + // "version": 1, + // "merkleroot": "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8", + // "tx": [ + // "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8" + // ], + // "time": 1231973656, + // "nonce": 330467862, + // "bits": "1d00ffff", + // "difficulty": 1, + // "chainwork": "000000000000000000000000000000000000000000000000000001fc01fc01fc", + // "confirmations": 528404, + // "previousblockhash": "00000000a99525c043fd7e323414b60add43c254c44860094048f9c01e9a5fdd", + // "nextblockhash": "000000000d550f4161f2702165fdd782ec72ff9c541f864ebb8256b662b7e51a", + // "reward": 50, + // "isMainChain": true, + // "poolInfo": {} + // }] + +### `detailsByHash` + +Return details about a Block. Lookup the block with a block hash. + +#### Arguments + +- hashes (required): + - `string`: block hash + - `string[]` of Strings: block hashes + +#### Result + +- details + - `Promise` + - `Promise` + +#### Examples + + (async () => { + try { + let details = await bitbox.Block.hash("000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201"); + console.log(details); + } catch(error) { + console.error(error) + } + })() + + // { + // "hash": "000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0", + // "size": 216, + // "height": 507, + // "version": 1, + // "merkleroot": "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8", + // "tx": [ + // "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8" + // ], + // "time": 1231973656, + // "nonce": 330467862, + // "bits": "1d00ffff", + // "difficulty": 1, + // "chainwork": "000000000000000000000000000000000000000000000000000001fc01fc01fc", + // "confirmations": 528404, + // "previousblockhash": "00000000a99525c043fd7e323414b60add43c254c44860094048f9c01e9a5fdd", + // "nextblockhash": "000000000d550f4161f2702165fdd782ec72ff9c541f864ebb8256b662b7e51a", + // "reward": 50, + // "isMainChain": true, + // "poolInfo": { + // "poolName": "ViaBTC", + // "url": "https://viabtc.com/" + // } + // } + + (async () => { + try { + let details = await bitbox.Block.detailsByHeight([ + "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201", + "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201" + ]); + console.log(details); + } catch(error) { + console.error(error) + } + })() + + // [{ + // "hash": "000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0", + // "size": 216, + // "height": 507, + // "version": 1, + // "merkleroot": "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8", + // "tx": [ + // "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8" + // ], + // "time": 1231973656, + // "nonce": 330467862, + // "bits": "1d00ffff", + // "difficulty": 1, + // "chainwork": "000000000000000000000000000000000000000000000000000001fc01fc01fc", + // "confirmations": 528404, + // "previousblockhash": "00000000a99525c043fd7e323414b60add43c254c44860094048f9c01e9a5fdd", + // "nextblockhash": "000000000d550f4161f2702165fdd782ec72ff9c541f864ebb8256b662b7e51a", + // "reward": 50, + // "isMainChain": true, + // "poolInfo": { + // "poolName": "ViaBTC", + // "url": "https://viabtc.com/" + // } + // }, + // { + // "hash": "000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0", + // "size": 216, + // "height": 507, + // "version": 1, + // "merkleroot": "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8", + // "tx": [ + // "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8" + // ], + // "time": 1231973656, + // "nonce": 330467862, + // "bits": "1d00ffff", + // "difficulty": 1, + // "chainwork": "000000000000000000000000000000000000000000000000000001fc01fc01fc", + // "confirmations": 528404, + // "previousblockhash": "00000000a99525c043fd7e323414b60add43c254c44860094048f9c01e9a5fdd", + // "nextblockhash": "000000000d550f4161f2702165fdd782ec72ff9c541f864ebb8256b662b7e51a", + // "reward": 50, + // "isMainChain": true, + // "poolInfo": {} + // }] + +## Interfaces + +### BlockDetails + + { + hash: string + size: number + height: number + version: number + merkleroot: string + tx: string[] + time: number + mediantime?: number + nonce: number + bits: string + difficulty: number + chainwork: string + confirmations: number + previousblockhash: string + nextblockhash: string + reward: number + isMainChain: boolean + poolInfo: object + } diff --git a/docs/blockchain.md b/docs/blockchain.md new file mode 100644 index 00000000..4e5f0d44 --- /dev/null +++ b/docs/blockchain.md @@ -0,0 +1,704 @@ +# Blockchain + +### `getBestBlockHash` + +Returns the hash of the best (tip) block in the longest blockchain. + +#### Result + +hex `Promise`: the block hash hex encoded + +#### Examples + + (async () => { + try { + let getBestBlockHash = await bitbox.Blockchain.getBestBlockHash(); + console.log(getBestBlockHash); + } catch(error) { + console.error(error) + } + })() + // 241decef88889efac8e6ce428a8ac696fdde5972eceed97e1fb58d6106af31d5 + +### `getBlock` + +If verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'. If verbose is true, returns an Object with information about block `hash`. + +#### Arguments + +1. blockhash `string`: The block hash +2. verbose `boolean` **optional**: true for a json object, false for the hex encoded data + +#### Result + +block `Promise` + +#### Examples + + (async () => { + try { + let getBlock = await bitbox.Blockchain.getBlock("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"); + console.log(getBlock); + } catch(error) { + console.error(error) + } + })() + + // { hash: '00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09', + // confirmations: 528236, + // size: 216, + // height: 1000, + // version: 1, + // versionHex: '00000001', + // merkleroot: 'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33', + // tx: + // [ 'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33' ], + // time: 1232346882, + // mediantime: 1232344831, + // nonce: 2595206198, + // bits: '1d00ffff', + // difficulty: 1, + // chainwork: '000000000000000000000000000000000000000000000000000003e903e903e9', + // previousblockhash: '0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d', + // nextblockhash: '00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6' } + +### `getBlockchainInfo` + +Returns an object containing various state info regarding blockchain processing. + +#### Result + +block `Promise` + +#### Examples + + (async () => { + try { + let getBlockchainInfo = await bitbox.Blockchain.getBlockchainInfo(); + console.log(getBlockchainInfo); + } catch(error) { + console.error(error) + } + })() + + // { chain: 'main', + // blocks: 529235, + // headers: 529235, + // bestblockhash: '00000000000000000108641af52e01a447b1f9d801571f93a0f20a8cbf80c236', + // difficulty: 702784497476.8376, + // mediantime: 1525727823, + // verificationprogress: 0.9999892037620548, + // chainwork: '00000000000000000000000000000000000000000099f5e1cf7d4e462a493a51', + // pruned: false, + // softforks: + // [ { id: 'bip34', version: 2, reject: [Object] }, + // { id: 'bip66', version: 3, reject: [Object] }, + // { id: 'bip65', version: 4, reject: [Object] } ], + // bip9_softforks: + // { csv: + // { status: 'active', + // startTime: 1462060800, + // timeout: 1493596800, + // since: 419328 } } } + +### `getBlockCount` + +Returns the number of blocks in the longest blockchain. + +#### Result + +n `Promise` + +#### Examples + + (async () => { + try { + let getBlockCount = await bitbox.Blockchain.getBlockCount(); + console.log(getBlockCount); + } catch(error) { + console.error(error) + } + })() + // 529235 + +### `getBlockHash` + +Returns hash of block in best-block-chain at height provided. + +#### Arguments + +1. height `number` **optional** + +#### Result + +hash `Promise` The block hash + +#### Examples + + (async () => { + try { + let getBlockHash = await bitbox.Blockchain.getBlockHash([0]); + console.log(getBlockHash); + } catch(error) { + console.error(error) + } + })() + // [ '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f' ] + +### `getBlockHeader` + +If verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'. If verbose is true, returns an Object with information about blockheader `hash`. + +#### Arguments + +1. hashes `string | string[]` +2. verbose `boolean` **optional**: true for a json object, false for the hex encoded data. + +#### Result + +blockHeader `Promise` The block header + +#### Examples + + (async () => { + try { + let getBlockHeader = await bitbox.Blockchain.getBlockHeader(["00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"]); + console.log(getBlockHeader); + } catch(error) { + console.error(error) + } + })() + + // [{ hash: '00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09', + // confirmations: 528236, + // height: 1000, + // version: 1, + // versionHex: '00000001', + // merkleroot: 'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33', + // time: 1232346882, + // mediantime: 1232344831, + // nonce: 2595206198, + // bits: '1d00ffff', + // difficulty: 1, + // chainwork: '000000000000000000000000000000000000000000000000000003e903e903e9', + // previousblockhash: '0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d', + // nextblockhash: '00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6' }] + +### `getChainTips` + +Return information about all known tips in the block tree, including the main chain as well as orphaned branches. + +#### Result + +chainTips `Promise` + +#### Examples + + (async () => { + try { + let getChainTips = await bitbox.Blockchain.getChainTips(); + console.log(getChainTips); + } catch(error) { + console.error(error) + } + })() + + // [ { height: 529235, + // hash: '00000000000000000108641af52e01a447b1f9d801571f93a0f20a8cbf80c236', + // branchlen: 0, + // status: 'active' }, + // { height: 527442, + // hash: '0000000000000000014cbf7b7aa12e52dd97db4b1ba5f39dccae37773af9272e', + // branchlen: 1, + // status: 'invalid' }, + // { height: 526861, + // hash: '00000000000000000225b070818bbafd95842ecbd25edf39bff54a7aa5c8fd10', + // branchlen: 1, + // status: 'valid-headers' } ] + +### `getDifficulty` + +Returns the proof-of-work difficulty as a multiple of the minimum difficulty. + +#### Result + +n `Promise`: the proof-of-work difficulty as a multiple of the minimum difficulty. + +#### Examples + + (async () => { + try { + let getDifficulty = await bitbox.Blockchain.getDifficulty(); + console.log(getDifficulty); + } catch(error) { + console.error(error) + } + })() + + // 702784497476.8376 + + + +### `getMempoolEntry` + +Returns mempool data for given transaction + +#### Arguments + +- txids (required): + - `string`: TXID currently in mempool + - `string[]`: Array of TXIDs + +#### Result + +- entry: + - `Promise`: containing details about the single mempool entry. + - `Promise`: Array of Objects with details about mempool entries. + +#### Examples + + (async () => { + try { + let getMempoolEntry = await bitbox.Blockchain.getMempoolEntry("fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33"); + console.log(getMempoolEntry); + } catch(error) { + console.error(error) + } + })() + + // { + // "size": 372, + // "fee": 0.00000374, + // "modifiedfee": 0.00000374, + // "time": 1547738850, + // "height": 565716, + // "startingpriority": 26524545.3974359, + // "currentpriority": 26524545.3974359, + // "descendantcount": 1, + // "descendantsize": 372, + // "descendantfees": 374, + // "ancestorcount": 1, + // "ancestorsize": 372, + // "ancestorfees": 374, + // "depends": [] + // } + + (async () => { + try { + let getMempoolEntry = await bitbox.Blockchain.getMempoolEntry([ + "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33", + "defea04c38ee00cf73ad402984714ed22dc0dd99b2ae5cb50d791d94343ba79b" + ]); + console.log(getMempoolEntry); + } catch(error) { + console.error(error) + } + })() + + // [ + // { + // "size": 372, + // "fee": 0.00000374, + // "modifiedfee": 0.00000374, + // "time": 1547738850, + // "height": 565716, + // "startingpriority": 26524545.3974359, + // "currentpriority": 26524545.3974359, + // "descendantcount": 1, + // "descendantsize": 372, + // "descendantfees": 374, + // "ancestorcount": 1, + // "ancestorsize": 372, + // "ancestorfees": 374, + // "depends": [] + // }, + // { + // "size": 372, + // "fee": 0.00000374, + // "modifiedfee": 0.00000374, + // "time": 1547738850, + // "height": 565716, + // "startingpriority": 26524545.3974359, + // "currentpriority": 26524545.3974359, + // "descendantcount": 1, + // "descendantsize": 372, + // "descendantfees": 374, + // "ancestorcount": 1, + // "ancestorsize": 372, + // "ancestorfees": 374, + // "depends": [] + // } + // ] + +### `getMempoolInfo` + +Returns details on the active state of the TX memory pool. + +#### Result + +entry `Promise` + +#### Examples + + (async () => { + try { + let getMempoolInfo = await bitbox.Blockchain.getMempoolInfo(); + console.log(getMempoolInfo); + } catch(error) { + console.error(error) + } + })() + + // { size: 257, + // bytes: 98257, + // usage: 365840, + // maxmempool: 300000000, + // mempoolminfee: 0 } + +### `getRawMempool` + +Returns all transaction ids in memory pool as a json array of string transaction ids. + +#### Arguments + +1. verbose `boolean` **optional**: True for a json object, false for array of transaction ids + +#### Result + +rawMemPool `Promise` + +#### Examples + + (async () => { + try { + let getRawMempool = await bitbox.Blockchain.getRawMempool(true); + console.log(getRawMempool); + } catch(error) { + console.error(error) + } + })() + + // [ {'2ae541af20db6f2b50410f418af56e349d08877d685f6cf54df54658e892db7a': + // { size: 237, + // fee: 0.00000238, + // modifiedfee: 0.00000238, + // time: 1525732015, + // height: 529235, + // startingpriority: 0, + // currentpriority: 0, + // descendantcount: 10, + // descendantsize: 2376, + // descendantfees: 2380, + // ancestorcount: 3, + // ancestorsize: 712, + // ancestorfees: 714, + // depends: + // [ 'e25682caafc7000645d59f4c11d8d594b2943979b9d8fafb9f946e2b35c21b7e' ] },] + +### `getTxOut` + +Returns details about an unspent transaction output. + +#### Arguments + +1. txid `string`: The transaction id +2. n `number`: vout number +3. include_mempool `boolean` **optional**: Whether to include the mempool + +#### Result + +txOut `Promise` + +#### Examples + + (async () => { + try { + let getTxOut = await bitbox.Blockchain.getTxOut("e25682caafc7000645d59f4c11d8d594b2943979b9d8fafb9f946e2b35c21b7e", 1); + console.log(getTxOut); + } catch(error) { + console.error(error) + } + })() + + // null + +### `getTxOutProof` + +Returns a hex-encoded proof that "txid" was included in a block. + +#### Arguments + +- txids: + - `string`: A single string containing a txid. + - `string[]` + +#### Result + +- proof: + - `Promise`: A string that is a serialized, hex-encoded data for the proof. + - `Promise`: Array of strings that are a serialized, hex-encoded data for the proof. + +#### Examples + + (async () => { + try { + let getTxOutProof = await bitbox.Blockchain.getTxOutProof("e25682caafc7000645d59f4c11d8d594b2943979b9d8fafb9f946e2b35c21b7e"); + console.log(getTxOutProof); + } catch(error) { + console.error(error) + } + })() + + // "0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01" + + (async () => { + try { + let getTxOutProof = await bitbox.Blockchain.getTxOutProof([ + "e25682caafc7000645d59f4c11d8d594b2943979b9d8fafb9f946e2b35c21b7e", + "d16662463fd98eb96c8f6898d58a4461ac3d0120f4d0aea601d72b37759f261c" + ]); + console.log(getTxOutProof); + } catch(error) { + console.error(error) + } + })() + + // [ + // "010000007de867cc8adc5cc8fb6b898ca4462cf9fd667d7830a275277447e60800000000338f121232e169d3100edd82004dc2a1f0e1f030c6c488fa61eafa930b0528fe021f7449ffff001d36b4af9a0100000001338f121232e169d3100edd82004dc2a1f0e1f030c6c488fa61eafa930b0528fe0101", + // "010000007de867cc8adc5cc8fb6b898ca4462cf9fd667d7830a275277447e60800000000338f121232e169d3100edd82004dc2a1f0e1f030c6c488fa61eafa930b0528fe021f7449ffff001d36b4af9a0100000001338f121232e169d3100edd82004dc2a1f0e1f030c6c488fa61eafa930b0528fe0101" + // ] + + + + + + + +### `verifyTxOutProof` + +Verifies that a proof points to a transaction in a block, returning the +transaction it commits to and throwing an RPC error if the block is not in our +best chain + +#### Arguments + +- proof (required): + - `string`: The hex-encoded proof generated by gettxoutproof + - `string[]`: The hex-encoded proof generated by gettxoutproof + +#### Result + +- txids `Promise`: The txid(s) which the proof commits to, or empty array if the proof is invalid + +#### Examples + + (async () => { + try { + const proof = "0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01" + let verifyTxOutProof = await bitbox.Blockchain.verifyTxOutProof(proof); + console.log(verifyTxOutProof); + } catch(error) { + console.error(error) + } + })() + + // [ + // "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7" + // ] + + (async () => { + try { + const proof = "0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01" + let verifyTxOutProof = await bitbox.Blockchain.verifyTxOutProof([proof, proof]); + console.log(verifyTxOutProof); + } catch(error) { + console.error(error) + } + })() + + // [ + // "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7", + // "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7" + // ] + +## Interfaces + +### MempoolInfo + + { + size: number + bytes: number + usage: number + maxmempool: number + mempoolminfee: number + } + +### BlockchainInfo + + { + chain: string + blocks: number + headers: number + bestblockhash: string + difficulty: number + mediantime: number + verificationprogress: number + chainwork: string + pruned: boolean + softforks: object[] + bip9_softforks: object + } + +### BlockHeader + + { + hash: string + confirmations: number + height: number + version: number + versionHex: string + merkleroot: string + time: number + mediantime: number + nonce: number + bits: string + difficulty: number + chainwork: string + previousblockhash: string + nextblockhash: string + } + +### ChainTip + + { + height: number + hash: string + branchlen: number + status: string + } + +### TxOut + + { + bestblock: string + confirmations: number + value: number + scriptPubKey: { + asm: string + hex: string + reqSigs: number + type: string + addresses: string[] + } + version: number + coinbase: boolean + } diff --git a/docs/cashAccounts.md b/docs/cashAccounts.md new file mode 100644 index 00000000..7c3f8ea7 --- /dev/null +++ b/docs/cashAccounts.md @@ -0,0 +1,191 @@ +# CashAccounts + +### `lookup` + +Returns an object containing account info + +#### Arguments + +1. account `string` **required** +2. number `number` **required** +3. collision `number` **optional** + +#### Result + +cashAccount `CashAccountInterface` + +#### Examples + + (async () => { + try { + let cashAccounts = await bitbox.CashAccounts.lookup("cgcardona", 122) + console.log(cashAccounts) + } catch (error) { + console.log(error) + } + })() + + // returns + { + identifier: "cgcardona#122;", + information: { + emoji: "🍞", + name: "cgcardona", + number: 122, + collision: { + hash: "6383276713", + count: 0, + length: 0 + }, + payment: [ + { + type: "Key Hash", + address: "bitcoincash:qrhncn6hgkhljqg4fuq4px5qg74sjz9fqqj64s9la9" + } + ] + } + } + +### `check` + +Returns an object containing block height and inclusion proof for independent verification + +#### Arguments + +1. account `string` **required** +2. number `number` **required** + +#### Result + +cashAccount `CashAccountCheckResult` + +#### Examples + + (async () => { + try { + let check = await bitbox.CashAccounts.check("cgcardona", 122) + console.log(check) + } catch (error) { + console.log(error) + } + })() + + // returns + { + "identifier": "cgcardona#122", + "block": 563742, + "results": [ + { + "transaction": "0100000001A8421264294082C08C0611E162BD49999443EF577C57923BD052F7202B09408E010000006A473044022039F4DD9AD6BC2C4E799D135BB68B5E05E71F83731EFC63260C7FB16F63BB842802203DEA9E82E97D28ADC9A9567E16762CF3663C24CE6A42AEDDC1E273E50B8CA9C941210202435C144A77C6ED76C3A74EE6006A9255B449F1B2F09FA2668027FEC106CFA1FFFFFFFF020000000000000000266A0401010101096367636172646F6E611501EF3C4F5745AFF901154F01509A8047AB0908A9008CD51100000000001976A914919908484336464C2A9938D24149A4177606340F88AC00000000", + "inclusionProof": "0000C020C98F109DA027EB72472AC903F6E2BFA993D88724734B2C01000000000000000019213AEE113214AF03EEEE303F733708AD79F259A148F4A17C496302E1D093DF7D9D2E5C4CE10418F2AE48C41F000000067AA86CA831AB260AF59E0ED93305939D9A300BD66076EB18D155143E992950C33A46C140D7202C577D6C25DCD8F315D304285D8BD890C41925F00CC256C22CC69E1410317FD69D5A58F762EE26B469DC1909F2D0DE5E471B0AC09C686C41664585DF32ABA0EEAF50B6AB66010206DE24A5C576CBC331EF153507E9E20D1C18506E24DBEDB0A0B66705E10376CD19ADB4A605098058ACB805D24456CC004CCA78ABA3969F47284773B7809C81B93E2CCCC280218272164AE5D90245A629F6801802EB00" + } + ] + } + +### `reverseLookup` + +Returns an object containing block height and inclusion proof for independent verification + +#### Arguments + +1. cashAddress `string` **required** + +#### Result + +reverseLookup `CashAccountReverseLookupResult` + +#### Examples + + (async () => { + try { + let reverseLookup = await bitbox.CashAccounts.reverseLookup("bitcoincash:qr4aadjrpu73d2wxwkxkcrt6gqxgu6a7usxfm96fst") + console.log(check) + } catch (error) { + console.log(error) + } + })() + + // returns + { + "results": [ + { + "accountEmoji": "☯", + "nameText": "Jonathan", + "accountNumber": 100, + "accountHash": "5876958390", + "accountCollisionLength": 0, + "payloadType": 1, + "payloadAddress": "bitcoincash:qr4aadjrpu73d2wxwkxkcrt6gqxgu6a7usxfm96fst" + }, + { + "accountEmoji": "🍭", + "nameText": "ConfirmationTest", + "accountNumber": 113, + "accountHash": "4640561912", + "accountCollisionLength": 0, + "payloadType": 1, + "payloadAddress": "bitcoincash:qr4aadjrpu73d2wxwkxkcrt6gqxgu6a7usxfm96fst" + }, + { + "accountEmoji": "🌽", + "nameText": "Bob", + "accountNumber": 4035, + "accountHash": "7443382842", + "accountCollisionLength": 0, + "payloadType": 1, + "payloadAddress": "bitcoincash:qr4aadjrpu73d2wxwkxkcrt6gqxgu6a7usxfm96fst" + }, + { + "accountEmoji": "🎀", + "nameText": "qr4aadjrpu73d2wxwkxkcrt6gqxgu6a7usxfm96fst", + "accountNumber": 7084, + "accountHash": "4319915751", + "accountCollisionLength": 0, + "payloadType": 1, + "payloadAddress": "bitcoincash:qr4aadjrpu73d2wxwkxkcrt6gqxgu6a7usxfm96fst" + } + ] + } + +## Interfaces + +### CashAccountInterface + + { + identifier: string + information: { + emoji: string + name: string + number: number + collision: { + hash: string + } + payment: string[] + } + } + +### CashAccountCheckResult + + { + identifier: string + block: number + results: string[] + } + +### CashAccountReverseLookupResult + + { + results: SingleCashAccountReverseLookupResult[] + } + +### SingleCashAccountReverseLookupResult + + { + accountEmoji: any + nameText: string + accountNumber: number + accountHash: string + accountCollisionLength: number + payloadType: number + payloadAddress: string + } diff --git a/docs/console.md b/docs/console.md new file mode 100644 index 00000000..da5d365b --- /dev/null +++ b/docs/console.md @@ -0,0 +1,38 @@ +# Console + +Launch a console w/ the entire Bitcoin Cash RPC available as well as dozens of helper methods via a built in `BITBOX` object. Pass in an `--environment` flag to connect to environments defined in a local `bitbox.js`. By default console will connect to your development environment. + +```bash +$ bitbox console --environment production +> bitbox. +bitbox.Address bitbox.BitcoinCash bitbox.Block bitbox.Blockchain bitbox.Control bitbox.Crypto bitbox.ECPair bitbox.Generating bitbox.restURL +bitbox.HDNode bitbox.Mining bitbox.Mnemonic bitbox.Network bitbox.Price bitbox.RawTransactions bitbox.Script bitbox.Socket +bitbox.Transaction bitbox.TransactionBuilder bitbox.Util +``` + +### Quickly test your ideas + +```javascript +bitbox console + +> bitbox.BitcoinCash.toSatoshi(9) +// 900000000 + +> bitbox.Address.toLegacyAddress('bitcoincash:qzm47qz5ue99y9yl4aca7jnz7dwgdenl85jkfx3znl') +// 1HiaTupadqQN66Tvgt7QSE5Wg13BUy25eN + +// create mnemonic +> let mnemonic = bitbox.Mnemonic.generate(128); +// ancient slide suggest chaos vivid property trophy faith bamboo lunch save hint + +// create seed buffer from mnemonic +> let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + +// create HDNode from seed buffer +> let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + +// derive hardened child HDNode +> let childNode = bitbox.HDNode.derivePath(hdNode, "m/44'/145'/0'"); +> bitbox.HDNode.toXPriv(childNode) +// xprv9yHczLBaxwHo85o8mJVHSu1ghxEWM2QZcrvWFvHWXgkqfuqNz6EDNxv4wAPTBwX7nkrnBTPgdCZi7qyQAF72MF4KTq9UzzygDhvBajpwScs +``` diff --git a/docs/control.md b/docs/control.md new file mode 100644 index 00000000..884d53e7 --- /dev/null +++ b/docs/control.md @@ -0,0 +1,135 @@ +# Control + +### `getInfo` + +Returns an object containing various state info. + +#### Result + +info `Promise` + +#### Examples + + (async () => { + try { + let getInfo = await bitbox.Control.getInfo(); + console.log(getInfo); + } catch(error) { + console.error(error) + } + })() + + // { version: 170000, + // protocolversion: 70015, + // blocks: 529235, + // timeoffset: 0, + // connections: 35, + // proxy: '', + // difficulty: 702784497476.8376, + // testnet: false, + // paytxfee: 0, + // relayfee: 0.00001, + // errors: '' } + +### `getNetworkInfo` + +Returns an object containing various network info. + +#### Result + +networkInfo `Promise` + +#### Examples + + (async () => { + try { + let getInfo = await bitbox.Control.getNetworkInfo(); + console.log(getInfo); + } catch(error) { + console.error(error) + } + })() + + // returns + { version: 190500, + subversion: '/Bitcoin ABC:0.19.5(EB32.0)/', + protocolversion: 70015, + localservices: '0000000000000425', + localrelay: true, + timeoffset: 0, + networkactive: true, + connections: 17, + networks: + [ { name: 'ipv4', + limited: false, + reachable: true, + proxy: '', + proxy_randomize_credentials: false }, + { name: 'ipv6', + limited: false, + reachable: true, + proxy: '', + proxy_randomize_credentials: false }, + { name: 'onion', + limited: true, + reachable: false, + proxy: '', + proxy_randomize_credentials: false } ], + relayfee: 0.00001, + excessutxocharge: 0, + warnings: + 'Warning: Unknown block versions being mined! It\'s possible unknown rules are in effect' }} + +## Interfaces + +### NodeInfo + + { + version: number + protocolversion: number + blocks: number + timeoffset: number + connections: number + proxy: string + difficulty: number + testnet: boolean + paytxfee: number + relayfee: number + errors: string + } + +### NetworkInfo + + { + version: number + subversion: string + protocolversion: number + localservices: string, + localrelay: boolean, + timeoffset: number, + networkactive: boolean, + connections: number, + networks: + [ { name: string, + limited: boolean, + reachable: boolean, + proxy: string, + proxy_randomize_credentials: boolean } + ], + relayfee: number, + excessutxocharge: number, + warnings: string + } + + diff --git a/docs/crypto.md b/docs/crypto.md new file mode 100644 index 00000000..5546a9cf --- /dev/null +++ b/docs/crypto.md @@ -0,0 +1,175 @@ +# Crypto + +### `sha1` + +Utility for creating sha1 hash digests of data + +#### Arguments + +1. buffer `Buffer`: data to be hashed + +#### Result + +buffer `Buffer`: sha1 hash of data + +#### Examples + + // buffer from hex + let buffer = Buffer.from('0101010101010101', 'hex') + bitbox.Crypto.sha1(buffer) + // + + // buffer from hex + let buffer = Buffer.from('031ad329b3117e1d1e2974406868e575d48cff88e8128ba0eedb10da053785033b', 'hex') + bitbox.Crypto.sha1(buffer) + // + + // buffer from hex + let buffer = Buffer.from('03123464075c7a5fa6b8680afa2c962a02e7bf071c6b2395b0ac711d462cac9354', 'hex') + bitbox.Crypto.sha1(buffer) + // + +### `sha256` + +Utility for creating sha256 hash digests of data + +#### Arguments + +1. buffer `Buffer`: data to be hashed + +#### Result + +buffer `Buffer`: sha1 hash of data + +#### Examples + + // buffer from hex + let buffer = Buffer.from('0101010101010101', 'hex') + bitbox.Crypto.sha256(buffer) + // + + // buffer from hex + let buffer = Buffer.from('031ad329b3117e1d1e2974406868e575d48cff88e8128ba0eedb10da053785033b', 'hex') + bitbox.Crypto.sha256(buffer) + // + + // buffer from hex + let buffer = Buffer.from('03123464075c7a5fa6b8680afa2c962a02e7bf071c6b2395b0ac711d462cac9354', 'hex') + bitbox.Crypto.sha256(buffer) + // + +### `ripemd160` + +Utility for creating ripemd160 hash digests of data + +#### Arguments + +1. buffer `Buffer`: data to be hashed + +#### Result + +buffer `Buffer`: ripemd160 hash of data + +#### Examples + + // buffer from hex + let buffer = Buffer.from('0101010101010101', 'hex') + bitbox.Crypto.ripemd160(buffer) + // + + // buffer from hex + let buffer = Buffer.from('75618d82d1f6251f2ef1f42f5f0d5040330948a707ff6d69720dbdcb00b48aab', 'hex') + bitbox.Crypto.ripemd160(buffer) + // + + // buffer from hex + let buffer = Buffer.from('978c09dd46091d1922fa01e9f4a975b91a371f26ba8399de27d53801152121de', 'hex') + bitbox.Crypto.ripemd160(buffer) + // + +### `hash256` + +Utility for creating double sha256 hash digests of data + +#### Arguments + +1. buffer `Buffer`: data to be hashed + +#### Result + +buffer `Buffer`: double sha256 hash of data + +#### Examples + + // buffer from hex + let buffer = Buffer.from('0101010101010101', 'hex') + bitbox.Crypto.hash256(buffer) + // + + // buffer from hex + let buffer = Buffer.from('031ad329b3117e1d1e2974406868e575d48cff88e8128ba0eedb10da053785033b', 'hex') + bitbox.Crypto.hash256(buffer) + // + + // buffer from hex + let buffer = Buffer.from('03123464075c7a5fa6b8680afa2c962a02e7bf071c6b2395b0ac711d462cac9354', 'hex') + bitbox.Crypto.hash256(buffer) + // + +### `hash160` + +Utility for creating ripemd160(sha256()) hash digests of data + +#### Arguments + +1. buffer `Buffer`: data to be hashed + +#### Result + +buffer `Buffer`: ripemd160(sha256()) hash of data + +#### Examples + + // buffer from hex + let buffer = Buffer.from('0101010101010101', 'hex') + bitbox.Crypto.hash160(buffer) + // + + // buffer from hex + let buffer = Buffer.from('031ad329b3117e1d1e2974406868e575d48cff88e8128ba0eedb10da053785033b', 'hex') + bitbox.Crypto.hash160(buffer) + // + + // buffer from hex + let buffer = Buffer.from('03123464075c7a5fa6b8680afa2c962a02e7bf071c6b2395b0ac711d462cac9354', 'hex') + bitbox.Crypto.hash160(buffer) + // + +### `randomBytes` + +Generates cryptographically strong pseudo\-random data. The size argument is a number indicating the number of bytes to generate. + +#### Arguments + +1. numBytes `number`: number of bytes to generate + +#### Result + +buffer `Buffer`: random bytes encoded as a buffer + +#### Examples + + bitbox.Crypto.randomBytes(16) + // + + bitbox.Crypto.randomBytes(20) + // + + bitbox.Crypto.randomBytes(24) + // + + bitbox.Crypto.randomBytes(28) + // + + bitbox.Crypto.randomBytes(32) + // diff --git a/docs/ecpair.md b/docs/ecpair.md new file mode 100644 index 00000000..3a9f47e3 --- /dev/null +++ b/docs/ecpair.md @@ -0,0 +1,243 @@ +# ECPair + +### `fromWIF` + +Generates an ECPair from a private key in wallet import format ([WIF](https://github.com/Bitcoin-com/mastering-bitcoin-cash/blob/master/3-keys-addresses-wallets.md#private-key-formats)). Follow these [steps to go from a private key to a WIF](https://en.bitcoin.it/wiki/Wallet_import_format). This method only works with a [compressed private key](https://github.com/Bitcoin-com/mastering-bitcoin-cash/blob/master/3-keys-addresses-wallets.md#compressed-public-keys). + +#### Arguments + +1. wif `string`: private key in wallet import format ([WIF](https://github.com/Bitcoin-com/mastering-bitcoin-cash/blob/master/3-keys-addresses-wallets.md#compressed-public-keys)) + +#### Result + +ecpair `ECPair` + +#### Examples + + // mainnet WIF + let wif = 'L4vmKsStbQaCvaKPnCzdRArZgdAxTqVx8vjMGLW5nHtWdRguiRi1'; + bitbox.ECPair.fromWIF(wif); + + // testnet WIF + let wif = 'cSNLj6xeg3Yg2rfcgKoWNx4MiAgn9ugCUUro37UDEhn6CzeYqjWW' + bitbox.ECPair.fromWIF(wif) + +### `toWIF` + +Gets a private key in wallet import format from an ECPair. + +#### Arguments + +1. ecpair `ECPair` + +#### Result + +wif `string`: private key in wallet import format + +#### Examples + + // mainnet wif + let wif = 'L4vmKsStbQaCvaKPnCzdRArZgdAxTqVx8vjMGLW5nHtWdRguiRi1'; + // ecpair from wif + let ecpair = bitbox.ECPair.fromWIF(wif); + // wif from ecpair + bitbox.ECPair.toWIF(ecpair); + // L4vmKsStbQaCvaKPnCzdRArZgdAxTqVx8vjMGLW5nHtWdRguiRi1 + + // testnet wif + let wif = 'cT3tJP7BnjFJSAHbooMXrY8E9t2AFj37amSBAYFMeHfqPqPgD4ZA'; + // ecpair from wif + let ecpair = bitbox.ECPair.fromWIF(wif); + // wif from ecpair + bitbox.ECPair.toWIF(ecpair); + // cT3tJP7BnjFJSAHbooMXrY8E9t2AFj37amSBAYFMeHfqPqPgD4ZA + +### `fromPublicKey` + +Generates an ECPair from a public key buffer. + +#### Arguments + +1. buffer `Buffer`: public key buffer + +#### Result + +ecpair `ECPair` + +#### Examples + + // create ECPair from mainnet pubkeyBuffer + let pubkeyBuffer = Buffer.from("02fb721b92025e775b1b84774e65d568d24645cb633275f5c26f5c3101b214a8fb", 'hex'); + bitbox.ECPair.fromPublicKey(pubkeyBuffer); + + // create ECPair from testnet pubkeyBuffer + let pubkeyBuffer = Buffer.from("024a6d0737a23c472d078d78c1cbc3c2bbf8767b48e72684ff03a911b463da7fa6", 'hex'); + bitbox.ECPair.fromPublicKey(pubkeyBuffer); + +### `toPublicKey` + +Get the public key of an ECPair as a buffer. + +#### Arguments + +1. ecpair `ECPair` + +#### Result + +buffer `Buffer`: public key of an ECPair as a buffer + +#### Examples + + // create ecpair from mainnet public key buffer + let ecpair = bitbox.ECPair.fromPublicKey(Buffer.from('02d305772e0873fba6c1c7ff353ce374233316eb5820acd7ff3d7d9b82d514126b', 'hex')); + // create public key buffer + bitbox.ECPair.toPublicKey(ecpair); + // + + // create ecpair from testnet public key buffer + let ecpair = bitbox.ECPair.fromPublicKey(Buffer.from('024a6d0737a23c472d078d78c1cbc3c2bbf8767b48e72684ff03a911b463da7fa6', 'hex')); + // create public key buffer + bitbox.ECPair.toPublicKey(ecpair); + // + +### `toLegacyAddress` + +Get legacy address of ECPair + +#### Arguments + +1. ecpair `ECPair` + +#### Result + +legacyAddress `string`: legacy base58check encoded address of an ECPair + +#### Examples + + // mainnet wif + let wif = 'L5GPEGxCmojgzFoBLUUqT2GegLGqobiYhTZzfLtpkLTfTb9E9NRn'; + // ecpair from wif + let ecpair = bitbox.ECPair.fromWIF(wif); + // to legacy address + bitbox.ECPair.toLegacyAddress(ecpair); + // 1DgxdA5bbMcCNWg3yB2MgKqFazV92BXgxK + + // testnet wif + let wif = 'cSNLj6xeg3Yg2rfcgKoWNx4MiAgn9ugCUUro37UDEhn6CzeYqjWW'; + // ecpair from wif + let ecpair = bitbox.ECPair.fromWIF(wif); + // to legacy address + bitbox.ECPair.toLegacyAddress(ecpair); + // mg4PygFcXoyNJGJkM2Dcpe25av9wXzz1My + +### `toCashAddress` + +Get cash address of ECPair + +#### Arguments + +1. ecpair `ECPair` +2. regtest `boolean` **optional**: return regtest address + +#### Result + +cashAddress `string`: cashaddr encoded address of an ECPair + +#### Examples + + // mainnet wif + let wif = 'L5GPEGxCmojgzFoBLUUqT2GegLGqobiYhTZzfLtpkLTfTb9E9NRn'; + // ecpair from wif + let ecpair = bitbox.ECPair.fromWIF(wif); + // to legacy address + bitbox.ECPair.toCashAddress(ecpair); + // bitcoincash:qz9nq206kteyv2t7trhdr4vzzkej60kqtytn7sxkxm + + // testnet wif + let wif = 'cSNLj6xeg3Yg2rfcgKoWNx4MiAgn9ugCUUro37UDEhn6CzeYqjWW'; + // ecpair from wif + let ecpair = bitbox.ECPair.fromWIF(wif); + // to legacy address + bitbox.ECPair.toCashAddress(ecpair); + // bchtest:qqzly4vrcxcjw62u4yq4nv86ltk2mc9v0yvq8mvj6m + +### `sign` + +Sign 32 byte hash encoded as a buffer + +#### Arguments + +1. ecpair `ECPair` +2. buffer `Buffer`: 32 byte Buffer +3. signatureAlgorithm: `number` **optional**. `0x00` for ECDSA and `0x01` for Schnorr. Defaults to `0x00` + +#### Result + +signature `Object` + +#### Examples + + // mainnet wif + let wif = 'Kxq2EzVbDwjquUt5zyCFED5FRt99RZKEKVDJWTQcpSDoLAWMqLer'; + // ecpair from wif + let ecpair = bitbox.ECPair.fromWIF(wif); + // 32 byte buffer + let buf = Buffer.from(bitbox.Crypto.sha256('EARTH'), 'hex'); + // sign + bitbox.ECPair.sign(ecpair, buf); + + // testnet wif + let wif = 'cT3tJP7BnjFJSAHbooMXrY8E9t2AFj37amSBAYFMeHfqPqPgD4ZA'; + // ecpair from wif + let ecpair = bitbox.ECPair.fromWIF(wif); + // 32 byte buffer + let buf = Buffer.from(bitbox.Crypto.sha256('EARTH'), 'hex'); + // sign + bitbox.ECPair.sign(ecpair, buf); + +### `verify` + +Verify signed 32 byte hash encoded as a buffer + +#### Arguments + +1. ecpair `ECPair` +2. buffer `Buffer`: 32 byte Buffer +3. signature `ECSignature` + +#### Result + +verified `boolean` + +#### Examples + + // mainnet wifs + let wif1 = 'Kxq2EzVbDwjquUt5zyCFED5FRt99RZKEKVDJWTQcpSDoLAWMqLer'; + let wif2 = 'L4BwXDmjzEyzKHbAfGruhieUDPs8KTx7DMgqPk4aF9GefzgqPENV'; + // ecpairs from wifs + let ecpair1 = bitbox.ECPair.fromWIF(wif1); + let ecpair2 = bitbox.ECPair.fromWIF(wif2); + // 32 byte buffer + let buf = Buffer.from(bitbox.Crypto.sha256('EARTH'), 'hex'); + // sign + let signature = bitbox.ECPair.sign(ecpair1, buf); + // verify + bitbox.ECPair.verify(ecpair1, buf, signature); + // true + bitbox.ECPair.verify(ecpair2, buf, signature); + // false + + // testnet wifs + let wif1 = 'cT3tJP7BnjFJSAHbooMXrY8E9t2AFj37amSBAYFMeHfqPqPgD4ZA'; + let wif2 = 'cRaFawZ49jEV2X3byAV4iGBYCRBVU8PoBzUMVToeEbFeVzbH4Gi7'; + // ecpairs from wifs + let ecpair1 = bitbox.ECPair.fromWIF(wif1); + let ecpair2 = bitbox.ECPair.fromWIF(wif2); + // 32 byte buffer + let buf = Buffer.from(bitbox.Crypto.sha256('EARTH'), 'hex'); + // sign + let signature = bitbox.ECPair.sign(ecpair1, buf); + // verify + bitbox.ECPair.verify(ecpair1, buf, signature); + // true + bitbox.ECPair.verify(ecpair2, buf, signature); diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 00000000..43fbb20f --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,129 @@ +# Getting Started + +### Dependencies + +#### NodeJS + +NodeJS is a javascript runtime build on Chrome’s V8 engine. npm is the package manager for NodeJS. + +Use the official installer from [nodejs.org](https://nodejs.org/). Install the one which says “Recommended for Most Users” + +### Command Line + +To use commands like `new` and `console`: + + npm install bitbox-cli --global + // installs a `bitbox` command + +To use inside a client/server app: + + npm install bitbox-sdk --save + +### Usage + +Import BITBOX into your code: + + // require syntax + let BITBOX = require('bitbox-sdk').BITBOX; + let bitbox = new BITBOX(); + bitbox.Mnemonic.generate() + // couple sleep cruise hybrid physical nature spin hedgehog put paddle silver laundry + + // import syntax + import { BITBOX } from 'bitbox-sdk' + let bitbox = new BITBOX(); + bitbox.Mnemonic.generate() + // whip mind item rapid use cigar gap inherit shove weasel similar stick + +All classes are able to be included via both `require` and `import` + + // require syntax + const Address = require("bitbox-sdk").Address + let address = new Address() + const BitcoinCash = require("bitbox-sdk").BitcoinCash + let bitcoincash = new BitcoinCash() + const BitDB = require("bitbox-sdk").BitDB + let bitdb = new BitDB() + const Block = require("bitbox-sdk").Block + let block = new Block() + const Blockchain = require("bitbox-sdk").Blockchain + let blockchain = new Blockchain + const CashAccounts = require("bitbox-sdk").CashAccounts + let cashAccounts = new CashAccounts() + const Control = require("bitbox-sdk").Control + let control = new Control() + const Crypto = require("bitbox-sdk").Crypto + let crypto = new Crypto() + const ECPair = require("bitbox-sdk").ECPair + let ecpair = new ECPair() + const Generating = require("bitbox-sdk").Generating + let generating = new Generating() + const HDNode = require("bitbox-sdk").HDNode + let hdnode = new HDNode() + const Mining = require("bitbox-sdk").Mining + let mining = new Mining() + const Mnemonic = require("bitbox-sdk").Mnemonic + let mnemonic = new Mnemonic() + const Price = require("bitbox-sdk").Price + let price = new Price() + const RawTransactions = require("bitbox-sdk").RawTransactions + let rawtransactions = new RawTransactions() + const Schnorr = require("bitbox-sdk").Schnorr + let schnorr = new Schnorr + const Script = require("bitbox-sdk").Script + let script = new Script() + const Socket = require("bitbox-sdk").Socket + let socket = new Socket() + const Transaction = require("bitbox-sdk").Transaction + let transaction = new Transaction + const TransactionBuilder = require("bitbox-sdk").TransactionBuilder + let transactionbuilder = new TransactionBuilder() + const Util = require("bitbox-sdk").Util + let util = new Util() + + // import syntax + import { + Address, + BitcoinCash, + BitDB, + Block, + Blockchain, + CashAccounts, + Control, + Crypto, + ECPair, + Generating, + HDNode, + Mining, + Mnemonic, + Price, + RawTransactions, + Schnorr, + Script, + Socket, + Transaction, + TransactionBuilder, + Util + } from "bitbox-sdk" + + let address = new Address() + let bitcoincash = new BitcoinCash() + let bitdb = new BitDB() + let block = new Block() + let blockchain = new Blockchain + let cashAccounts = new CashAccounts() + let control = new Control() + let crypto = new Crypto() + let ecpair = new ECPair() + let generating = new Generating() + let hdnode = new HDNode() + let mining = new Mining() + let mnemonic = new Mnemonic() + let price = new Price() + let rawtransactions = new RawTransactions() + let schnorr = new Schnorr + let script = new Script() + let socket = new Socket() + let transaction = new Transaction + let transactionbuilder = new TransactionBuilder() + let util = new Util() diff --git a/docs/hdnode.md b/docs/hdnode.md new file mode 100644 index 00000000..adb3b2f0 --- /dev/null +++ b/docs/hdnode.md @@ -0,0 +1,670 @@ +# HDNode + +HDNode stands for Hierarchically Deterministic node which can be used to create a [HD wallet](https://github.com/Bitcoin-com/mastering-bitcoin-cash/blob/master/3-keys-addresses-wallets.md#hierarchical-deterministic-wallets-bip0032bip0044). + +### `fromSeed` + +Create HDNode from Seed Buffer. + +#### Arguments + +1. rootSeed `Buffer`: root seed buffer +2. network `string` **optional**: network. default: 'mainnet' + +#### Result + +HDNode `HDNode` + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + bitbox.HDNode.fromSeed(seedBuffer); + + // generate entropy + let entropy = bitbox.Crypto.randomBytes(32); + // create mnemonic from entropy + let mnemonic = bitbox.Mnemonic.fromEntropy(entropy); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + bitbox.HDNode.fromSeed(seedBuffer); + +### `derive` + +Derive [non hardened](https://github.com/Bitcoin-com/mastering-bitcoin-cash/blob/master/3-keys-addresses-wallets.md#hardened-child-key-derivation) child HDNode + +#### Arguments + +1. hdnode `HDNode` +2. num `number`: number of child node. Ex: 0 + +#### Result + +HDNode `HDNode` + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // derive unhardened child HDNode + bitbox.HDNode.derive(hdNode, 0); + +### `deriveHardened` + +Derive [hardened](https://github.com/Bitcoin-com/mastering-bitcoin-cash/blob/master/3-keys-addresses-wallets.md#hardened-child-key-derivation) child HDNode + +#### Arguments + +1. hdnode `HDNode` +2. num `number`: number of child node. Ex: 0 + +#### Result + +HDNode `HDNode` + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // derive hardened child HDNode + bitbox.HDNode.deriveHardened(hdNode, 0); + +### `derivePath` + +Derive child HDNode from path + +#### Arguments + +1. hdnode `HDNode` +2. path `string`: path of child hd node. Ex: "m/44'/145'/0'" + +#### Result + +HDNode `HDNode` + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // derive hardened child HDNode + bitbox.HDNode.derivePath(hdNode, "m/44'/145'/0'"); + +### `toLegacyAddress` + +Get legacy address of HDNode + +#### Arguments + +1. hdnode `HDNode` + +#### Result + +legacyAddress `string`: legacy base58check encoded address of HDNode + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // to legacy address + bitbox.HDNode.toLegacyAddress(hdNode); + // 14apxtw2LDQmXWsS5k4JEhG93Jzjswhvma + + // generate entropy + let entropy = bitbox.Crypto.randomBytes(32); + // create mnemonic from entropy + let mnemonic = bitbox.Mnemonic.fromEntropy(entropy); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // to cash address + bitbox.HDNode.toLegacyAddress(hdNode); + // 14mVsq3H5Ep2Jb6AqoKsmY1BFHKCBGPDLi + +### `toCashAddress` + +Get cash address of HDNode + +#### Arguments + +1. hdnode `HDNode` +2. regtest `boolean` **optional**: return regtest address + +#### Result + +cashAddress `string`: cashaddr encoded address of HDNode + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // to cash address + bitbox.HDNode.toCashAddress(hdNode); + // bitcoincash:qqrz6kqw6nvhwgwrt4g7fggepvewtkr7nukkeqf4rw + + // generate entropy + let entropy = bitbox.Crypto.randomBytes(32); + // create mnemonic from entropy + let mnemonic = bitbox.Mnemonic.fromEntropy(entropy); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // to cash address + bitbox.HDNode.toCashAddress(hdNode); + // bitcoincash:qq549jxsjv66kw0smdju4es2axnk7hhe9cquhjg4gt + +### `toWIF` + +Get private key in wallet import format (WIF) of HDNode + +#### Arguments + +1. hdnode `HDNode` + +#### Result + +privateKeyWIF `string`: private key in wallet import format (WIF) of HDNode + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // to WIF + bitbox.HDNode.toWIF(hdNode); + // L5E8QjFnLukp8BuF4uu9gmvvSrbafioURGdBve5tA3Eq5ptzbMCJ + + // generate entropy + let entropy = bitbox.Crypto.randomBytes(32); + // create mnemonic from entropy + let mnemonic = bitbox.Mnemonic.fromEntropy(entropy); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // to WIF + bitbox.HDNode.toWIF(hdNode); + // KwobPFhv3AuXc3ps6YtWfMVRpLBDBA7jnJddurfELTyTNcFhZYpJ + +### `toXPub` + +Get [extended](https://github.com/Bitcoin-com/mastering-bitcoin-cash/blob/master/3-keys-addresses-wallets.md#extended-keys) [public key](https://github.com/Bitcoin-com/mastering-bitcoin-cash/blob/master/3-keys-addresses-wallets.md#public-key-cryptography-and-cryptocurrency) of HDNode + +#### Arguments + +1. hdnode `HDNode` + +#### Result + +xpub `string`: extended public key of HDNode + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // to extended public key + bitbox.HDNode.toXPub(hdNode); + // xpub661MyMwAqRbcG4CnhNYoK1r1TKLwQQ1UdC3LHoWFK61rsnzh7Hx35qQ9Z53ucYcE5WvA7GEDXhqqKjSY2e6Y8n7WNVLYHpXCuuX945VPuYn + + // generate entropy + let entropy = bitbox.Crypto.randomBytes(32); + // create mnemonic from entropy + let mnemonic = bitbox.Mnemonic.fromEntropy(entropy); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // to extended public key + bitbox.HDNode.toXPub(hdNode); + // xpub661MyMwAqRbcFuMLeHkSbTNwNHG9MQyrAZqV1Q4MEAsmj9MYa5sxg8WC2LKqW6EHviHVucBjWi1n38juZpDDeX3U6YrsMeACdcNSTHkM8BQ + +### `toXPriv` + +Get [extended](https://github.com/Bitcoin-com/mastering-bitcoin-cash/blob/master/3-keys-addresses-wallets.md#extended-keys) [private key](https://github.com/Bitcoin-com/mastering-bitcoin-cash/blob/master/3-keys-addresses-wallets.md#private-keys) of HDNode + +#### Arguments + +1. hdnode `HDNode` + +#### Result + +xpriv `string`: extended private key of HDNode + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // to extended private key + bitbox.HDNode.toXPriv(hdNode); + // xprv9s21ZrQH143K2eMCcbT4qwwRhw6qZaPaEDWB792bnrxQZPoP2JUk4kfEx9eeV1uGTAWAfCqYr4wDWo52qALiukizKwQzvEyNR1fWZJi97Kv + + // generate entropy + let entropy = bitbox.Crypto.randomBytes(32); + // create mnemonic from entropy + let mnemonic = bitbox.Mnemonic.fromEntropy(entropy); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // to extended private key + bitbox.HDNode.toXPriv(hdNode); + // xprv9s21ZrQH143K2b5GPP6zHz22E6LeCgQXJtwNbC3MA3Kz7Se7tveKo96EhqwFtSkYWkyenVcMqM7uq35PcUNG8cUdpsJEgwKG3dvfP7TmL3v + +### `toKeyPair` + +Get the ECPair of an HDNode + +#### Arguments + +1. hdnode `HDNode` + +#### Result + +keyPair `ECPair`: ECPair of an HDNode + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create root seed buffer from mnemonic + let rootSeed= bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from root seed + let hdNode = bitbox.HDNode.fromSeed(rootSeed); + // create public key buffer from HDNode + bitbox.HDNode.toKeyPair(hdNode); + + // generate entropy + let entropy = bitbox.Crypto.randomBytes(32); + // create mnemonic from entropy + let mnemonic = bitbox.Mnemonic.fromEntropy(entropy); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // create public key buffer from HDNode + bitbox.HDNode.toKeyPair(hdNode); + +### `toPublicKey` + +Get the public key of an HDNode as a buffer + +#### Arguments + +1. hdnode `HDNode` + +#### Result + +publicKeyBuffer `Buffer`: public key of HDNode as a buffer + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create root seed buffer from mnemonic + let rootSeed= bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from root seed + let hdNode = bitbox.HDNode.fromSeed(rootSeed); + // create public key buffer from HDNode + bitbox.HDNode.toPublicKey(hdNode); + // + + // generate entropy + let entropy = bitbox.Crypto.randomBytes(32); + // create mnemonic from entropy + let mnemonic = bitbox.Mnemonic.fromEntropy(entropy); + // create seed buffer from mnemonic + let seedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create HDNode from seed buffer + let hdNode = bitbox.HDNode.fromSeed(seedBuffer); + // create public key buffer from HDNode + bitbox.HDNode.toPublicKey(hdNode); + // + +### `toIdentifier` + +hash160 of Node’s public key. The same value you would see in a scriptPubKey. + +#### Arguments + +1. hdnode `HDNode` + +#### Result + +identifier `Buffer` + +#### Examples + + // mainnet + let xpub = 'xpub6DWfGUo4cjC8oWmgZdpyFMH6v3oeyADfdUPhsehzn5jX44zpazivha3JxUtkcCvBEB1c6DGaiUmpyz2m1DRfGDEVZ5VxLLW2UNEbZ5iTRvi'; + let node = bitbox.HDNode.fromXPub(xpub); + bitbox.HDNode.toIdentifier(node); + // + // the same as if we hash160ed it's publicKey + let publicKeyBuffer = bitbox.HDNode.toPublicKey(node); + bitbox.Crypto.hash160(publicKeyBuffer); + // + + // testnet + let xpub = 'tpubDCxmZ3qLVVphg6NpsnAjQFqDPwr9HYqSgoAcUYAfqSgo32dL6NA8QXqWsS6XTjoGggohZKvujsAv2F2ugej9qfUYau2jSUB4JaYnfMsx3MJ'; + let node = bitbox.HDNode.fromXPub(xpub); + bitbox.HDNode.toIdentifier(node); + // + // the same as if we hash160ed it's publicKey + let publicKeyBuffer = bitbox.HDNode.toPublicKey(node); + bitbox.Crypto.hash160(publicKeyBuffer); + // + +### `fromXPriv` + +Generate HDNode from extended private key + +#### Arguments + +1. xpriv `string`: extended private key + +#### Result + +hdNode `HDNode` + +#### Examples + + // mainnet xpriv + bitbox.HDNode.fromXPriv('xprv9s21ZrQH143K2b5GPP6zHz22E6LeCgQXJtwNbC3MA3Kz7Se7tveKo96EhqwFtSkYWkyenVcMqM7uq35PcUNG8cUdpsJEgwKG3dvfP7TmL3v'); + + // testnet xpriv + bitbox.HDNode.fromXPriv('tprv8gQ3zr1F5pRHMebqqhorrorYNvUG3XkcZjSWVs2cEtRwwJy1TRhgRx4XcF8dYHM2eyTbTCcdKYNhqgyBQphxwRoVyVKr9zuyoA8WxNDRvom'); + +### `fromXPub` + +Generate HDNode from extended public key + +#### Arguments + +1. xpub `string`: extended public key + +#### Result + +hdNode `HDNode` + +#### Examples + + // mainnet xpub + bitbox.HDNode.fromXPub('xpub661MyMwAqRbcFuMLeHkSbTNwNHG9MQyrAZqV1Q4MEAsmj9MYa5sxg8WC2LKqW6EHviHVucBjWi1n38juZpDDeX3U6YrsMeACdcNSTHkM8BQ'); + + // testnet xpub + bitbox.HDNode.fromXPub('tpubDD669G3VEC6xF7ddjMUTGDWewwzCCrwX933HnP4ufAELmoDn5pXGcSgPnLodjFvWQwRXkG94f77BatEDA8dfQ99yy97kRYynUpNLENEqTBo'); + +### `isPublic` + +Check if an HDNode can only derive public keys and children + +#### Arguments + +1. hdnode `HDNode` + +#### Result + +isPublic `boolean` + +#### Examples + + // mainnet xpub + let xpub = 'xpub6DWfGUo4cjC8oWmgZdpyFMH6v3oeyADfdUPhsehzn5jX44zpazivha3JxUtkcCvBEB1c6DGaiUmpyz2m1DRfGDEVZ5VxLLW2UNEbZ5iTRvi'; + let node = bitbox.HDNode.fromXPub(xpub); + bitbox.HDNode.isPublic(node); + // true + + // mainnet xpriv + let xpriv = 'xprv9ys4cvcoU8RoxqkZ7Fgt33te4LPHgcsKwyoZYVorkzp9uonWxWgP9wiSQhPeBUqVHbdAyov4Yi55RywBkDfZKdJFRqA51Anz6v72zGaMGZp'; + let node = bitbox.HDNode.fromXPriv(xpriv); + bitbox.HDNode.isPublic(node); + // false + + // testnet xpub + let xpub = 'tpubDCxmZ3qLVVphg6NpsnAjQFqDPwr9HYqSgoAcUYAfqSgo32dL6NA8QXqWsS6XTjoGggohZKvujsAv2F2ugej9qfUYau2jSUB4JaYnfMsx3MJ'; + let node = bitbox.HDNode.fromXPub(xpub); + bitbox.HDNode.isPublic(node); + // true + + // testnet xpriv + let xpriv = 'tprv8ggxJ8SG5EdqakzVUeLa9Gr7sqCdEcJPUNDmtdJscNxfmxoXvU36ZguiUWukJVEWEixAUr8pJabJkCt33wzxFQA587gqN51Lxdxx97zAzuG'; + let node = bitbox.HDNode.fromXPriv(xpriv); + bitbox.HDNode.isPublic(node); + // false + +### `isPrivate` + +Check if an HDNode can derive both public and private keys and children + +#### Arguments + +1. hdnode `HDNode` + +#### Result + +isPrivate `boolean` + +#### Examples + + // mainnet xpub + let xpub = 'xpub6DWfGUo4cjC8oWmgZdpyFMH6v3oeyADfdUPhsehzn5jX44zpazivha3JxUtkcCvBEB1c6DGaiUmpyz2m1DRfGDEVZ5VxLLW2UNEbZ5iTRvi'; + let node = bitbox.HDNode.fromXPub(xpub); + bitbox.HDNode.isPrivate(node); + // false + + // mainnet xpriv + let xpriv = 'xprv9ys4cvcoU8RoxqkZ7Fgt33te4LPHgcsKwyoZYVorkzp9uonWxWgP9wiSQhPeBUqVHbdAyov4Yi55RywBkDfZKdJFRqA51Anz6v72zGaMGZp'; + let node = bitbox.HDNode.fromXPriv(xpriv); + bitbox.HDNode.isPrivate(node); + // true + + // testnet xpub + let xpub = 'tpubDCxmZ3qLVVphg6NpsnAjQFqDPwr9HYqSgoAcUYAfqSgo32dL6NA8QXqWsS6XTjoGggohZKvujsAv2F2ugej9qfUYau2jSUB4JaYnfMsx3MJ'; + let node = bitbox.HDNode.fromXPub(xpub); + bitbox.HDNode.isPrivate(node); + // false + + // testnet xpriv + let xpriv = 'tprv8ggxJ8SG5EdqakzVUeLa9Gr7sqCdEcJPUNDmtdJscNxfmxoXvU36ZguiUWukJVEWEixAUr8pJabJkCt33wzxFQA587gqN51Lxdxx97zAzuG'; + let node = bitbox.HDNode.fromXPriv(xpriv); + bitbox.HDNode.isPrivate(node); + // true + +### `sign` + +Sign 32 byte hash encoded as a buffer + +#### Arguments + +1. hdnode `HDNode` +2. buffer `Buffer` + +#### Result + +signature `ECSignature` + +#### Examples + + // mainnet xpriv + let xpriv = 'xprv9z2uWrGjbYPxc728rvtMi4jt4SudRiSfYn6Tdif5XN17pJ1NTbHoHK6JePkPLY1NHXLaQcA6sWudpZDm7DwKhbsGQieAp9wx46Wbio4iXg9'; + // hdnode from xpriv + let hdnode = bitbox.HDNode.fromXPriv(xpriv); + // 32 byte buffer + let buf = Buffer.from(bitbox.Crypto.sha256('EARTH'), 'hex'); + // sign + bitbox.HDNode.sign(hdnode, buf); + + // testnet xpriv + let xpriv = 'tprv8ggxJ8SG5EdqakzVUeLa9Gr7sqCdEcJPUNDmtdJscNxfmxoXvU36ZguiUWukJVEWEixAUr8pJabJkCt33wzxFQA587gqN51Lxdxx97zAzuG'; + // hdnode from xpriv + let hdnode = bitbox.HDNode.fromXPriv(xpriv); + // 32 byte buffer + let buf = Buffer.from(bitbox.Crypto.sha256('EARTH'), 'hex'); + // sign + bitbox.HDNode.sign(hdnode, buf); + +### `verify` + +Verify signed 32 byte hash encoded as a buffer + +#### Arguments + +1. hdnode `HDNode` +2. buffer `Buffer` +3. signature `ECSignature` + +#### Result + +verified `boolean` + +#### Examples + + // mainnet xprivs + let xpriv1 = 'xprv9ys4cvcoU8RoqvzxGj886r4Ey3w1WfVNYH8sMnVPVzyQtaPPM6Q8pHm3D9WPWvEupGEgcJ1xLaGaZDcvKfoAurE2AzHRRRup5FuHzDr8n15'; + let xpriv2 = 'xprv9ys4cvcoU8RoxqkZ7Fgt33te4LPHgcsKwyoZYVorkzp9uonWxWgP9wiSQhPeBUqVHbdAyov4Yi55RywBkDfZKdJFRqA51Anz6v72zGaMGZp'; + // hdnodes from xprivs + let hdnode1 = bitbox.HDNode.fromXPriv(xpriv1); + let hdnode2 = bitbox.HDNode.fromXPriv(xpriv2); + // 32 byte buffer + let buf = Buffer.from(bitbox.Crypto.sha256('EARTH'), 'hex'); + // sign + let signature = bitbox.HDNode.sign(hdnode1, buf); + // verify + bitbox.HDNode.verify(hdnode1, buf, signature); + // true + bitbox.HDNode.verify(hdnode2, buf, signature); + // false + + // testnet xprivs + let xpriv1 = 'tprv8ggxJ8SG5EdqakzVUeLa9Gr7sqCdEcJPUNDmtdJscNxfmxoXvU36ZguiUWukJVEWEixAUr8pJabJkCt33wzxFQA587gqN51Lxdxx97zAzuG'; + let xpriv2 = 'tprv8ggxJ8SG5EdqiM6Dn63QwHScQ7HS5hXqUMxSD1NEbDyPw6VtoUMFZBAohpTMsPz9cYbpHELmA4Zm79NKRvEvFdhWRX2bSmu7V7PiNb364nv'; + // hdnodes from xprivs + let hdnode1 = bitbox.HDNode.fromXPriv(xpriv1); + let hdnode2 = bitbox.HDNode.fromXPriv(xpriv2); + // 32 byte buffer + let buf = Buffer.from(bitbox.Crypto.sha256('EARTH'), 'hex'); + // sign + let signature = bitbox.ECPair.sign(hdnode1, buf); + // verify + bitbox.HDNode.verify(hdnode1, buf, signature); + // true + bitbox.HDNode.verify(hdnode2, buf, signature); + // false + +### `createAccount` + +Create [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#the-default-wallet-layout) account. Has `getChainAddress` and `nextChainAddress` helper methods. + +#### Arguments + +1. hdNodes `HDNode[]` + +#### Result + +account: `Object` + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create root seed buffer + let rootSeedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create master hd node + let masterHDNode = bitbox.HDNode.fromSeed(rootSeedBuffer); + // derive child node + let childNode = masterHDNode.derivePath("m/44'/145'/0'/0"); + // create account + let account = bitbox.HDNode.createAccount([childNode]); + +### `getChainAddress` + +Returns the latest address from account + +#### Arguments + +1. account: `number` + +#### Result + +address: `string` + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create root seed buffer + let rootSeedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create master hd node + let masterHDNode = bitbox.HDNode.fromSeed(rootSeedBuffer); + // derive child node + let childNode = masterHDNode.derivePath("m/44'/145'/0'/0"); + // create account + let account = bitbox.HDNode.createAccount([childNode]); + account.getChainAddress(0) + // 1EsibxXqzxzcor7eS34dSGrZp1kb3nQFFr + +### `nextChainAddress` + +Moves the most recent address forward for account + +#### Arguments + +1. account: `number` + +#### Result + +address: `string` + +#### Examples + + // create mnemonic + let mnemonic = bitbox.Mnemonic.generate(128); + // create root seed buffer + let rootSeedBuffer = bitbox.Mnemonic.toSeed(mnemonic); + // create master hd node + let masterHDNode = bitbox.HDNode.fromSeed(rootSeedBuffer); + // derive child node + let childNode = masterHDNode.derivePath("m/44'/145'/0'/0"); + // create account + let account = bitbox.HDNode.createAccount([childNode]); + account.getChainAddress(0) + // 1EsibxXqzxzcor7eS34dSGrZp1kb3nQFFr + account.nextChainAddress(0) + account.getChainAddress(0) + // 1JBApcAMD3riimPxABg2pNvwLumP9DEpxD diff --git a/docs/images/paper.png b/docs/images/paper.png new file mode 100644 index 00000000..48b8ff99 Binary files /dev/null and b/docs/images/paper.png differ diff --git a/docs/mining.md b/docs/mining.md new file mode 100644 index 00000000..51c04032 --- /dev/null +++ b/docs/mining.md @@ -0,0 +1,44 @@ +# Mining + +### `getMiningInfo` + +Returns a json object containing mining-related information. + +#### Result + +miningInfo: `Promise` + +#### Examples + + (async () => { + try { + let getMiningInfo = await bitbox.Mining.getMiningInfo(); + console.log(getMiningInfo); + } catch(error) { + console.error(error) + } + })() + +### `getNetworkHashps` + +Returns the estimated network hashes per second based on the last n blocks. Pass in \[blocks\] to override # of blocks, -1 specifies since last difficulty change. Pass in \[height\] to estimate the network speed at the time when a certain block was found. + +#### Arguments + +1. nblocks `number` **optional**: The number of blocks, or -1 for blocks since last difficulty change. +2. height `number`, **optional**: To estimate at the time of the given height. + +#### Result + +x `Promise`: Hashes per second estimated + +#### Examples + + (async () => { + try { + let getNetworkHashps = await bitbox.Mining.getNetworkHashps(); + console.log(getNetworkHashps); + } catch(error) { + console.error(error) + } + })() diff --git a/docs/mnemonic.md b/docs/mnemonic.md new file mode 100644 index 00000000..fd53a42b --- /dev/null +++ b/docs/mnemonic.md @@ -0,0 +1,293 @@ +# Mnemonic + +### `generate` + +Generate [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) mnemonic from entropy + +#### Arguments + +1. randomBits `number` **optional**: number of random bits of entropy to use. The more bits the longer the mnemonic. +2. mnemonic word list `string[]` **optional**: list of words to generate the mnemonic from + +#### Result + +mnemonic `string` a random mnemonic + +#### Examples + + // generate 12 word mnemonic + bitbox.Mnemonic.generate(128); + // boil lonely casino manage habit where total glory muffin name limit mansion + + // generate 15 word mnemonic + bitbox.Mnemonic.generate(160); + // steak prevent estate save dance design close noise cheap season among train sleep ketchup gas + + // generate 18 word mnemonic + bitbox.Mnemonic.generate(192); + // fever endorse purpose normal fashion desert blood robust prevent clean guard display raise virtual again unit banana rich + + // generate 21 word mnemonic + bitbox.Mnemonic.generate(224); + // scan pink shock describe chicken edit budget exit camera morning awesome silk inner pair sea few flock walnut write mountain surface + + // generate 24 word mnemonic + bitbox.Mnemonic.generate(256); + // disagree tide elbow citizen jazz cinnamon bridge certain april settle pact film always inmate border inform solution that submit produce cloth balcony upper maid + + // generate 12 french word mnemonic + bitbox.Mnemonic.generate(128, bitbox.Mnemonic.wordLists().french); + // annonce ampleur sanglier peser acheter cultiver abroger embellir résoudre dialogue grappin lanterne + + // generate 256 bit korean word mnemonic + bitbox.Mnemonic.generate(256, bitbox.Mnemonic.wordLists().korean) + // 기능 단추 교육 비난 시집 근육 운동 코미디 숟가락 과목 한동안 유적 시리즈 삼월 앞날 유난히 흰색 사실 논문 장사 어른 논문 의논 장차 + +### `fromEntropy` + +Create mnemonic from entropy + +#### Arguments + +1. randomBytes `Buffer`: buffer of random entropy. This entropy can be generated w/ `bitbox.Crypto.randomBytes`. +2. mnemonic word list `string[]` **optional**: list of words to generate the mnemonic from + +#### Result + +mnemonic `string` a random mnemonic + +#### Examples + + // generate 16 bytes of entropy + let entropy = bitbox.Crypto.randomBytes(16); + // + // turn entropy to 12 word mnemonic + bitbox.Mnemonic.fromEntropy(entropy) + // security question relief cruel nephew jump chest copper axis assist gift correct + + // generate 20 bytes of entropy + let entropy = bitbox.Crypto.randomBytes(20); + // + // turn entropy to 15 word mnemonic + bitbox.Mnemonic.fromEntropy(entropy) + // impact hub pattern turkey cruel adult short moment make toe one actress roast yellow hurt + + // generate 24 bytes of entropy + let entropy = bitbox.Crypto.randomBytes(24); + // + // turn entropy to 18 word mnemonic + bitbox.Mnemonic.fromEntropy(entropy) + // bid quantum chronic marriage swing affair record amateur enhance heart object mind spoon speak toast piece chef real + + // generate 28 bytes of entropy + let entropy = bitbox.Crypto.randomBytes(28); + // + // turn entropy to 21 word mnemonic + bitbox.Mnemonic.fromEntropy(entropy) + // orchard rural giant okay tape pipe luggage clap bring wear ticket slot fiscal seminar crazy robot distance current dizzy swarm barrel + + // generate 32 bytes of entropy + let entropy = bitbox.Crypto.randomBytes(32); + // + // turn entropy to 24 word mnemonic + bitbox.Mnemonic.fromEntropy(entropy) + // vibrant solution level obtain cheap damage october giant chalk cushion assist fossil spawn artist rice edit proof hotel process survey gas sausage mouse property + + // generate 16 bytes of entropy + let entropy = bitbox.Crypto.randomBytes(16); + // + // turn entropy to 12 japanese word mnemonic + bitbox.Mnemonic.fromEntropy(entropy.toString('hex'), bitbox.Mnemonic.wordLists().japanese) + // ぱそこん にあう にんめい きどく ちそう せんきょ かいが きおく いれる いねむり しいく きかんしゃ + +### `toEntropy` + +Turn mnemonic to entropy + +#### Arguments + +1. mnemonic `string`: a mnemonic to turn to entropy. +2. mnemonic word list `string[]` **optional**: list of words the mnemonic was generated from + +#### Result + +entropy `Buffer` entropy encoded as buffer + +#### Examples + + // turn 12 word mnemonic to entropy + let mnemonic = 'security question relief cruel nephew jump chest copper axis assist gift correct'; + bitbox.Mnemonic.toEntropy(mnemonic) + // + + // turn 15 word mnemonic to entropy + let mnemonic = 'impact hub pattern turkey cruel adult short moment make toe one actress roast yellow hurt'; + bitbox.Mnemonic.toEntropy(mnemonic) + // + + // turn 18 word mnemonic to entropy + let mnemonic = 'bid quantum chronic marriage swing affair record amateur enhance heart object mind spoon speak toast piece chef real'; + bitbox.Mnemonic.toEntropy(mnemonic) + // + + // turn 21 word mnemonic to entropy + let mnemonic = 'orchard rural giant okay tape pipe luggage clap bring wear ticket slot fiscal seminar crazy robot distance current dizzy swarm barrel'; + bitbox.Mnemonic.toEntropy(mnemonic) + // + + // turn 24 word mnemonic to entropy + let mnemonic = 'vibrant solution level obtain cheap damage october giant chalk cushion assist fossil spawn artist rice edit proof hotel process survey gas sausage mouse property'; + bitbox.Mnemonic.toEntropy(mnemonic) + // + +### `validate` + +Validate mnemonic + +#### Arguments + +1. mnemonic `string` mnemonic phrase +2. mnemonic word list `string[]`: list of words the mnemonic was generated from + +#### Result + +valid `string` + +#### Examples + + bitbox.Mnemonic.validate('ca', bitbox.Mnemonic.wordLists().english) + // ca is not in wordlist, did you mean cabbage? + + bitbox.Mnemonic.validate('boil lonely casino manage habit where total glory muffin name limit mansion', bitbox.Mnemonic.wordLists().english) + // Valid mnemonic + + bitbox.Mnemonic.validate('boil lonely casino manage habit where total glory muffin name limit mansion boil lonely casino manage habit where total glory muffin name limit mansion', bitbox.Mnemonic.wordLists().english) + // Invalid mnemonic + +### `toSeed` + +Create root seed from mnemonic + +#### Arguments + +1. mnemonic `string` mnemonic phrase +2. passphrase `string` **optional**: passphrase. Defaults to "" + +#### Result + +rootSeed `Buffer` + +#### Examples + + bitbox.Mnemonic.toSeed('enable stem left method one submit coach bid inspire cluster armed bracket') + // + + bitbox.Mnemonic.toSeed('vendor talk alone sick balance tissue number armor frequent plug transfer chest', 'password'); + // + + bitbox.Mnemonic.toSeed('idea relax weird defense body bronze champion ancient vocal peanut similar dose grit company peasant gate sunset deal library act include penalty annual main', ''); + // + + bitbox.Mnemonic.toSeed('bus aware census desk orphan zebra fashion host try muscle pig close jealous slice elegant prison reject ship great program trumpet syrup tray remove', ''); + // + + bitbox.Mnemonic.toSeed('frost deliver coin clutch upon round scene wonder various wise luggage country', 'yayayayay'); + // + +### `wordLists` + +Return mnemonic word lists + +#### Result + +wordlists `object` an object with wordlists in the following languages english (default), japanese, chinese simplified, chinese traditional, french, italian, japanese, korean, spanish + +#### Examples + + bitbox.Mnemonic.wordLists(); + // { + // EN: [], + // JA: [], + // chinese_simplified: [], + // chinese_traditional: [], + // english: [], + // french: [], + // italian: [], + // japanese: [], + // korean: [], + // spanish: [] + // } + +### `toKeypairs` + +Returns an array of privateKeyWIF/publicAddress pairs. It generates the addresses as the nth external change address of the first account from that mnemonic w/ this derivation path: `m/44’/145’/0’/0/n` + +#### Arguments + +1. mnemonic `string`: mnemonic to use +2. numberOfKeypairs `number` **optional**: number of keypairs to return. Default is 1 +3. regtest `boolean` **optional**: return regtest key pairs + +#### Result + +keypairs `any[]` array of privateKeyWIF/publicAddress pairs + +#### Examples + + // First create a mnemonic from 32 bytes of random entropy + let entropy = bitbox.Crypto.randomBytes(32); + // + let mnemonic = bitbox.Mnemonic.fromEntropy(entropy); + // rural pistol giant label nominee curtain egg crystal famous only drill van place unit attitude oven memory fade mix sun shrug soon steak easily + + // Then call toKeypairs and pass in your mnemonic and how many keypairs you'd like + bitbox.Mnemonic.toKeypairs(mnemonic, 5) + // [ { privateKeyWIF: 'KwuSgSuV6m3U1oahRQEhSQ6e4gRE6LZXNGDTETGPGotKQJdH7ADd', + // address: 'bitcoincash:qqvk7aculs8r6t29pj23de35t43tupks2ua6wmc2hy' }, + // { privateKeyWIF: 'L34pfoBm2swLBX5vAx1ReeYbSnpsvu7DRVaiLW8e9wNEJw5p3mV5', + // address: 'bitcoincash:qzt8ju6au2075cpzrhzwe5n96ycqnurarur5k92nd5' }, + // { privateKeyWIF: 'L2nCRgDzmTRrQzSssFvVA7xiYHBJyfj62jdDwu1bTjHKVoLGxsqs', + // address: 'bitcoincash:qpdjwtyvqqaapykxr3pr6cty4gpww30aucam9l0qzn' }, + // { privateKeyWIF: 'KyDLLa4RZKhnBP78Ue6557B55Jmffu1y8mH8p8WKA12knJUjiq4u', + // address: 'bitcoincash:qq8kee4k4h9fn22xya9p5u203vg69aat3usqdvkdkn' }, + // { privateKeyWIF: 'L5gB66JqhfouEtZG5aRMQ9JaVS2ggkK3YozGfzZegBupaPXqdfaz', + // address: 'bitcoincash:qphwlpu2wzjxrjts94pn4wh778fwsu2afg2aj5her9' } ] + +### `findNearestWord` + +Returns nearest matching word from provided word list + +#### Arguments + +1. word `string`: mnemonic to use +2. wordlist `string[]`: wordlist to search + +#### Result + +word `string` nearest matching word from provided wordlist + +#### Examples + + // english + let word = 'ab'; + let wordlist = bitbox.Mnemonic.wordLists().english; + bitbox.Mnemonic.findNearestWord(word, wordlist); + // abandon + + // french + let word = 'octu'; + let wordlist = bitbox.Mnemonic.wordLists().french; + bitbox.Mnemonic.findNearestWord(word, wordlist); + // octupler + + // spanish + let word = 'foobaro'; + let wordlist = bitbox.Mnemonic.wordLists().spanish; + bitbox.Mnemonic.findNearestWord(word, wordlist); + // forro + + // italian + let word = 'nv'; + let wordlist = bitbox.Mnemonic.wordLists().italian; + bitbox.Mnemonic.findNearestWord(word, wordlist); + // neve diff --git a/docs/new.md b/docs/new.md new file mode 100644 index 00000000..2a8fc616 --- /dev/null +++ b/docs/new.md @@ -0,0 +1,31 @@ +# New + +BITBOX will generate a new app w/ empty `src/` and `test/` directories and a `bitbox.js` configured to connect to Bitcoin.com’s Cloud. + +### Usage + +```bash +new [options] + Options: + -s, --scaffold The framework to use. Options include react, angular, node, next, vue and websockets. (Default: react) + -r, --restURL The rest URL to use. default: https://trest.bitcoin.com/v2/ + -e, --environment environment to map to restURL. Ex: production, staging. Default: development + -h, --help output usage information + +$ bitbox new helloEARTH +$ bitbox new helloEARTH --scaffold react +``` + +## `bitbox.js` + +Your `bitbox.js` file will contain the default settings to connect to Bitcoin.com’s Cloud. + +```javascript +exports.config = { + environments: { + development: { + restURL: "https://trest.bitcoin.com/v2/", + }, + }, +} +``` diff --git a/docs/price.md b/docs/price.md new file mode 100644 index 00000000..6e82139d --- /dev/null +++ b/docs/price.md @@ -0,0 +1,30 @@ +# Price + +### `current` + +Return current price of BCH in multiple currencies + +#### Arguments + +1. currency `string` **optional**: Defaults to usd + +Valid currencies + +aed, afn, all, amd, ang, aoa, ars, aud, awg, azn, bam, bbd, bdt, bgn, bhd, bif, bmd, bnd, bob, brl, bsd, btn, bwp, byn, bzd, cad, cdf, chf, clf, clp, cnh, cny, cop, crc, cuc, cup, cve, czk, djf, dkk, dop, dzd, egp, ern, etb, eur, fjd, fkp, gbp, gel, ggp, ghs, gip, gmd, gnf, gtq, gyd, hkd, hnl, hrk, htg, huf, idr, ils, imp, inr, iqd, irr, isk, jep, jmd, jod, jpy, kes, kgs, khr, kmf, kpw, krw, kwd, kyd, kzt, lak, lbp, lkr, lrd, lsl, lyd, mad, mdl, mga, mkd, mmk, mnt, mop, mro, mur, mvr, mwk, mxn, myr, mzn, nad, ngn, nio, nok, npr, nzd, omr, pab, pen, pgk, php, pkr, pln, pyg, qar, ron, rsd, rub, rwf, sar, sbd, scr, sdg, sek, sgd, shp, sll, sos, srd, ssp, std, svc, syp, szl, thb, tjs, tmt, tnd, top, try, ttd, twd, tzs, uah, ugx, usd, uyu, uzs, vef, vnd, vuv, wst, xaf, xag, xau, xcd, xdr, xof, xpd, xpf, xpt, yer, zar, zmw, zwl + +#### Result + +price `Promise`: Price of single requested currency + +#### Examples + + (async () => { + try { + let current = await bitbox.Price.current('usd'); + console.log(current); + } catch(error) { + console.error(error) + } + })() + + // 26681 diff --git a/docs/rawtransactions.md b/docs/rawtransactions.md new file mode 100644 index 00000000..e5ddb34b --- /dev/null +++ b/docs/rawtransactions.md @@ -0,0 +1,250 @@ +# RawTransactions + +### `decodeRawTransaction` + +Return an Array of JSON objects representing the serialized, hex-encoded transactions. + +#### Arguments + +- hex `string | string[]` + +#### Result + +- txs `Promise` + +#### Examples + + (async () => { + try { + let decodeRawTransaction = await bitbox.RawTransactions.decodeRawTransaction('01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'); + console.log(decodeRawTransaction); + } catch(error) { + console.error(error) + } + })() + + // { txid: 'd86c34adaeae19171fd98fe0ffd89bfb92a1e6f0339f5e4f18d837715fd25758', + // hash: + // 'd86c34adaeae19171fd98fe0ffd89bfb92a1e6f0339f5e4f18d837715fd25758', + // size: 191, + // version: 1, + // locktime: 0, + // vin: + // [ { txid: + // '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b', + // vout: 0, + // scriptSig: [Object], + // sequence: 4294967295 } ], + // vout: [ { value: 12.5, n: 0, scriptPubKey: [Object] } ] } + + (async () => { + try { + let decodeRawTransaction = await bitbox.RawTransactions.decodeRawTransaction([ + '01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000', + '01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000' + ]); + console.log(decodeRawTransaction); + } catch(error) { + console.error(error) + } + })() + + // [ { txid: + // 'd86c34adaeae19171fd98fe0ffd89bfb92a1e6f0339f5e4f18d837715fd25758', + // hash: + // 'd86c34adaeae19171fd98fe0ffd89bfb92a1e6f0339f5e4f18d837715fd25758', + // size: 191, + // version: 1, + // locktime: 0, + // vin: [ [Object] ], + // vout: [ [Object] ] }, + // { txid: + // 'd86c34adaeae19171fd98fe0ffd89bfb92a1e6f0339f5e4f18d837715fd25758', + // hash: + // 'd86c34adaeae19171fd98fe0ffd89bfb92a1e6f0339f5e4f18d837715fd25758', + // size: 191, + // version: 1, + // locktime: 0, + // vin: [ [Object] ], + // vout: [ [Object] ] } ] + +### `decodeScript` + +Decode hex-encoded scripts + +#### Arguments + +1. hex `string | string[]` + +#### Result + +decodedScripts `Promise` + +#### Examples + + (async () => { + try { + let decodeScript = await bitbox.RawTransactions.decodeScript('4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16'); + console.log(decodeScript); + } catch(error) { + console.error(error) + } + })() + + // { asm: '30450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed59201 02e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16', type: 'nonstandard', p2sh: 'bitcoincash:pqwndulzwft8dlmqrteqyc9hf823xr3lcc7ypt74ts' } + + + (async () => { + try { + let decodeScript = await bitbox.RawTransactions.decodeScript(['4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16']); + console.log(decodeScript); + } catch(error) { + console.error(error) + } + })() + + // [{ asm: '30450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed59201 02e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16', + // type: 'nonstandard', + // p2sh: 'bitcoincash:pqwndulzwft8dlmqrteqyc9hf823xr3lcc7ypt74ts' }] + +### `getRawTransaction` + +Return the raw transaction data. If verbose is 'true', returns an Object with +information about 'txid'. If verbose is 'false' or omitted, returns a string +that is serialized, hex-encoded data for 'txid'. + +#### Arguments + +- txids `string | string[]` +- verbose `boolean` **optiona**: If false, return a string, + otherwise return a json object + +#### Result + +- rawTx `Promise` + +#### Examples + + (async () => { + try { + let getRawTransaction = await bitbox.RawTransactions.getRawTransaction("0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098"); + console.log(getRawTransaction); + } catch(error) { + console.error(error) + } + })() + + // 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000 + + (async () => { + try { + let getRawTransaction = await bitbox.RawTransactions.getRawTransaction([ + "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098", + "b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f" + ], true); + console.log(getRawTransaction); + } catch(error) { + console.error(error) + } + })() + + // [ { hex: + // '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000', + // txid: + // '0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098', + // hash: + // '0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098', + // size: 134, + // version: 1, + // locktime: 0, + // vin: [ [Object] ], + // vout: [ [Object] ], + // blockhash: + // '00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048', + // confirmations: 581882, + // time: 1231469665, + // blocktime: 1231469665 }, + // { hex: + // '01000000010f3cb469bc82f931ee77d80b3dd495d02f9ed7cdc455cea3e7baa4bdeea6a78d000000006a47304402205ce3e1dfe4b5207818ce27035bc7cc03a5631f806d351535b32ce77c8d136aed02204e66e1fa4c2e12feab0d41a5593aff9629cdbc6ccb6126bc3d1a20404be7760c412103d44946d17e00179bbfc3b723aedc1831d8604e6a04bbd91170f1d894d04657bbffffffff02e6ec8500000000001976a914b5befddad83d9180fd4082c5528cf5a779b0fa6688acdf220000000000001976a9142c21a1be4239eeed678a456627a08d5f813d5c9288ac00000000', + // txid: + // 'b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f', + // hash: + // 'b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f', + // size: 225, + // version: 1, + // locktime: 0, + // vin: [ [Object] ], + // vout: [ [Object], [Object] ], + // blockhash: + // '000000000000000003a09a7d68a0d62fd0ab51c368372e46bac84277e2df47e2', + // confirmations: 16151, + // time: 1547752564, + // blocktime: 1547752564 } ] + +### `sendRawTransaction` + +Submits raw transaction (serialized, hex-encoded) to local node and network. Also see createrawtransaction and signrawtransaction calls. + +For bulk uploads, transactions must use different UTXOs. + +#### Arguments + +- hex `string | string[]` + +#### Result + +txid `Promise` + +#### Examples + + // single tx + (async () => { + try { + let sendRawTransaction = await bitbox.RawTransactions.sendRawTransaction("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000"); + console.log(sendRawTransaction); + } catch(error) { + console.error(error) + } + })() + // 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098 + + // single tx as array + (async () => { + try { + let sendRawTransaction = await bitbox.RawTransactions.sendRawTransaction(["01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000"]); + console.log(sendRawTransaction); + } catch(error) { + console.error(error) + } + })() + // ['0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098'] + +## Interfaces + +### VerboseRawTransaction + + { + hex: string + txid: string + size: number + version: number + locktime: number + vin: [{ coinbase: string; sequence: number }] + vout: [ + { + value: number + n: number + scriptPubKey: { + asm: string + hex: string + reqSigs: number + type: string + addresses: string[] + } + } + ] + blockhash: string + confirmations: number + time: number + blocktime: number + } diff --git a/docs/schnorr.md b/docs/schnorr.md new file mode 100644 index 00000000..644d6c69 --- /dev/null +++ b/docs/schnorr.md @@ -0,0 +1,472 @@ +# Schnorr + +### `sign` + +Sign a 32-byte message with the private key, returning a 64-byte signature. + +#### Arguments + +1. privateKey `BigInteger` +2. message `Buffer` + +#### Result + +signature `Buffer` + +#### Examples + + const Buffer = require("safe-buffer").Buffer + const BigInteger = require("bigi") + + // signing + const privateKey = BigInteger.fromHex( + "B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF" + ) + const message = Buffer.from( + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "hex" + ) + const createdSignature = bitbox.Schnorr.sign(privateKey, message) + console.log("The signature is: " + createdSignature.toString("hex")) + // The signature is: 2a298dacae57395a15d0795ddbfd1dcb564da82b0f269bc70a74f8220429ba1d1e51a22ccec35599b8f266912281f8365ffc2d035a230434a1a64dc59f7013fd + +### `verify` + +Verify a 64-byte signature of a 32-byte message against the public key. Throws an `Error` if verification fails. + +#### Arguments + +1. publicKey. `Buffer` +2. message. `Buffer` +3. signature. `Buffer` + +#### Examples + + const Buffer = require("safe-buffer").Buffer + const publicKey = Buffer.from( + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + "hex" + ) + const message = Buffer.from( + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "hex" + ) + const signatureToVerify = Buffer.from( + "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", + "hex" + ) + try { + bitbox.Schnorr.verify(publicKey, message, signatureToVerify) + console.log("The signature is valid.") + } catch (e) { + console.error("The signature verification failed: " + e) + } + +### `batchVerify` + +Verify a list of 64-byte signatures as a batch operation. Throws an `Error` if verification fails. + +#### Arguments + +1. publicKeys. `Buffer[]` +2. messages. `Buffer[]` +3. signatures. `Buffer[]` + +#### Examples + + const Buffer = require("safe-buffer").Buffer + const publicKeys = [ + Buffer.from( + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + "hex" + ), + Buffer.from( + "03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B", + "hex" + ), + Buffer.from( + "026D7F1D87AB3BBC8BC01F95D9AECE1E659D6E33C880F8EFA65FACF83E698BBBF7", + "hex" + ) + ] + const messages = [ + Buffer.from( + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "hex" + ), + Buffer.from( + "5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C", + "hex" + ), + Buffer.from( + "B2F0CD8ECB23C1710903F872C31B0FD37E15224AF457722A87C5E0C7F50FFFB3", + "hex" + ) + ] + const signatures = [ + Buffer.from( + "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", + "hex" + ), + Buffer.from( + "00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BE00880371D01766935B92D2AB4CD5C8A2A5837EC57FED7660773A05F0DE142380", + "hex" + ), + Buffer.from( + "68CA1CC46F291A385E7C255562068357F964532300BEADFFB72DD93668C0C1CAC8D26132EB3200B86D66DE9C661A464C6B2293BB9A9F5B966E53CA736C7E504F", + "hex" + ) + ] + try { + bitbox.Schnorr.batchVerify(publicKeys, messages, signatures) + console.log("The signatures are valid.") + } catch (e) { + console.error("The signature verification failed: " + e) + } + +### `nonInteractive` + +Aggregates multiple signatures of different private keys over the same message into a single 64-byte signature using a scheme that is safe from rogue-key attacks. + +This non-interactive scheme requires the knowledge of all private keys that are participating in the multi-signature creation. + +#### Arguments + +1. privateKeys. `BigInteger[]` +2. message `Buffer` + +#### Result + +aggregatedSignature `Buffer` + +#### Examples + + const Buffer = require("safe-buffer").Buffer + const BigInteger = require("bigi") + + const privateKey1 = BigInteger.fromHex( + "B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF" + ) + const privateKey2 = BigInteger.fromHex( + "C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C7" + ) + const message = Buffer.from( + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "hex" + ) + const aggregatedSignature = bitbox.Schnorr.nonInteractive( + [privateKey1, privateKey2], + message + ) + + // verifying an aggregated signature + const publicKey1 = Buffer.from( + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + "hex" + ) + const publicKey2 = Buffer.from( + "03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B", + "hex" + ) + const X = bitbox.Schnorr.publicKeyCombine([publicKey1, publicKey2]) + try { + bitbox.Schnorr.verify(X, message, aggregatedSignature) + console.log("The signature is valid.") + } catch (e) { + console.error("The signature verification failed: " + e) + } + +### `computeEll` + +Generate `ell` which is the hash over all public keys participating in a session. + +#### Arguments + +1. publicKeys. `BigInteger[]` + +#### Result + +publicKeyHash `Buffer` + +#### Examples + + const Buffer = require("safe-buffer").Buffer + const BigInteger = require("bigi") + + const publicData = { + pubKeys: [ + Buffer.from( + "03846f34fdb2345f4bf932cb4b7d278fb3af24f44224fb52ae551781c3a3cad68a", + "hex" + ), + Buffer.from( + "02cd836b1d42c51d80cef695a14502c21d2c3c644bc82f6a7052eb29247cf61f4f", + "hex" + ), + Buffer.from( + "03b8c1765111002f09ba35c468fab273798a9058d1f8a4e276f45a1f1481dd0bdb", + "hex" + ) + ], + message: bitbox.Schnorr.hash(Buffer.from("muSig is awesome!", "utf8")), + pubKeyHash: null, + pubKeyCombined: null, + commitments: [], + nonces: [], + nonceCombined: null, + partialSignatures: [], + signature: null + } + + // data only known by the individual party, these values are never shared + // between the signers! + const signerPrivateData = [ + // signer 1 + { + privateKey: BigInteger.fromHex( + "add2b25e2d356bec3770305391cbc80cab3a40057ad836bcb49ef3eed74a3fee" + ), + session: null + }, + // signer 2 + { + privateKey: BigInteger.fromHex( + "0a1645eef5a10e1f5011269abba9fd85c4f0cc70820d6f102fb7137f2988ad78" + ), + session: null + }, + // signer 3 + { + privateKey: BigInteger.fromHex( + "2031e7fed15c770519707bb092a6337215530e921ccea42030c15d86e8eaf0b8" + ), + session: null + } + ] + + // ----------------------------------------------------------------------- + // Step 1: Combine the public keys + // The public keys P_i are combined into the combined public key P. + // This can be done by every signer individually or by the initializing + // party and then be distributed to every participant. + // ----------------------------------------------------------------------- + publicData.pubKeyHash = bitbox.Schnorr.computeEll(publicData.pubKeys) + +### `publicKeyCombine` + +Creates the special rogue-key-resistant combined public key `P` by applying the MuSig coefficient to each public key `P_i` before adding them together. + +#### Arguments + +1. publicKeys. `Buffer[]` +2. publicKeyHash. `Buffer` + +#### Result + +X `Buffer` + +#### Examples + + // continued from above + publicData.pubKeyCombined = bitbox.Schnorr.publicKeyCombine( + publicData.pubKeys, + publicData.pubKeyHash + ) + +### `sessionInitialize` + +Creates a signing session. Each participant must create a session and must not share the content of the session apart from the commitment and later the nonce. + +#### Arguments + +1. sessionId. `Buffer` +2. privateKey. `BigInteger` +3. message. `Buffer` +4. pubKeyCombined. `Buffer` +5. ell. `Buffer` +6. idx. `number` + +#### Result + +session `Session` + +#### Examples + + // continued from above + // ----------------------------------------------------------------------- + // Step 2: Create the private signing session + // Each signing party does this in private. The session ID *must* be + // unique for every call to sessionInitialize, otherwise it's trivial for + // an attacker to extract the secret key! + // ----------------------------------------------------------------------- + signerPrivateData.forEach((data, idx) => { + const sessionId = bitbox.Crypto.randomBytes(32) // must never be reused between sessions! + data.session = bitbox.Schnorr.sessionInitialize( + sessionId, + data.privateKey, + publicData.message, + publicData.pubKeyCombined, + publicData.pubKeyHash, + idx + ) + }) + const signerSession = signerPrivateData[0].session + +### `sessionNonceCombine` + +Combines multiple nonces `R_i` into the combined nonce `R`. + +#### Arguments + +1. session. `Session` +2. nonces. `Buffer[]` + +#### Result + +nonceCombined `Buffer` + +#### Examples + + // continued from above + // ----------------------------------------------------------------------- + // Step 3: Exchange commitments (communication round 1) + // The signers now exchange the commitments H(R_i). This is simulated here + // by copying the values from the private data to public data array. + // ----------------------------------------------------------------------- + for (let i = 0; i < publicData.pubKeys.length; i++) { + publicData.commitments[i] = signerPrivateData[i].session.commitment + } + + // ----------------------------------------------------------------------- + // Step 4: Get nonces (communication round 2) + // Now that everybody has commited to the session, the nonces (R_i) can be + // exchanged. Again, this is simulated by copying. + // ----------------------------------------------------------------------- + for (let i = 0; i < publicData.pubKeys.length; i++) { + publicData.nonces[i] = signerPrivateData[i].session.nonce + } + + // ----------------------------------------------------------------------- + // Step 5: Combine nonces + // The nonces can now be combined into R. Each participant should do this + // and keep track of whether the nonce was negated or not. This is needed + // for the later steps. + // ----------------------------------------------------------------------- + publicData.nonceCombined = bitbox.Schnorr.sessionNonceCombine( + signerSession, + publicData.nonces + ) + signerPrivateData.forEach( + data => (data.session.nonceIsNegated = signerSession.nonceIsNegated) + ) + +### `partialSign` + +Creates a partial signature `s_i` for a participant. + +#### Arguments + +1. session. `Session` +2. message. `Buffer` +3. nonceCombined. `Buffer` +4. publicKeyCombined. `Buffer` + +#### Result + +partialSignature `BigInteger` + +#### Examples + + // continued from above + // ----------------------------------------------------------------------- + // Step 6: Generate partial signatures + // Every participant can now create their partial signature s_i over the + // given message. + // ----------------------------------------------------------------------- + signerPrivateData.forEach(data => { + data.session.partialSignature = bitbox.Schnorr.partialSign( + data.session, + publicData.message, + publicData.nonceCombined, + publicData.pubKeyCombined + ) + }) + +### `partialSignatureVerify` + +Verifies a partial signature `s_i` against the participant's public key `P_i`. Throws an `Error` if verification fails. + +#### Arguments + +1. session. `Session` +2. partialSig. `BigInteger` +3. nonceCombined. `Buffer` +4. idx. `number` +5. publicKey. `Buffer` +6. nonce. `Buffer` + +#### Examples + + // continued from above + // ----------------------------------------------------------------------- + // Step 7: Exchange partial signatures (communication round 3) + // The partial signature of each signer is exchanged with the other + // participants. Simulated here by copying. + // ----------------------------------------------------------------------- + for (let i = 0; i < publicData.pubKeys.length; i++) { + publicData.partialSignatures[i] = + signerPrivateData[i].session.partialSignature + } + + // ----------------------------------------------------------------------- + // Step 8: Verify individual partial signatures + // Every participant should verify the partial signatures received by the + // other participants. + // ----------------------------------------------------------------------- + for (let i = 0; i < publicData.pubKeys.length; i++) { + bitbox.Schnorr.partialSignatureVerify( + signerSession, + publicData.partialSignatures[i], + publicData.nonceCombined, + i, + publicData.pubKeys[i], + publicData.nonces[i] + ) + } + +### `partialSignaturesCombine` + +Combines multiple partial signatures into a Schnorr signature `(s, R)` that can be verified against the combined public key `P`. + +#### Arguments + +1. nonceCombined. `Buffer` +2. partialSignatures. `BigInteger[]` + +#### Result + +signature `Buffer` + +#### Examples + + // continued from above + // ----------------------------------------------------------------------- + // Step 9: Combine partial signatures + // Finally, the partial signatures can be combined into the full signature + // (s, R) that can be verified against combined public key P. + // ----------------------------------------------------------------------- + publicData.signature = bitbox.Schnorr.partialSignaturesCombine( + publicData.nonceCombined, + publicData.partialSignatures + ) + + // ----------------------------------------------------------------------- + // Step 10: Verify signature + // The resulting signature can now be verified as a normal Schnorr + // signature (s, R) over the message m and public key P. + // ----------------------------------------------------------------------- + bitbox.Schnorr.verify( + publicData.pubKeyCombined, + publicData.message, + publicData.signature + ) diff --git a/docs/script.md b/docs/script.md new file mode 100644 index 00000000..f0e05468 --- /dev/null +++ b/docs/script.md @@ -0,0 +1,1135 @@ +# Script + +### `opcodes` + +Script OP Codes + +#### Result + +opcodes `Object` + +#### Examples + + // list all op codes + bitbox.Script.opcodes; + // { OP_FALSE: 0, + // OP_0: 0, + // OP_PUSHDATA1: 76, + // OP_PUSHDATA2: 77, + // OP_PUSHDATA4: 78, + // OP_1NEGATE: 79, + // OP_RESERVED: 80, + // OP_TRUE: 81, + // OP_1: 81, + // OP_2: 82, + // OP_3: 83, + // OP_4: 84, + // ... + // } + + // get the op code for a word + bitbox.Script.opcodes.OP_SPLIT + // 127 + bitbox.Script.opcodes.OP_NUM2BIN + // 128 + bitbox.Script.opcodes.OP_BIN2NUM + // 129 + +### `encode` + +Encode a Script buffer + +#### Arguments + +1. scriptChunks `Array` + +#### Result + +buffer `Buffer` + +#### Examples + + // encode P2PKH scriptSig to buffer + let scriptSig = [ + Buffer.from('3045022100877e2f9c28421f0a850cc8ff66ba1d0f6c8dbe9e63e199c2c2600c9c15bf9d4402204d35b13d3cc202aa25722b2b1791442ebc5c39d898b609515260ad08f0e766a601', 'hex'), + Buffer.from('02fb721b92025e775b1b84774e65d568d24645cb633275f5c26f5c3101b214a8fb', 'hex') + ] + bitbox.Script.encode(scriptSig); + // + + // encode P2PKH scriptPubKey to buffer + let scriptPubKey = [ + 118, + 169, + Buffer.from('24e9c07804d0ee7e5bda934e0a3ae8710fc007dd', 'hex'), + 136, + 172 + ]; + bitbox.Script.encode(scriptPubKey); + // + +### `decode` + +Decode a Script buffer. + +#### Arguments + +1. buffer `Buffer` + +#### Result + +decodedScript `Array` + +#### Examples + + // decode P2PKH scriptSig buffer + let scriptSigBuffer = Buffer.from("483045022100877e2f9c28421f0a850cc8ff66ba1d0f6c8dbe9e63e199c2c2600c9c15bf9d4402204d35b13d3cc202aa25722b2b1791442ebc5c39d898b609515260ad08f0e766a6012102fb721b92025e775b1b84774e65d568d24645cb633275f5c26f5c3101b214a8fb", 'hex'); + bitbox.Script.decode(scriptSigBuffer); + // [ , ] + + // decode P2PKH scriptPubKey buffer + let scriptPubKeyBuffer = Buffer.from("76a91424e9c07804d0ee7e5bda934e0a3ae8710fc007dd88ac", 'hex'); + bitbox.Script.decode(scriptPubKeyBuffer); + // [ 118, + // 169, + // , + // 136, + // 172 ] + +### `toASM` + +Script buffer to ASM. + +#### Arguments + +1. buffer `Buffer` + +#### Result + +asm `string` + +#### Examples + + // P2PKH scriptSig + let scriptSigBuffer = Buffer.from('483045022100877e2f9c28421f0a850cc8ff66ba1d0f6c8dbe9e63e199c2c2600c9c15bf9d4402204d35b13d3cc202aa25722b2b1791442ebc5c39d898b609515260ad08f0e766a6012102fb721b92025e775b1b84774e65d568d24645cb633275f5c26f5c3101b214a8fb', 'hex'); + bitbox.Script.toASM(scriptSigBuffer); + // 3045022100877e2f9c28421f0a850cc8ff66ba1d0f6c8dbe9e63e199c2c2600c9c15bf9d4402204d35b13d3cc202aa25722b2b1791442ebc5c39d898b609515260ad08f0e766a601 02fb721b92025e775b1b84774e65d568d24645cb633275f5c26f5c3101b214a8fb + + // P2PKH scriptPubKey + let scriptBuffer = Buffer.from("76a914bee4182d9fbc8931a728410a0cd3e0f340f2995a88ac", 'hex'); + bitbox.Script.toASM(scriptBuffer); + // OP_DUP OP_HASH160 bee4182d9fbc8931a728410a0cd3e0f340f2995a OP_EQUALVERIFY OP_CHECKSIG + +### `fromASM` + +Script ASM to buffer + +#### Arguments + +1. asm `string` + +#### Result + +buffer `Buffer` + +#### Examples + + // P2PKH scriptSig + let scriptSigASM = "3045022100877e2f9c28421f0a850cc8ff66ba1d0f6c8dbe9e63e199c2c2600c9c15bf9d4402204d35b13d3cc202aa25722b2b1791442ebc5c39d898b609515260ad08f0e766a601 02fb721b92025e775b1b84774e65d568d24645cb633275f5c26f5c3101b214a8fb"; + bitbox.Script.fromASM(scriptSigASM); + // + + // P2PKH scriptPubKey + let scriptPubKeyASM = "OP_DUP OP_HASH160 bee4182d9fbc8931a728410a0cd3e0f340f2995a OP_EQUALVERIFY OP_CHECKSIG"; + bitbox.Script.fromASM(scriptPubKeyASM); + // + +### `encodeNullDataOutput` + +nulldata output template: `` OP_RETURN `data` `` + +#### Arguments + +1. data `Buffer` + +#### Result + +buffer `Buffer` + +#### Examples + + let data = "BCHForEveryone"; + let buf = Buffer.from(data, 'ascii') + let encoded = bitbox.Script.encodeNullDataOutput(buf); + bitbox.Script.toASM(encoded); + // OP_RETURN 424348466f7245766572796f6e65 + + let data = "Satoshi Nakamoto"; + let buf = Buffer.from(data, 'ascii') + let encoded = bitbox.Script.encodeNullDataOutput(buf); + bitbox.Script.toASM(encoded); + // OP_RETURN 5361746f736869204e616b616d6f746 + +### `decodeNullDataOutput` + +decode nulldata output + +#### Arguments + +1. output `Buffer` + +#### Result + +buffer `Buffer` + +#### Examples + + let hex = '6a0e424348466f7245766572796f6e65'; + let buf = Buffer.from(hex, 'hex') + let decoded = bitbox.Script.decodeNullDataOutput(buf); + decoded.toString('ascii') + // BCHForEveryone + + let hex = '6a105361746f736869204e616b616d6f746f'; + let buf = Buffer.from(hex, 'hex') + let decoded = bitbox.Script.decodeNullDataOutput(buf); + decoded.toString('ascii') + // Satoshi Nakamoto + +### `checkNullDataOutput` + +check nulldata output format + +#### Arguments + +1. output `Buffer` + +#### Result + +valid `boolean` + +#### Examples + + // check null data output + let data = "BCHForEveryone" + let buf = Buffer.from(data, 'ascii') + let encoded = bitbox.Script.encodeNullDataOutput(buf) + bitbox.Script.checkNullDataOutput(encoded) + // true + + // check p2pk input + let signature = '304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801'; + let buf = Buffer.from(signature, 'hex') + let encoded = bitbox.Script.encodeP2PKInput(buf) + bitbox.Script.checkNullDataOutput(encoded); + // false + +### `encodeP2PKInput` + +p2pk input template: `` `signature` `` + +#### Arguments + +1. signature `Buffer` + +#### Result + +encoded `Buffer` + +#### Examples + + let signature = '304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801'; + let buf = Buffer.from(signature, 'hex') + let encoded = bitbox.Script.encodeP2PKInput(buf) + bitbox.Script.toASM(encoded); + // 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 + +### `decodeP2PKInput` + +decode p2pk input + +#### Arguments + +1. input `Buffer` + +#### Result + +decoded `Buffer` + +#### Examples + + let input = '47304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801'; + let buf = Buffer.from(input, 'hex') + bitbox.Script.decodeP2PKInput(buf) + // + +### `checkP2PKInput` + +check p2pk input format + +#### Arguments + +1. input `Buffer` + +#### Result + +valid `boolean` + +#### Examples + + // check p2pk input + let input = '304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801'; + let buf = Buffer.from(input, 'hex') + let encoded = bitbox.Script.encodeP2PKInput(buf) + bitbox.Script.checkP2PKInput(encoded) + // true + + // check null data output + let data = "BCHForEveryone"; + let buf = Buffer.from(data, 'ascii') + let encoded = bitbox.Script.encodeNullDataOutput(buf); + bitbox.Script.checkP2PKInput(encoded) + // false + +### `encodeP2PKOutput` + +p2pk output template: `` `pubKey` OP_CHECKSIG `` + +#### Arguments + +1. pubKey `Buffer` + +#### Result + +output `Buffer` + +#### Examples + + let pubKey = '02d305772e0873fba6c1c7ff353ce374233316eb5820acd7ff3d7d9b82d514126b' + let buf = Buffer.from(pubKey, 'hex') + let encoded = bitbox.Script.encodeP2PKOutput(buf) + bitbox.Script.toASM(encoded) + // 02d305772e0873fba6c1c7ff353ce374233316eb5820acd7ff3d7d9b82d514126b OP_CHECKSIG + +### `decodeP2PKOutput` + +decode p2pk output + +#### Arguments + +1. output `Buffer` + +#### Result + +decoded `Buffer` + +#### Examples + + let output = '2102d305772e0873fba6c1c7ff353ce374233316eb5820acd7ff3d7d9b82d514126bac'; + let buf = Buffer.from(output, 'hex') + bitbox.Script.decodeP2PKOutput(buf) + // + +### `checkP2PKOutput` + +check P2PK output format + +#### Arguments + +1. output `Buffer` + +#### Result + +valid `boolean` + +#### Examples + + // check p2pk output + let output = '02d305772e0873fba6c1c7ff353ce374233316eb5820acd7ff3d7d9b82d514126b'; + let buf = Buffer.from(output, 'hex') + let encoded = bitbox.Script.encodeP2PKOutput(buf) + bitbox.Script.checkP2PKOutput(encoded) + // true + + // null data output + let data = "BCHForEveryone"; + let buf = Buffer.from(data, 'ascii') + let encoded = bitbox.Script.encodeNullDataOutput(buf); + bitbox.Script.checkP2PKOutput(encoded) + // false + +### `encodeP2PKHInput` + +p2pkh input template: `` `signature` `pubKey` `` + +#### Arguments + +1. signature `Buffer` +2. pubKey `Buffer` + +#### Result + +encoded `Buffer` + +#### Examples + + let signature = '304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801'; + let pubKey = '02d9bb8da1de26d390b6f3dcb4e589857730536b646995fa948a8319ede2ca1c15'; + let sigBuf = Buffer.from(signature, 'hex') + let pubKeyBuf = Buffer.from(pubKey, 'hex') + let encoded = bitbox.Script.encodeP2PKHInput(sigBuf, pubKeyBuf); + bitbox.Script.toASM(encoded); + // 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 02d9bb8da1de26d390b6f3dcb4e589857730536b646995fa948a8319ede2ca1c15 + +### `decodeP2PKHInput` + +decode p2pkh input + +#### Arguments + +1. input `Buffer` + +#### Result + +decoded `Buffer` + +#### Examples + + let input = '47304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca28012102d9bb8da1de26d390b6f3dcb4e589857730536b646995fa948a8319ede2ca1c15' + let buf = Buffer.from(input, 'hex') + bitbox.Script.decodeP2PKHInput(buf) + // { signature: + // , + // pubKey: } + +### `checkP2PKHInput` + +check P2PKH input format + +#### Arguments + +1. input `Buffer` + +#### Result + +valid `boolean` + +#### Examples + + // check p2pkh input + let signature = '304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801'; + let pubKey = '02d9bb8da1de26d390b6f3dcb4e589857730536b646995fa948a8319ede2ca1c15'; + let sigBuf = Buffer.from(signature, 'hex') + let pubKeyBuf = Buffer.from(pubKey, 'hex') + let encoded = bitbox.Script.encodeP2PKHInput(sigBuf, pubKeyBuf); + bitbox.Script.checkP2PKHInput(encoded); + // true + + // check p2pk input + let input = '304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801'; + let buf = Buffer.from(input, 'hex') + let encoded = bitbox.Script.encodeP2PKInput(buf) + bitbox.Script.checkP2PKHInput(encoded); + // false + +### `encodeP2PKHOutput` + +p2pkh output template: `` OP_DUP OP_HASH160 `pubKeyHash` OP_EQUALVERIFY OP_CHECKSIG `` + +#### Arguments + +1. identifier `Buffer` + +#### Result + +output `Buffer` + +#### Examples + + let node = bitbox.HDNode.fromXPriv('xprv9xoxVbZ7L8jmvKx7e1hgd7muo8H35ysTx1LCKFey5nVHUkHSPBxpzBzt2HVK16hu4m6oN5vfaCWSZQvqtDhfJTCY3t9ocp7H7zcTZ2fVRwL'); + let identifier = bitbox.HDNode.toIdentifier(node); + let output = bitbox.Script.encodeP2PKHOutput(identifier); + bitbox.Script.toASM(output) + // OP_DUP OP_HASH160 6ee7ded4f9d0deb6f4a63d68df5ccc4e41ad8967 OP_EQUALVERIFY OP_CHECKSIG + +### `decodeP2PKHOutput` + +decode p2pkh output + +#### Arguments + +1. output `Buffer` + +#### Result + +decoded `Buffer` + +#### Examples + + let output = '76a9146ee7ded4f9d0deb6f4a63d68df5ccc4e41ad896788ac'; + let buf = Buffer.from(output, 'hex') + bitbox.Script.pubKeyHash.output.decode(buf); + // + +### `checkP2PKHOutput` + +check P2PKH output format + +#### Arguments + +1. output `Buffer` + +#### Result + +valid `boolean` + +#### Examples + + // check p2pkh output + let node = bitbox.HDNode.fromXPriv('xprv9xoxVbZ7L8jmvKx7e1hgd7muo8H35ysTx1LCKFey5nVHUkHSPBxpzBzt2HVK16hu4m6oN5vfaCWSZQvqtDhfJTCY3t9ocp7H7zcTZ2fVRwL'); + let identifier = bitbox.HDNode.toIdentifier(node); + let output = bitbox.Script.encodeP2PKHOutput(identifier); + bitbox.Script.checkP2PKHOutput(output); + // true + + + // check p2pk output + let output = '02d305772e0873fba6c1c7ff353ce374233316eb5820acd7ff3d7d9b82d514126b'; + let buf = Buffer.from(output, 'hex') + let encoded = bitbox.Script.encodeP2PKOutput(buf) + bitbox.Script.checkP2PKHOutput(encoded); + // false + +### `encodeP2MSInput` + +p2ms Input template: `OP_0 [signatures ...]` + +#### Arguments + +1. signatures `Buffer[]` + +#### Result + +encoded `Buffer` + +#### Examples + + let signatures = [ + Buffer.from("304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801", "hex"), + Buffer.from("3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501", "hex") + ]; + let encoded = bitbox.Script.encodeP2MSInput(signatures); + bitbox.Script.toASM(encoded); + // OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d14050 + +### `decodeP2MSInput` + +decode p2ms input + +#### Arguments + +1. input `Buffer` + +#### Result + +decoded `Buffer[]` + +#### Examples + + let hex = '0047304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801483045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501'; + let input = Buffer.from(hex, 'hex') + bitbox.Script.multisig.input.decode(input); + // [ , + // ] + +### `checkP2MSInput` + +check P2MS input format + +#### Arguments + +1. input `Buffer` + +#### Result + +valid `boolean` + +#### Examples + + // check p2ms input + let signatures = [ + Buffer.from("304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801", "hex"), + Buffer.from("3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501", "hex") + ]; + let encoded = bitbox.Script.encodeP2MSInput(signatures); + bitbox.Script.checkP2MSInput(encoded); + // true + + // check p2pkh input + let signature = '304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801'; + let pubKey = '02d9bb8da1de26d390b6f3dcb4e589857730536b646995fa948a8319ede2ca1c15'; + let sigBuf = Buffer.from(signature, 'hex') + let pubKeyBuf = Buffer.from(pubKey, 'hex') + let encoded = bitbox.Script.encodeP2PKHInput(sigBuf, pubKeyBuf); + bitbox.Script.checkP2MSInput(encoded); + // false + +### `encodeP2MSOutput` + +p2ms Output template: `m [pubKeys ...] n OP_CHECKMULTISIG` + +#### Arguments + +1. m `number` +2. pubKeys `Buffer[]` + +#### Result + +output `Buffer` + +#### Examples + + let pubKeys = [ + Buffer.from("02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1", "hex"), + Buffer.from("0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a", "hex") + ]; + let m = pubKeys.length + let buf = bitbox.Script.encodeP2MSOutput(m, pubKeys); + bitbox.Script.toASM(buf); + // OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG + +### `decodeP2MSOutput` + +decode p2ms output + +#### Arguments + +1. output `Buffer` + +#### Result + +buffer `Buffer` + +#### Examples + + let hex = '522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae'; + let output = Buffer.from(hex, 'hex') + bitbox.Script.decodeP2MSOutput(output); + // { m: 2, + // pubKeys: [ , + // ] } + +### `checkP2MSOutput` + +check P2MS output format + +#### Arguments + +1. output `Buffer` + +#### Result + +valid `boolean` + +#### Examples + + // check p2ms output + let pubKeys = [ + Buffer.from("02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1", "hex"), + Buffer.from("0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a", "hex") + ]; + let m = pubKeys.length + let output = bitbox.Script.encodeP2MSOutput(m, pubKeys); + bitbox.Script.checkP2MSOutput(output); + // true + + let node = bitbox.HDNode.fromXPriv('xprv9xoxVbZ7L8jmvKx7e1hgd7muo8H35ysTx1LCKFey5nVHUkHSPBxpzBzt2HVK16hu4m6oN5vfaCWSZQvqtDhfJTCY3t9ocp7H7zcTZ2fVRwL'); + let identifier = bitbox.HDNode.toIdentifier(node); + let output = bitbox.Script.encodeP2PKHOutput(identifier); + bitbox.Script.checkP2MSOutput(output); + // false + +### `encodeP2SHInput` + +p2sh Input template: `` `scriptSig` `serialized scriptPubKey script` `` + +#### Arguments + +1. redeemScriptSig `Buffer` +2. redeemScript `Buffer` + +#### Result + +input`Buffer` + +#### Examples + + let redeemScriptSig = bitbox.Script.fromASM("OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501"); + let redeemScript = bitbox.Script.fromASM("OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG"); + let input = bitbox.Script.encodeP2SHInput(redeemScriptSig, redeemScript); + bitbox.Script.toASM(input) + // OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501 522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae + +### `decodeP2SHInput` + +decode p2sh input + +#### Arguments + +1. input `Buffer` + +#### Result + +decoded `Buffer` + +#### Examples + + let hex = '0047304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801483045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d14050147522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae' + let input = Buffer.from(hex, 'hex') + bitbox.Script.decodeP2SHInput(input) + // { redeemScript: , + // redeemScriptSig: }} + +### `checkP2SHInput` + +check P2SH input format + +#### Arguments + +1. input `Buffer` + +#### Result + +valid `boolean` + +#### Examples + + // check p2sh input + let redeemScriptSig = bitbox.Script.fromASM("OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501") + let redeemScript = bitbox.Script.fromASM("OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG") + let input = bitbox.Script.encodeP2SHInput(redeemScriptSig, redeemScript) + bitbox.Script.checkP2SHInput(input) + // true + + // check p2ms input + let signatures = [ + Buffer.from("304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801", "hex"), + Buffer.from("3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501", "hex") + ]; + let input = bitbox.Script.encodeP2MSInput(signatures); + bitbox.Script.checkP2SHInput(input) + // false + +### `encodeP2SHOutput` + +p2sh Output template: `` OP_HASH160 `scriptHash` OP_EQUAL `` + +#### Arguments + +1. scriptHash `Buffer` + +#### Result + +output `Buffer` + +#### Examples + + let redeemScript = bitbox.Script.fromASM("OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG"); + let scriptHash = bitbox.Crypto.hash160(redeemScript); + let output = bitbox.Script.encodeP2SHOutput(scriptHash); + bitbox.Script.toASM(output) + // OP_HASH160 1b61ebed0c2a16c699a99c3d5ef4d08de7fb1cb8 OP_EQUAL + +### `decodeP2SHOutput` + +decode p2sh output + +#### Arguments + +1. output `Buffer` + +#### Result + +decoded `Buffer` + +#### Examples + + let hex = 'a9141b61ebed0c2a16c699a99c3d5ef4d08de7fb1cb887' + let output = Buffer.from(hex, 'hex') + bitbox.Script.decodeP2SHOutput(output) + // + +### `checkP2SHOutput` + +check P2SH output format + +#### Arguments + +1. output `Buffer` + +#### Result + +valid `boolean` + +#### Examples + + // check p2sh output + let redeemScript = bitbox.Script.fromASM("OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG") + let scriptHash = bitbox.Crypto.hash160(redeemScript) + let output = bitbox.Script.encodeP2SHOutput(scriptHash) + bitbox.Script.checkP2SHOutput(output); + // true + + // check p2ms output + let pubKeys = [ + Buffer.from("02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1", "hex"), + Buffer.from("0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a", "hex") + ]; + let m = pubKeys.length + let output = bitbox.Script.encodeP2MSOutput(m, pubKeys); + bitbox.Script.checkP2SHOutput(output); + // false + +### `classifyInput` + +Classify transaction input + +#### Arguments + +1. input `Buffer` + +#### Result + +type `string` + +#### Examples + + let pubkeyInput = "3045022100ba2c3b717e023966cb16df65ca83f77029e2a5b80c47c47b6956474ac9ff281302201d48ee3292439e284a6654a0e79ac2b8f7fff5c6b0d715260aa296501a239c6441"; + bitbox.Script.classifyInput(bitbox.Script.fromASM(pubkeyInput)); + // pubkey + + let pubkeyhashInput = "30440220280d4a9954c5afe24089bdd545466bd7a8caad8b295e30de9d3cb5e56fccf64e022036663b2c53b5fac674b4b935b53e2a4ea88dfc71c9b879870976d82887542ab441 02969479fa9bea3082697dce683ac05b13ae63016b41d5ca1a450ad40f6c543751"; + bitbox.Script.classifyInput(bitbox.Script.fromASM(pubkeyhashInput)); + // pubkeyhash + + let multisigInput = "OP_0 3045022100fe324541215798b2df68cbd44039615e23c506d4ec1a05572064392a98196b82022068c849fa6699206da2fc6d7848efc1d3804a5816d6293615fe34c1a7f34e1c2f01 3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901 3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01"; + bitbox.Script.classifyInput(bitbox.Script.fromASM(multisigInput)); + // multisig + + let scripthashInput = "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501 522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae"; + bitbox.Script.classifyInput(bitbox.Script.fromASM(scripthashInput)); + // scripthash + +### `classifyOutput` + +Classify transaction output + +#### Arguments + +1. output `Buffer` + +#### Result + +type `string` + +#### Examples + + let nullDataOutput = "OP_RETURN 424348466f7245766572796f6e65"; + bitbox.Script.classifyOutput(bitbox.Script.fromASM(nullDataOutput)); + // nulldata + + let pubkeyOutput = "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 OP_CHECKSIG"; + bitbox.Script.classifyOutput(bitbox.Script.fromASM(pubkeyOutput)); + // pubkey + + let pubkeyhashOutput = "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG"; + bitbox.Script.classifyOutput(bitbox.Script.fromASM(pubkeyhashOutput)); + // pubkeyhash + + let multisigOutput = "OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG"; + bitbox.Script.classifyOutput(bitbox.Script.fromASM(multisigOutput)); + // multisig + + let scripthashOutput = "OP_HASH160 722ff0bc2c3f47b35c20df646c395594da24e90e OP_EQUAL"; + bitbox.Script.classifyOutput(bitbox.Script.fromASM(scripthashOutput)); + // scripthash + +### `encodeNumber` + +Classify transaction output + +#### Arguments + +1. number: `number` + +#### Result + +hex `string` + +#### Examples + + bitbox.Script.encodeNumber(1) + // "01" + + bitbox.Script.encodeNumber(1000) + // "e803" + +### `decodeNumber` + +Classify transaction output + +#### Arguments + +1. buffer: `Buffer` +2. maxLength: `number` **optional** +3. minimal: `boolean` **optional** + +#### Result + +hex `string` + +#### Examples + + bitbox.Script.number.decode(Buffer.from("01", 'hex')) + // 1 + + bitbox.Script.number.decode(Buffer.from("e803", 'hex')) + // 1000 + +## Interfaces + +### opcodes + + { + OP_FALSE: 0 + OP_0: 0 + OP_PUSHDATA1: 76 + OP_PUSHDATA2: 77 + OP_PUSHDATA4: 78 + OP_1NEGATE: 79 + OP_RESERVED: 80 + OP_TRUE: 81 + OP_1: 81 + OP_2: 82 + OP_3: 83 + OP_4: 84 + OP_5: 85 + OP_6: 86 + OP_7: 87 + OP_8: 88 + OP_9: 89 + OP_10: 90 + OP_11: 91 + OP_12: 92 + OP_13: 93 + OP_14: 94 + OP_15: 95 + OP_16: 96 + OP_NOP: 97 + OP_VER: 98 + OP_IF: 99 + OP_NOTIF: 100 + OP_VERIF: 101 + OP_VERNOTIF: 102 + OP_ELSE: 103 + OP_ENDIF: 104 + OP_VERIFY: 105 + OP_RETURN: 106 + OP_TOALTSTACK: 107 + OP_FROMALTSTACK: 108 + OP_2DROP: 109 + OP_2DUP: 110 + OP_3DUP: 111 + OP_2OVER: 112 + OP_2ROT: 113 + OP_2SWAP: 114 + OP_IFDUP: 115 + OP_DEPTH: 116 + OP_DROP: 117 + OP_DUP: 118 + OP_NIP: 119 + OP_OVER: 120 + OP_PICK: 121 + OP_ROLL: 122 + OP_ROT: 123 + OP_SWAP: 124 + OP_TUCK: 125 + OP_CAT: 126 + OP_SPLIT: 127 + OP_NUM2BIN: 128 + OP_BIN2NUM: 129 + OP_SIZE: 130 + OP_INVERT: 131 + OP_AND: 132 // May 2018 reenabled + OP_OR: 133 // May 2018 reenabled + OP_XOR: 134 // May 2018 reenabled + OP_EQUAL: 135 + OP_EQUALVERIFY: 136 + OP_RESERVED1: 137 + OP_RESERVED2: 138 + OP_1ADD: 139 + OP_1SUB: 140 + OP_2MUL: 141 + OP_2DIV: 142 + OP_NEGATE: 143 + OP_ABS: 144 + OP_NOT: 145 + OP_0NOTEQUAL: 146 + OP_ADD: 147 + OP_SUB: 148 + OP_MUL: 149 + OP_DIV: 150 // May 2018 reenabled + OP_MOD: 151 // May 2018 reenabled + OP_LSHIFT: 152 + OP_RSHIFT: 153 + OP_BOOLAND: 154 + OP_BOOLOR: 155 + OP_NUMEQUAL: 156 + OP_NUMEQUALVERIFY: 157 + OP_NUMNOTEQUAL: 158 + OP_LESSTHAN: 159 + OP_GREATERTHAN: 160 + OP_LESSTHANOREQUAL: 161 + OP_GREATERTHANOREQUAL: 162 + OP_MIN: 163 + OP_MAX: 164 + OP_WITHIN: 165 + OP_RIPEMD160: 166 + OP_SHA1: 167 + OP_SHA256: 168 + OP_HASH160: 169 + OP_HASH256: 170 + OP_CODESEPARATOR: 171 + OP_CHECKSIG: 172 + OP_CHECKSIGVERIFY: 173 + OP_CHECKMULTISIG: 174 + OP_CHECKMULTISIGVERIFY: 175 + OP_NOP1: 176 + OP_NOP2: 177 + OP_CHECKLOCKTIMEVERIFY: 177 + OP_NOP3: 178 + OP_CHECKSEQUENCEVERIFY: 178 + OP_NOP4: 179 + OP_NOP5: 180 + OP_NOP6: 181 + OP_NOP7: 182 + OP_NOP8: 183 + OP_NOP9: 184 + OP_NOP10: 185 + OP_CHECKDATASIG: 186 + OP_CHECKDATASIGVERIFY: 187 + OP_PUBKEYHASH: 253 + OP_PUBKEY: 254 + OP_INVALIDOPCODE: 255 + } + +### DecodedP2PKHInput + + { + signature: Buffer + pubKey: Buffer + } + +### DecodedP2MSOutput + + { + m: number + pubKeys: Buffer[] + } + +### DecodedP2SHInput + + { + redeemScript: Buffer + redeemScriptSig: Buffer + } + +### nullData + + { + output: { + encode(data: Buffer): Buffer + decode(output: Buffer): Buffer + check(output: Buffer): boolean + } + } + +#### pubKey + + { + input: + { + encode(signature: Buffer): Buffer + decode(input: Buffer): Buffer + check(input: Buffer): boolean + decodeStack(data: Buffer): Buffer + encodeStack(data: Buffer): Buffer + }, + output: { + encode(pubKey: Buffer): Buffer + decode(output: Buffer): Buffer + check(output: Buffer): boolean + } + } + +### pubKeyHash + + { + input: + { + encode(signature: Buffer, pubKey: Buffer): Buffer + decode(data: Buffer): DecodedP2PKHInput + check(data: Buffer): boolean + decodeStack(data: Buffer): Buffer + encodeStack(data: Buffer): Buffer + }, + output: + { + encode(identifier: Buffer): Buffer + decode(output: Buffer): Buffer + check(output: Buffer): boolean + } + } + +### multisig + + { + input: + { + encode(signatures: Buffer[]): Buffer + decode(input: Buffer): Buffer[] + check(input: Buffer): boolean + }, + output: + { + encode(m: number, pubKeys: Buffer[]): Buffer + decode(output: Buffer): DecodedP2MSOutput + check(output: Buffer): boolean + } + } + +### scriptHash + + { + input: + { + encode(redeemScriptSig: Buffer, redeemScript: Buffer): Buffer + decode(input: Buffer): DecodedP2SHInput + check(data: Buffer): boolean + decodeStack(data: Buffer): Buffer + encodeStack(data: Buffer): Buffer + }, + output: + { + encode(scriptHash: Buffer): Buffer + decode(output: Buffer): Buffer + check(output: Buffer): boolean + } + } + +### scriptNumber + + { + encode(number: number): Buffer + decode(buffer: Buffer, maxLength?: number, minimal?: boolean): number + } diff --git a/docs/socket.md b/docs/socket.md new file mode 100644 index 00000000..14a64996 --- /dev/null +++ b/docs/socket.md @@ -0,0 +1,151 @@ +# Socket + +### `constructor` + +Create new Socket. + +#### Arguments + +1. config `Object`: with properties: + 1. wsURL `string`: optional, Defaults to `wss://ws.bitcoin.com` + 2. bitsocketURL `string`: optional + 3. restURL `string`: optional + 4. callback `Function`: optional + +#### Result + +Socket `Socket` + +#### Examples + + // instance of Socket + let socket = new bitbox.Socket({callback: () => {console.log('connected')}, wsURL: 'wss://ws.bitcoin.com'}) + +### `listen` + +Listen on a websocket to get real\-time data. + +#### Arguments + +1. query `string | object`: type of data to return in real time. `transactions` or `blocks` are valid `string`s. Any BitSocket `query` object is also valid +2. callback `function`: function to be called which gets passed back `message` in real time. + +#### Result + +data `Object`: data returned in real\-time over a websocket + +#### Examples + + // raw websocket data example + + let socket = new bitbox.Socket({callback: () => {console.log('connected')}, wsURL: 'wss://ws.bitcoin.com'}) + socket.listen('transactions', (message) => { + console.log(message) + }) + // returns the following + { + "format": { + "txid": "edbfdc5a149741009df15f8b518bdebc54261854fcdfefd7d8aa8a78b5e14250", + "version": 2, + "locktime": 0, + "size": 225, + "vsize": 225 + }, + "inputs": [ + { + "txid": "92923f5048703bbf4cb78344d200935b37b88cfaa767635cf0c4275942c9b382", + "n": 3, + "script": "304502210099b59aaf9238612ad9ab706cb469dbd13662177e44cfdc5f29101e9e142ceb10022018061daf1127544f1b97817f2430b9f9c78efe54b51303c91c723807834e4ece41 025cc1f660956d4b924a0792b222ddd9b1742280c5e283281364a9b63123fe23e2", + "sequence": 4294967295 + } + ], + "outputs": [ + { + "satoshi": 6526, + "value": "0.00006526", + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 670180972852c974359232baa64f4019f205bfbc OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a914670180972852c974359232baa64f4019f205bfbc88ac", + "type": "pubkeyhash", + "addresses": [ + "1APeQ9A39esuwsPDogNZYpGS5CxC54m5CL" + ] + } + }, + { + "satoshi": 0, + "value": "0.00000000", + "n": 1, + "scriptPubKey": { + "asm": "OP_RETURN 73747265737374657374626974636f696e2e63617368", + "hex": "6a1673747265737374657374626974636f696e2e63617368", + "type": "nulldata", + "addresses": [] + } + } + ] + } + + + let socket = new bitbox.Socket({callback: () => {console.log('connected')}, wsURL: 'https://ws.bitcoin.com'}) + socket.listen('blocks', (message) => { + console.log(message) + }) + // returns the following + { + "transactions": 183, + "totalBCHSent": 1057662477171, + "reward": 1250000000, + "prevHash": "cfac607ebae85629ede7d34f36064d24974f95c90b89c5000000000000000000", + "id": "0d2d939b3793ff8b2e130fe1f5257abd7784bfe147009f000000000000000000", + "hash": "0000000000000000009f0047e1bf8477bd7a25f5e10f132e8bff93379b932d0d", + "merkleRoot": "ac040e9130a71647f29dc55355fbe8db8bb1a5f1ac86b7ee1be0ae8488dc407e", + "version": 549453824, + "time": 1558667998, + "bits": 402882446, + "nonce": 2478895818 + } + + // BitSocket query example + let socket = new bitbox.Socket({ + callback: () => { + console.log("connected") + }, + wsURL: "wss://ws.bitcoin.com" + }) + socket.listen( + { + v: 3, + q: { find: {} } + }, + msg => { + setTimeout(function() { + socket.close(() => { + console.log("closed") + }) + }, 5000) + } + ) + // returns + // {"type":"mempool","data":[{"tx":{"h":"09ff3049857875089519407e6d00634c901ca3e42b79c2357f07ca0806255abd"},"in":[{"i":0,"b0":"MEUCIQD1aIxxL/QsWBU+yaRTWi8CPtF22Lgj9FyFgs/Tk0MzTAIgTrw3P06CszZYN3hE6AzRSntvutzpgb5YM5ydgQJrWhJB","b1":"BGf/LfIPKLxirRiFJYaPQdRh99qzweUAMUzbUhjlY3v9D5wC61s/OD9pjSj/E1R+rwXdkhYTCGHdAhaCTp1zN+M=","str":"3045022100f5688c712ff42c58153ec9a4535a2f023ed176d8b823f45c8582cfd39343334c02204ebc373f4e82b33658377844e80cd14a7b6fbadce981be58339c9d81026b5a1241 0467ff2df20f28bc62ad188525868f41d461f7dab3c1e500314cdb5218e5637bfd0f9c02eb5b3f383f698d28ff13547eaf05dd9216130861dd0216824e9d7337e3","e":{"h":"6749fdb788c89abcbd28008470b7823e6658ce82b6939135ea52dd6df3d529bd","i":1,"a":"qqrxa0h9jqnc7v4wmj9ysetsp3y7w9l36u8gnnjulq"},"h0":"3045022100f5688c712ff42c58153ec9a4535a2f023ed176d8b823f45c8582cfd39343334c02204ebc373f4e82b33658377844e80cd14a7b6fbadce981be58339c9d81026b5a1241","h1":"0467ff2df20f28bc62ad188525868f41d461f7dab3c1e500314cdb5218e5637bfd0f9c02eb5b3f383f698d28ff13547eaf05dd9216130861dd0216824e9d7337e3"}],"out":[{"i":0,"b0":{"op":106},"b1":"XUh5xw==","s1":"]Hy�","b2":"Rjj8ADakaq4888s+Ock4xDyiM5w8CFCcNgQ0WDfncRM=","s2":"F8�\u00006�j�<��>9�8�<�3�<\bP�6\u00044X7�q\u0013","str":"OP_RETURN 5d4879c7 4638fc0036a46aae3cf3cb3e39c938c43ca2339c3c08509c3604345837e77113","e":{"v":0,"i":0},"h1":"5d4879c7","h2":"4638fc0036a46aae3cf3cb3e39c938c43ca2339c3c08509c3604345837e77113"},{"i":1,"b0":{"op":118},"b1":{"op":169},"b2":"Bm6+5ZAnjzKu3IpIZXAMSecX8dc=","s2":"\u0006n��'�2�܊Hep\fI�\u0017��","b3":{"op":136},"b4":{"op":172},"str":"OP_DUP OP_HASH160 066ebee590278f32aedc8a4865700c49e717f1d7 OP_EQUALVERIFY OP_CHECKSIG","e":{"v":2020,"i":1,"a":"qqrxa0h9jqnc7v4wmj9ysetsp3y7w9l36u8gnnjulq"},"h2":"066ebee590278f32aedc8a4865700c49e717f1d7"}],"_id":"5d4879c8a236c608b89c551e"}]} + // closed + +### `close` + +Close websocket connection + +#### Arguments + +1. callback `function` (optional): function to be called. + +#### Examples + + let socket = new bitbox.Socket({callback: () => {console.log('connected')}, wsURL: 'wss://ws.bitcoin.com'}) + socket.listen('transactions', (message) => { + socket.close(() => { + console.log("closed") + }) + }) + // returns the following + // closed diff --git a/docs/transaction.md b/docs/transaction.md new file mode 100644 index 00000000..af42d862 --- /dev/null +++ b/docs/transaction.md @@ -0,0 +1,123 @@ +# Transaction + +## Transaction + +### `details` + +Return details about a Transaction. + +#### Arguments + +- txids `string | string[]`: transaction ID + +#### Result + +details `Promise` + +#### Examples + + // single txid + (async () => { + try { + let details = await bitbox.Transaction.details('a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8'); + console.log(details); + } catch(error) { + console.error(error) + } + })() + + // { + // "txid": "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8", + // "version": 1, + // "locktime": 0, + // "vin": [ + // { + // "coinbase": "04ffff001d029804", + // "sequence": 4294967295, + // "n": 0 + // } + // ], + // "vout": [ + // { + // "value": "50.00000000", + // "n": 0, + // "scriptPubKey": { + // "hex": "41047737b5d3036fcc149960d41ce31d47c5a47d3a843b23898d28a5e24d1482616860ba5bc61f060586c7ac2b0e7e3ec76e4763cf897d5b8b1110691832c9368f8cac", + // "asm": "047737b5d3036fcc149960d41ce31d47c5a47d3a843b23898d28a5e24d1482616860ba5bc61f060586c7ac2b0e7e3ec76e4763cf897d5b8b1110691832c9368f8c OP_CHECKSIG", + // "addresses": [ + // "1QEHawPyyALtoDcXTpQsMNtQCoUswtWRJu" + // ], + // "type": "pubkeyhash" + // }, + // "spentTxId": null, + // "spentIndex": null, + // "spentHeight": null + // } + // ], + // "blockhash": "000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0", + // "blockheight": 507, + // "confirmations": 528404, + // "time": 1231973656, + // "blocktime": 1231973656, + // "isCoinBase": true, + // "valueOut": 50, + // "size": 135 + // } + + // array of txids + (async () => { + try { + let details = await bitbox.Transaction.details(["a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8", "113f1fe1c454a56436d4f93c7c6e315d1ed985d111299e9c2a3e2d3d1e9f177f"]); + console.log(details); + } catch(error) { + console.error(error) + } + })() + + // [ { txid: 'a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8', + // version: 1, + // locktime: 0, + // vin: [ [Object] ], + // vout: [ [Object] ], + // blockhash: '000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0', + // blockheight: 507, + // confirmations: 528728, + // time: 1231973656, + // blocktime: 1231973656, + // isCoinBase: true, + // valueOut: 50, + // size: 135 }, + // { txid: '113f1fe1c454a56436d4f93c7c6e315d1ed985d111299e9c2a3e2d3d1e9f177f', + // version: 1, + // locktime: 0, + // vin: [ [Object], [Object] ], + // vout: [ [Object], [Object] ], + // blockhash: '000000000000000001da2a49a63fb7d0d0893ebcb892aee3fbbfa47c803f9cf0', + // blockheight: 418195, + // confirmations: 111040, + // time: 1467019582, + // blocktime: 1467019582, + // valueOut: 2.09965689, + // size: 372, + // valueIn: 2.0997689, + // fees: 0.00011201 } ] + +## Interfaces + +### TxnDetails + + { + txid: string + version: number + locktime: number + vin: object[] + vout: object[] + blockhash: string + blockheight: number + confirmations: number + time: number + blocktime: number + isCoinBase: boolean + valueOut: number + size: number + } diff --git a/docs/transactionBuilder.md b/docs/transactionBuilder.md new file mode 100644 index 00000000..2a265d3e --- /dev/null +++ b/docs/transactionBuilder.md @@ -0,0 +1,290 @@ +# TransactionBuilder + +### `constructor` + +Create new Transaction Builder. +The Transaction Builder object represents a transaction internally and is used to build a transaction step-by-step. It can then be expressed as a hexadecimal `string` ready to be sent to the \$BCH network. The necessary steps to create a transaction are: [`addInput`](#addinput), [`addOutput`](#addoutput), [`setLockTime`](#setlocktime), [`sign`](#sign) and [`build`](#build). + +#### Arguments + +1. network `string`: Defaults to "mainnet" + +#### Result + +TransactionBuilder `TransactionBuilder` + +#### Examples + + // instance of transaction builder + let transactionBuilder = new bitbox.TransactionBuilder('mainnet'); + +### `hashTypes` + +BITBOX supports the `SIGHASH_ALL`, `SIGHASH_NONE` and `SIGHASH_SINGLE` hash types w/ the `SIGHASH_ANYONECANPAY` modifier. + +#### Examples + + transactionBuilder.hashTypes + // { SIGHASH_ALL: 1, + // SIGHASH_NONE: 2, + // SIGHASH_SINGLE: 3, + // SIGHASH_ANYONECANPAY: 128, + // SIGHASH_BITCOINCASH_BIP143: 64 } + + transactionBuilder.hashTypes.SIGHASH_ALL + // 1 + + // also has a DEFAULT_SEQUENCE of 0xffffffff + transactionBuilder.DEFAULT_SEQUENCE + // 4294967295 + +### `signatureAlgorithms` + +BITBOX supports the `ECDSA` and `SCHNORR` signature algorithms. + +#### Examples + + transactionBuilder.signatureAlgorithms + // { ECDSA: 0, + // SCHNORR: 1 } + +### `addInput` + +Add input to transaction + +#### Arguments + +1. txid `string`: txid of vout +2. index `number`: index of vout +3. sequence `number` **optional**: relative lock time. Default `0xffffffff` +4. prevOutScript `string` **optional**: previous output script + +#### Examples + + // txid of vout + let txid = 'f7890915febe580920df2681d2bac0909ae89bd0cc1d3ed763e5eeba7f337f0e'; + // add input with txid and index of vout + transactionBuilder.addInput(txid, 0); + +### `addOutput` + +Add output to transaction + +#### Arguments + +1. scriptPubKey `string`: legacy/cashaddr address or script +2. sendAmount `number`: amount to send in satoshis + +#### Examples + + let originalAmount = 100000; + let byteCount = bitbox.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 1 }); + // amount to send to receiver. It's the original amount - 1 sat/byte for tx size + let sendAmount = originalAmount - byteCount; + // add output w/ address and amount to send + transactionBuilder.addOutput('bitcoincash:qpuax2tarq33f86wccwlx8ge7tad2wgvqgjqlwshpw', sendAmount); + +### `setLockTime` + +Set [locktime](https://github.com/Bitcoin-com/mastering-bitcoin-cash/blob/master/4-transactions.md#transaction-locktime) + +#### Arguments + +1. locktime `number` + +#### Examples + + let originalAmount = 100000; + let byteCount = bitbox.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 1 }); + // amount to send to receiver. It's the original amount - 1 sat/byte for tx size + let sendAmount = originalAmount - byteCount; + // add output w/ address and amount to send + transactionBuilder.addOutput('bitcoincash:qpuax2tarq33f86wccwlx8ge7tad2wgvqgjqlwshpw', sendAmount); + transactionBuilder.setLockTime(50000) + +### `sign` + +Sign transaction. It creates the unlocking script needed to spend an input. Each input has its own script and thus 'sign' must be called for each input even if the keyPair is the same. + +#### Arguments + +1. vin `number`: vin to sign +2. keyPair `ECPair`: ECPair of HDNode +3. redeemScript `Buffer` +4. hashType `number` +5. originalAmount `number`: satoshis in vin +6. signatureAlgorithm **optional** `number`: Signature Algorithm (ECDSA/Schnorr) + +#### Examples + + let originalAmount = 100000; + // node of address which is going to spend utxo + let hdnode = bitbox.HDNode.fromXPriv("xprvA3eaDg64MwDr72PVGJ7CkvshNAzCDRz7rn98sYrZVAtDSWCAmNGQhEQeCLDcnmcpSkfjhHevXmu4ZL8ZcT9D4vEbG8LpiToZETrHZttw9Yw"); + // keypair + let keyPair = bitbox.HDNode.toKeyPair(hdnode); + // empty redeemScript variable + let redeemScript; + // sign w/ keyPair + transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount, transactionBuilder.signatureAlgorithms.SCHNORR); + +### `build` + +Build transaction + +#### Result + +Transaction `Object`: Transaction + +#### Examples + + // build tx + let tx = transactionBuilder.build(); + +### `toHex` + +Return raw hex of transaction ready to be sent to the \$BCH network + +#### Result + +rawHex `string`: hex encoded raw transaction ready to be sent to the \$BCH network + +#### Examples + + // output rawhex + let hex = tx.toHex(); + // 02000000010e7f337fbaeee563d73e1dccd09be89a90c0bad28126df200958befe150989f7000000006b48304502210085b8eb33f3981315bbe39c6810d0311c6cb39504914300ecd952cab8353222e202200ec95797c06ba8c9b15d59ab80e63300cb2371f67b3969d0b502d0fed733fbed4121025c85a571619e60fed412de0356b4e28f4f3670ab0c2b899dfe60e69aaa6cd4c0ffffffff01a6370000000000001976a91479d3297d1823149f4ec61df31d19f2fad5390c0288ac00000000 + // sendRawTransaction to running BCH node + bitbox.RawTransactions.sendRawTransaction(hex).then((result) => { console.log(result); }, (err) => { console.log(err); }); + // dfe54ec45c6fa2fa85b76d113de85b169d36902eaf6700f1cca21eed1392814b + +### `OP_RETURN` + +Write data to the blockchain w/ `OP_RETURN` + +#### Result + +rawHex `string`: hex encoded raw transaction ready to be sent to the \$BCH network + +#### Examples + + // encode some text as a buffer + let buf = new Buffer('#BCHForEveryone'); + // create array w/ OP_RETURN code and text buffer and encode + let data = bitbox.Script.encode([ + bitbox.Script.opcodes.OP_RETURN, + buf + ]) + // add encoded data as output and send 0 satoshis + transactionBuilder.addOutput(data, 0) + + // later when you decode the raw hex of the tx you'll see this scriptPubKey + "OP_RETURN 23424348466f7245766572796f6e65" + + // you can use BITBOX to decode it to the original text + let fromAsm = bitbox.Script.fromASM("OP_RETURN 23424348466f7245766572796f6e65") + let decoded = bitbox.Script.decode(fromAsm) + decoded[1].toString('ascii') + // #BCHForEveryone + +### `bip66.encode` + +Strict DER signature encoding per [bip66](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki) + +#### Arguments + +1. r `Buffer` +2. s `Buffer` + +#### Result + +encoded `Buffer` + +#### Examples + + let transactionBuilder = new bitbox.TransactionBuilder(); + let r = Buffer.from('1ea1fdff81b3a271659df4aad19bc4ef83def389131a36358fe64b245632e777', 'hex'); + let s = Buffer.from('29e164658be9ce810921bf81d6b86694785a79ea1e52dbfa5105148d1f0bc1', 'hex'); + transactionBuilder.bip66.encode(r, s); + // + +### `bip66.decode` + +Strict DER signature decoding per [bip66](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki) + +#### Arguments + +1. signature `Buffer` + +#### Result + +decoded `Object` + +#### Examples + + let transactionBuilder = new bitbox.TransactionBuilder(); + let signature = new Buffer.from('304302201ea1fdff81b3a271659df4aad19bc4ef83def389131a36358fe64b245632e777021f29e164658be9ce810921bf81d6b86694785a79ea1e52dbfa5105148d1f0bc1', 'hex'); + transactionBuilder.bip66.decode(signature); + // { r: + // , + // s: + // } + +### `bip66.check` + +Check format of [bip66](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki) Strict DER Signature + +#### Arguments + +1. DER `Buffer` + +#### Result + +value `boolean` + +#### Examples + + let transactionBuilder = new bitbox.TransactionBuilder(); + let DER = '3044022029db2d5f4e1dcc04e19266cce3cb135865784c62ab653b307f0e0bb744f5c2aa022000a97f5826912cac8b44d9f577a26f169a2f8db781f2ddb7de2bc886e93b6844'; + let buffer = Buffer.from(DER, 'hex') + transactionBuilder.bip66.check(buffer); + // true + +### `bip68.encode` + +Encoded [bip68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki) relative time lock + +#### Arguments + +1. config `Object`: Valid keys: `seconds` and `block`. `seconds` must be in multiples of 512. + +#### Result + +hex `string`: hex encoded relative timelock + +#### Examples + + let transactionBuilder = new bitbox.TransactionBuilder(); + transactionBuilder.bip68.encode({ seconds: 2048 }) + // 4194308 + transactionBuilder.bip68.encode({ blocks: 52 }) + // 52 + +### `bip68.decode` + +Decoded [bip68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki) relative time lock + +#### Arguments + +1. hex `string`: hex encoded relative lock time + +#### Result + +details `Object`: details about the relative lock time + +#### Examples + + let transactionBuilder = new bitbox.TransactionBuilder(); + transactionBuilder.bip68.decode(0x03ffffff) + // { seconds: 33553920 } + transactionBuilder.bip68.decode(0x0100fffe) + // { blocks: 65534 } diff --git a/docs/util.md b/docs/util.md new file mode 100644 index 00000000..9e28128c --- /dev/null +++ b/docs/util.md @@ -0,0 +1,118 @@ +# Util + +### `validateAddress` + +Return information about the given bitcoin address. + +#### Arguments + +- address `string | string[]` + +#### Result + +- addressDetails `Promise` + +#### Examples + + (async () => { + try { + let validateAddress = await bitbox.Util.validateAddress("bitcoincash:qzc86hrdufhcwlyzk7k82x77kfs2myekn57nv9cw5f"); + console.log(validateAddress); + } catch(error) { + console.error(error) + } + })() + + // { isvalid: true, + // address: '17fshh33qUze2yifiJ2sXgijSMzJ2KNEwu', + // scriptPubKey: '76a914492ae280d70af33acf0ae7cd329b961e65e9cbd888ac', + // ismine: true, + // iswatchonly: false, + // isscript: false, + // pubkey: '0312eeb9ae5f14c3cf43cece11134af860c2ef7d775060e3a578ceec888acada31', + // iscompressed: true, + // account: 'Test' } + + (async () => { + try { + let validateAddress = await bitbox.Util.validateAddress(["bitcoincash:qzc86hrdufhcwlyzk7k82x77kfs2myekn57nv9cw5f"]); + console.log(validateAddress); + } catch(error) { + console.error(error) + } + })() + + // [{ isvalid: true, + // address: '17fshh33qUze2yifiJ2sXgijSMzJ2KNEwu', + // scriptPubKey: '76a914492ae280d70af33acf0ae7cd329b961e65e9cbd888ac', + // ismine: true, + // iswatchonly: false, + // isscript: false, + // pubkey: '0312eeb9ae5f14c3cf43cece11134af860c2ef7d775060e3a578ceec888acada31', + // iscompressed: true, + // account: 'Test' }] + +### `sweep` + +Sweep utxo for `wif` to cashAddress + +#### Arguments + +- wif `string` +- toAddr `string` +- balanceOnly `boolean` **optional**. Defaults to `false` + +#### Result + +- result `string | number` + +#### Examples + + // balance only + (async () => { + try { + const wif = "cP8LcsoMneSyjdtyFTmnASsmAuyd2SfZjG4drp5twAJoSpRa2RCx" + const toAddr = "bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35" + const result = await bitbox.Util.sweep( + wif, + toAddr, + true + ) + console.log(result); + } catch(error) { + console.error(error) + } + })() + // 0.1 + + // sweep utxo + (async () => { + try { + const wif = "cP8LcsoMneSyjdtyFTmnASsmAuyd2SfZjG4drp5twAJoSpRa2RCx" + const toAddr = "bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35" + const result = await bitbox.Util.sweep( + wif, + toAddr + ) + console.log(result); + } catch(error) { + console.error(error) + } + })() + // 6b647ddfbb6b0edfaf61d2952b9f8e195d2dfede0e63fe12e1beab16e5bcfe5c + +## Interfaces + +### AddressDetails + + { + isvalid: boolean + address: string + scriptPubKey: string + ismine: boolean + iswatchonly: boolean + isscript: boolean + pubkey: string + iscompressed: boolean + account: string + } diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..5cc54ec3 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,51 @@ +This directory contains a series of small example apps that illustrate how to +code up common use cases for a Bitcoin Cash application. + +The `low-level` directory +contains low-level applications exercising a single feature of bitbox. Think of +these examples like lego blocks that can be used to build a bigger app. + +The `applications` directory contains example applications like wallets, voting, +and other ideas. + +## Installation +Prior to running these examples, you need to setup this code repository. In the +root directory run these commands: +``` +npm install +npm run build +npm run postbuild +``` + +## Running Examples +You can run each example script by entering its directory and executing `npm start` + +## Basic BCH Wallet Functions +These basic examples in the `applications/wallet` directory are used to bootstrap +a BCH testnet wallet for use with the other examples. Recommended path: + +1. Create a wallet +2. [Fund it with a testnet faucet](https://developer.bitcoin.com/faucets/bch) +3. Check the balance +4. Send some tBCH (testnet BCH) +5. Send tBCH back to the faucet. + +Once those objectives are achieved, you're ready explore some of the other examples. + +* `create-wallet` Create a BCH compatible HD Node wallet on the BCH testnet. +Send test BCH using a testnet faucet (like +[this one](https://developer.bitcoin.com/faucets)) to the address saved in the +wallet.json file generated by this app. + +* `check-balance` Check the balance of your BCH wallet. + +* `send-bch` Send BCH to another address. You can send small amounts of tBCH +(testnet BCH) to the address in the address in the wallet to generate +UTXOs and explore +[the difference between *addresses* and *utxos* in Bitcoin](https://developer.bitcoin.com/mastering-bitcoin-cash/4-transactions/#transaction-outputs). + +* `consolidate-utxos` to combine multiple utxos in an address back into a single +UTXO. + +* `send-all` sends all BCH in an address to another address. Great for sending +you tBCH back to the testnet faucet. diff --git a/examples/applications/wallet/check-balance/check-balance.js b/examples/applications/wallet/check-balance/check-balance.js new file mode 100644 index 00000000..5e0ecc15 --- /dev/null +++ b/examples/applications/wallet/check-balance/check-balance.js @@ -0,0 +1,41 @@ +/* + Check the balance of the root address of an HD node wallet generated + with the create-wallet example. +*/ + +const BITBOX = require("../../../../lib/BITBOX").BITBOX + +// Set NETWORK to either testnet or mainnet +const NETWORK = `testnet` + +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) + +// Open the wallet generated with create-wallet. +let walletInfo +try { + walletInfo = require(`../create-wallet/wallet.json`) +} catch (err) { + console.log( + `Could not open wallet.json. Generate a wallet with create-wallet first.` + ) + process.exit(1) +} + +// Get the balance of the wallet. +async function getBalance() { + try { + // first get BCH balance + const balance = await bitbox.Address.details(walletInfo.cashAddress) + + console.log(`BCH Balance information:`) + console.log(balance) + } catch (err) { + console.error(`Error in getBalance: `, err) + process.exit(1) + } +} +getBalance() diff --git a/examples/applications/wallet/check-balance/package.json b/examples/applications/wallet/check-balance/package.json new file mode 100644 index 00000000..b6654790 --- /dev/null +++ b/examples/applications/wallet/check-balance/package.json @@ -0,0 +1,29 @@ +{ + "name": "check-balance", + "version": "1.0.0", + "description": "Check the balance of an HDNode wallet", + "main": "create-wallet.js", + "scripts": { + "test": "echo no tests yet", + "start": "node check-balance.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Bitcoin-com/bitbox-javascript-sdk.git" + }, + "keywords": [ + "bitbox", + "example", + "bch", + "bitcoin", + "bitcoin cash", + "bitcoin.com", + "javascript" + ], + "author": "Chris Troutner ", + "license": "MIT", + "bugs": { + "url": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/issues" + }, + "homepage": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/blob/master/README.md" +} diff --git a/examples/applications/wallet/consolidate-dust/consolidate-dust.js b/examples/applications/wallet/consolidate-dust/consolidate-dust.js new file mode 100644 index 00000000..f3295482 --- /dev/null +++ b/examples/applications/wallet/consolidate-dust/consolidate-dust.js @@ -0,0 +1,124 @@ +/* + Consolidate all UTXOs of size 546 sats or smaller into + a single UTXO. +*/ + +const BITBOX = require("../../../../lib/BITBOX").BITBOX + +// Set NETWORK to either testnet or mainnet +const NETWORK = `testnet` + +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) + +// Open the wallet generated with create-wallet. +let walletInfo +try { + walletInfo = require(`../create-wallet/wallet.json`) +} catch (err) { + console.log( + `Could not open wallet.json. Generate a wallet with create-wallet first.` + ) + process.exit(1) +} + +const SEND_ADDR = walletInfo.cashAddress +const SEND_MNEMONIC = walletInfo.mnemonic + +async function consolidateDust() { + try { + const transactionBuilder = new bitbox.TransactionBuilder(NETWORK) + + const dust = 546 + let sendAmount = 0 + const inputs = [] + + const u = await bitbox.Address.utxo(SEND_ADDR) + + // Loop through each UTXO assigned to this address. + u.utxos.forEach(utxo => { + // If the UTXO is dust... + if (utxo.satoshis <= dust) { + inputs.push(utxo) + sendAmount += utxo.satoshis + + // ..Add the utxo as an input to the transaction. + transactionBuilder.addInput(utxo.txid, utxo.vout) + } + }) + + if (inputs.length === 0) { + console.log(`No dust found in the wallet address.`) + process.exit(0) + } + + // get byte count to calculate fee. paying 1.0 sat/byte + const byteCount = bitbox.BitcoinCash.getByteCount( + { P2PKH: inputs.length }, + { P2PKH: 1 } + ) + console.log(`byteCount: ${byteCount}`) + + const satoshisPerByte = 1.0 + const txFee = Math.ceil(satoshisPerByte * byteCount) + console.log(`txFee: ${txFee}`) + + // Exit if the transaction costs too much to send. + if (sendAmount - txFee < 0) { + console.log( + `Transaction fee costs more combined dust. Can't send transaction.` + ) + process.exit(1) + } + + // add output w/ address and amount to send + transactionBuilder.addOutput(SEND_ADDR, sendAmount - txFee) + + // Generate a change address from a Mnemonic of a private key. + const change = changeAddrFromMnemonic(SEND_MNEMONIC) + + // Generate a keypair from the change address. + const keyPair = bitbox.HDNode.toKeyPair(change) + + // sign w/ HDNode + let redeemScript + inputs.forEach((input, index) => { + transactionBuilder.sign( + index, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + input.satoshis + ) + }) + + // build tx + const tx = transactionBuilder.build() + + // output rawhex + const hex = tx.toHex() + console.log(`TX hex: ${hex}`) + console.log() + + // Broadcast transation to the network + const broadcast = await bitbox.RawTransactions.sendRawTransaction([hex]) + console.log(`Transaction ID: ${broadcast}`) + } catch (err) { + console.log(`error: `, err) + } +} +consolidateDust() + +// Generate a change address from a Mnemonic of a private key. +function changeAddrFromMnemonic(mnemonic, network) { + const rootSeed = bitbox.Mnemonic.toSeed(mnemonic) + const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, network) + const account = bitbox.HDNode.derivePath(masterHDNode, "m/44'/145'/0'") + + // derive the first external change address HDNode which is going to spend utxo + const change = bitbox.HDNode.derivePath(account, "0/0") + return change +} diff --git a/examples/applications/wallet/consolidate-dust/package.json b/examples/applications/wallet/consolidate-dust/package.json new file mode 100644 index 00000000..3f7295ec --- /dev/null +++ b/examples/applications/wallet/consolidate-dust/package.json @@ -0,0 +1,29 @@ +{ + "name": "consolidate-dust", + "version": "1.0.0", + "description": "Combine dust UTXOs", + "main": "consolidate-dust.js", + "scripts": { + "test": "echo no tests yet", + "start": "node consolidate-dust.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Bitcoin-com/bitbox-javascript-sdk.git" + }, + "keywords": [ + "bitbox", + "example", + "bch", + "bitcoin", + "bitcoin cash", + "bitcoin.com", + "javascript" + ], + "author": "Chris Troutner ", + "license": "MIT", + "bugs": { + "url": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/issues" + }, + "homepage": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/blob/master/README.md" +} diff --git a/examples/applications/wallet/consolidate-utxos/consolidate-utxos.js b/examples/applications/wallet/consolidate-utxos/consolidate-utxos.js new file mode 100644 index 00000000..5edf6d40 --- /dev/null +++ b/examples/applications/wallet/consolidate-utxos/consolidate-utxos.js @@ -0,0 +1,114 @@ +/* + Consolidate all UTXOs in an address into a single UTXO +*/ + +const BITBOX = require("../../../../lib/BITBOX").BITBOX + +// Set NETWORK to either testnet or mainnet +const NETWORK = `testnet` + +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) + +// Open the wallet generated with create-wallet. +let walletInfo +try { + walletInfo = require(`../create-wallet/wallet.json`) +} catch (err) { + console.log( + `Could not open wallet.json. Generate a wallet with create-wallet first.` + ) + process.exit(1) +} + +const SEND_ADDR = walletInfo.cashAddress +const SEND_MNEMONIC = walletInfo.mnemonic + +async function consolidateDust() { + try { + const transactionBuilder = new bitbox.TransactionBuilder(NETWORK) + + let sendAmount = 0 + const inputs = [] + + const u = await bitbox.Address.utxo(SEND_ADDR) + + // Loop through each UTXO assigned to this address. + u.utxos.forEach(utxo => { + inputs.push(utxo) + sendAmount += utxo.satoshis + transactionBuilder.addInput(utxo.txid, utxo.vout) + }) + + // get byte count to calculate fee. paying 1.0 sat/byte + const byteCount = bitbox.BitcoinCash.getByteCount( + { P2PKH: inputs.length }, + { P2PKH: 1 } + ) + console.log(`byteCount: ${byteCount}`) + + const satoshisPerByte = 1.0 + const txFee = Math.ceil(satoshisPerByte * byteCount) + console.log(`txFee: ${txFee}`) + + // Exit if the transaction costs too much to send. + if (sendAmount - txFee < 0) { + console.log( + `Transaction fee costs more combined UTXOs. Can't send transaction.` + ) + process.exit(1) + } + + // add output w/ address and amount to send + transactionBuilder.addOutput(SEND_ADDR, sendAmount - txFee) + + // Generate a change address from a Mnemonic of a private key. + const change = changeAddrFromMnemonic(SEND_MNEMONIC) + + // Generate a keypair from the change address. + const keyPair = bitbox.HDNode.toKeyPair(change) + + // sign w/ HDNode + let redeemScript + inputs.forEach((input, index) => { + transactionBuilder.sign( + index, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + input.satoshis + ) + }) + + // build tx + const tx = transactionBuilder.build() + + // output rawhex + const hex = tx.toHex() + console.log(`TX hex: ${hex}`) + console.log() + + // Broadcast transation to the network + const txid = await bitbox.RawTransactions.sendRawTransaction([hex]) + console.log(`Transaction ID: ${txid}`) + console.log(`Check the status of your transaction on this block explorer:`) + console.log(`https://explorer.bitcoin.com/tbch/tx/${txid}`) + } catch (err) { + console.log(`error: `, err) + } +} +consolidateDust() + +// Generate a change address from a Mnemonic of a private key. +function changeAddrFromMnemonic(mnemonic, network) { + const rootSeed = bitbox.Mnemonic.toSeed(mnemonic) + const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, network) + const account = bitbox.HDNode.derivePath(masterHDNode, "m/44'/145'/0'") + + // derive the first external change address HDNode which is going to spend utxo + const change = bitbox.HDNode.derivePath(account, "0/0") + return change +} diff --git a/examples/applications/wallet/consolidate-utxos/package.json b/examples/applications/wallet/consolidate-utxos/package.json new file mode 100644 index 00000000..04ca8db4 --- /dev/null +++ b/examples/applications/wallet/consolidate-utxos/package.json @@ -0,0 +1,29 @@ +{ + "name": "consolidate-utxos", + "version": "1.0.0", + "description": "Combine all UTXOs in an address into a single UTXO", + "main": "consolidate-utxos.js", + "scripts": { + "test": "echo no tests yet", + "start": "node consolidate-utxos.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Bitcoin-com/bitbox-javascript-sdk.git" + }, + "keywords": [ + "bitbox", + "example", + "bch", + "bitcoin", + "bitcoin cash", + "bitcoin.com", + "javascript" + ], + "author": "Chris Troutner ", + "license": "MIT", + "bugs": { + "url": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/issues" + }, + "homepage": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/blob/master/README.md" +} diff --git a/examples/applications/wallet/create-wallet/create-wallet.js b/examples/applications/wallet/create-wallet/create-wallet.js new file mode 100644 index 00000000..770cc03f --- /dev/null +++ b/examples/applications/wallet/create-wallet/create-wallet.js @@ -0,0 +1,71 @@ +/* + Create an HDNode wallet using bitbox. The mnemonic from this wallet + will be used in future examples. +*/ + +const fs = require("fs") +const BITBOX = require("../../../../lib/BITBOX").BITBOX + +// Set NETWORK to either testnet or mainnet +const NETWORK = `testnet` + +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) + +const lang = "english" // Set the language of the wallet. + +// These objects used for writing wallet information out to a file. +let outStr = "" +const outObj = {} + +// create 256 bit BIP39 mnemonic +const mnemonic = bitbox.Mnemonic.generate( + 128, + bitbox.Mnemonic.wordLists()[lang] +) + +console.log("BIP44 $BCH Wallet") +outStr += "BIP44 $BCH Wallet\n" +console.log(`128 bit ${lang} BIP39 Mnemonic: `, mnemonic) +outStr += `\n128 bit ${lang} BIP32 Mnemonic:\n${mnemonic}\n\n` +outObj.mnemonic = mnemonic + +// root seed buffer +const rootSeed = bitbox.Mnemonic.toSeed(mnemonic) + +// master HDNode +const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, NETWORK) + +// HDNode of BIP44 account +console.log(`BIP44 Account: "m/44'/145'/0'"`) +outStr += `BIP44 Account: "m/44'/145'/0'"\n` + +// Generate the first 10 seed addresses. +for (let i = 0; i < 10; i++) { + const childNode = masterHDNode.derivePath(`m/44'/145'/0'/0/${i}`) + console.log(`m/44'/145'/0'/0/${i}: ${bitbox.HDNode.toCashAddress(childNode)}`) + outStr += `m/44'/145'/0'/0/${i}: ${bitbox.HDNode.toCashAddress(childNode)}\n` + + // Save the first seed address for use in the .json output file. + if (i === 0) { + outObj.cashAddress = bitbox.HDNode.toCashAddress(childNode) + outObj.legacyAddress = bitbox.HDNode.toLegacyAddress(childNode) + outObj.WIF = bitbox.HDNode.toWIF(childNode) + } +} + +// Write the extended wallet information into a text file. +fs.writeFile("wallet-info.txt", outStr, function(err) { + if (err) return console.error(err) + + console.log(`wallet-info.txt written successfully.`) +}) + +// Write out the basic information into a json file for other example apps to use. +fs.writeFile("wallet.json", JSON.stringify(outObj, null, 2), function(err) { + if (err) return console.error(err) + console.log(`wallet.json written successfully.`) +}) diff --git a/examples/applications/wallet/create-wallet/package.json b/examples/applications/wallet/create-wallet/package.json new file mode 100644 index 00000000..66997241 --- /dev/null +++ b/examples/applications/wallet/create-wallet/package.json @@ -0,0 +1,29 @@ +{ + "name": "create-wallet", + "version": "1.0.0", + "description": "Create an HDNode wallet", + "main": "create-wallet.js", + "scripts": { + "test": "echo no tests yet", + "start": "node create-wallet.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Bitcoin-com/bitbox-javascript-sdk.git" + }, + "keywords": [ + "bitbox", + "example", + "bch", + "bitcoin", + "bitcoin cash", + "bitcoin.com", + "javascript" + ], + "author": "Chris Troutner ", + "license": "MIT", + "bugs": { + "url": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/issues" + }, + "homepage": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/blob/master/README.md" +} diff --git a/examples/applications/wallet/get-utxos/get-utxos.js b/examples/applications/wallet/get-utxos/get-utxos.js new file mode 100644 index 00000000..23515a66 --- /dev/null +++ b/examples/applications/wallet/get-utxos/get-utxos.js @@ -0,0 +1,42 @@ +/* + Check the balance of the root address of an HD node wallet generated + with the create-wallet example. +*/ + +const BITBOX = require("../../../../lib/BITBOX").BITBOX + +// Set NETWORK to either testnet or mainnet +const NETWORK = `testnet` + +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) + +// Open the wallet generated with create-wallet. +let walletInfo +try { + walletInfo = require(`../create-wallet/wallet.json`) +} catch (err) { + console.log( + `Could not open wallet.json. Generate a wallet with create-wallet first.` + ) + process.exit(1) +} + +const ADDR = walletInfo.cashAddress + +async function getUtxos() { + try { + // first get BCH balance + const utxos = await bitbox.Address.utxo(ADDR) + + console.log(`UTXO information for address ${ADDR}:`) + console.log(utxos) + } catch (err) { + console.error(`Error in getUtxos: `, err) + throw err + } +} +getUtxos() diff --git a/examples/applications/wallet/get-utxos/package.json b/examples/applications/wallet/get-utxos/package.json new file mode 100644 index 00000000..f62d3ffb --- /dev/null +++ b/examples/applications/wallet/get-utxos/package.json @@ -0,0 +1,29 @@ +{ + "name": "get-utxos", + "version": "1.0.0", + "description": "Get UTXOs associated with an address", + "main": "get-utxos.js", + "scripts": { + "test": "echo no tests yet", + "start": "node get-utxos.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Bitcoin-com/bitbox-javascript-sdk.git" + }, + "keywords": [ + "bitbox", + "example", + "bch", + "bitcoin", + "bitcoin cash", + "bitcoin.com", + "javascript" + ], + "author": "Chris Troutner ", + "license": "MIT", + "bugs": { + "url": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/issues" + }, + "homepage": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/blob/master/README.md" +} diff --git a/examples/applications/wallet/send-WIF/package.json b/examples/applications/wallet/send-WIF/package.json new file mode 100644 index 00000000..be328d32 --- /dev/null +++ b/examples/applications/wallet/send-WIF/package.json @@ -0,0 +1,29 @@ +{ + "name": "send-wif", + "version": "1.0.0", + "description": "Send some tBCH to another address using WIF as input.", + "main": "send-wif.js", + "scripts": { + "test": "echo no tests yet", + "start": "node send-wif.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Bitcoin-com/bitbox-javascript-sdk.git" + }, + "keywords": [ + "bitbox", + "example", + "bch", + "bitcoin", + "bitcoin cash", + "bitcoin.com", + "javascript" + ], + "author": "Chris Troutner ", + "license": "MIT", + "bugs": { + "url": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/issues" + }, + "homepage": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/blob/master/README.md" +} diff --git a/examples/applications/wallet/send-WIF/send-wif.js b/examples/applications/wallet/send-WIF/send-wif.js new file mode 100644 index 00000000..ad10b5df --- /dev/null +++ b/examples/applications/wallet/send-WIF/send-wif.js @@ -0,0 +1,152 @@ +/* + Same as send-bch example, except this uses a WIF instead of a mnemonic to + sign the transaction. + Send 1000 satoshis to RECV_ADDR. +*/ + +const BITBOX = require("../../../../lib/BITBOX").BITBOX + +// Set NETWORK to either testnet or mainnet +const NETWORK = `testnet` + +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) + +// Open the wallet generated with create-wallet. +let walletInfo +try { + walletInfo = require(`../create-wallet/wallet.json`) +} catch (err) { + console.log( + `Could not open wallet.json. Generate a wallet with create-wallet first.` + ) + process.exit(1) +} + +// Replace the address below with the address you want to send the BCH to. +let RECV_ADDR = `` +const SATOSHIS_TO_SEND = 1000 + +const SEND_ADDR = walletInfo.cashAddress +const SEND_WIF = walletInfo.WIF + +async function sendBch() { + try { + // Send the money back to yourself if the users hasn't specified a destination. + if (RECV_ADDR === "") RECV_ADDR = SEND_ADDR + + // Get the balance of the sending address. + const balance = await getBCHBalance(SEND_ADDR, false) + console.log(`balance: ${JSON.stringify(balance, null, 2)}`) + console.log(`Balance of sending address ${SEND_ADDR} is ${balance} BCH.`) + + // Exit if the balance is zero. + if (balance <= 0.0) { + console.log(`Balance of sending address is zero. Exiting.`) + process.exit(0) + } + + const SEND_ADDR_LEGACY = bitbox.Address.toLegacyAddress(SEND_ADDR) + const RECV_ADDR_LEGACY = bitbox.Address.toLegacyAddress(RECV_ADDR) + console.log(`Sender Legacy Address: ${SEND_ADDR_LEGACY}`) + console.log(`Receiver Legacy Address: ${RECV_ADDR_LEGACY}`) + + const balance2 = await getBCHBalance(RECV_ADDR, false) + console.log(`Balance of recieving address ${RECV_ADDR} is ${balance2} BCH.`) + + const u = await bitbox.Address.utxo(SEND_ADDR) + const utxo = findBiggestUtxo(u.utxos) + console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`) + + const transactionBuilder = new bitbox.TransactionBuilder(NETWORK) + + const satoshisToSend = SATOSHIS_TO_SEND + const originalAmount = utxo.satoshis + const vout = utxo.vout + const txid = utxo.txid + + // add input with txid and index of vout + transactionBuilder.addInput(txid, vout) + + // get byte count to calculate fee. paying 1.2 sat/byte + const byteCount = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 2 } + ) + console.log(`byteCount: ${byteCount}`) + const satoshisPerByte = 1.0 + const txFee = Math.floor(satoshisPerByte * byteCount) + console.log(`txFee: ${txFee}`) + + // amount to send back to the sending address. + // It's the original amount - 1 sat/byte for tx size + const remainder = originalAmount - satoshisToSend - txFee + + // add output w/ address and amount to send + transactionBuilder.addOutput(RECV_ADDR, satoshisToSend) + transactionBuilder.addOutput(SEND_ADDR, remainder) + + const ecPair = bitbox.ECPair.fromWIF(SEND_WIF) + + // Sign the transaction with the HD node. + let redeemScript + transactionBuilder.sign( + 0, + ecPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + + // build tx + const tx = transactionBuilder.build() + // output rawhex + const hex = tx.toHex() + console.log(`TX hex: ${hex}`) + console.log() + + // Broadcast transation to the network + const txidStr = await bitbox.RawTransactions.sendRawTransaction([hex]) + console.log(`Transaction ID: ${txidStr}`) + console.log(`Check the status of your transaction on this block explorer:`) + console.log(`https://explorer.bitcoin.com/tbch/tx/${txidStr}`) + } catch (err) { + console.log(`error: `, err) + } +} +sendBch() + +// Get the balance in BCH of a BCH address. +async function getBCHBalance(addr, verbose) { + try { + const bchBalance = await bitbox.Address.details(addr) + + if (verbose) console.log(bchBalance) + + return bchBalance.balance + } catch (err) { + console.error(`Error in getBCHBalance: `, err) + console.log(`addr: ${addr}`) + throw err + } +} + +// Returns the utxo with the biggest balance from an array of utxos. +function findBiggestUtxo(utxos) { + let largestAmount = 0 + let largestIndex = 0 + + for (let i = 0; i < utxos.length; i++) { + const thisUtxo = utxos[i] + + if (thisUtxo.satoshis > largestAmount) { + largestAmount = thisUtxo.satoshis + largestIndex = i + } + } + + return utxos[largestIndex] +} diff --git a/examples/applications/wallet/send-all/package.json b/examples/applications/wallet/send-all/package.json new file mode 100644 index 00000000..aacb5cec --- /dev/null +++ b/examples/applications/wallet/send-all/package.json @@ -0,0 +1,29 @@ +{ + "name": "send-all", + "version": "1.0.0", + "description": "Send all the BCH in an address to another address", + "main": "send-all.js", + "scripts": { + "test": "echo no tests yet", + "start": "node send-all.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Bitcoin-com/bitbox-javascript-sdk.git" + }, + "keywords": [ + "bitbox", + "example", + "bch", + "bitcoin", + "bitcoin cash", + "bitcoin.com", + "javascript" + ], + "author": "Chris Troutner ", + "license": "MIT", + "bugs": { + "url": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/issues" + }, + "homepage": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/blob/master/README.md" +} diff --git a/examples/applications/wallet/send-all/send-all.js b/examples/applications/wallet/send-all/send-all.js new file mode 100644 index 00000000..6e0ffc9a --- /dev/null +++ b/examples/applications/wallet/send-all/send-all.js @@ -0,0 +1,120 @@ +/* + Send all BCH from one address to another. Similar to consolidating UTXOs. +*/ + +const BITBOX = require("../../../../lib/BITBOX").BITBOX + +// Set NETWORK to either testnet or mainnet +const NETWORK = `testnet` + +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) + +// Open the wallet generated with create-wallet. +let walletInfo +try { + walletInfo = require(`../create-wallet/wallet.json`) +} catch (err) { + console.log( + `Could not open wallet.json. Generate a wallet with create-wallet first.` + ) + process.exit(1) +} + +// Set the address below to the address that should receive the BCH. +let RECV_ADDR = `` + +const SEND_ADDR = walletInfo.cashAddress +const SEND_MNEMONIC = walletInfo.mnemonic + +async function sendAll() { + try { + // Send the money back to yourself if the users hasn't specified a destination. + if (RECV_ADDR === "") RECV_ADDR = SEND_ADDR + + const transactionBuilder = new bitbox.TransactionBuilder(NETWORK) + + let sendAmount = 0 + const inputs = [] + + const u = await bitbox.Address.utxo(SEND_ADDR) + + // Loop through each UTXO assigned to this address. + u.utxos.forEach(utxo => { + inputs.push(utxo) + sendAmount += utxo.satoshis + transactionBuilder.addInput(utxo.txid, utxo.vout) + }) + + // get byte count to calculate fee. paying 1.0 sat/byte + const byteCount = bitbox.BitcoinCash.getByteCount( + { P2PKH: inputs.length }, + { P2PKH: 1 } + ) + console.log(`byteCount: ${byteCount}`) + + const satoshisPerByte = 1.0 + const txFee = Math.ceil(satoshisPerByte * byteCount) + console.log(`txFee: ${txFee}`) + + // Exit if the transaction costs too much to send. + if (sendAmount - txFee < 0) { + console.log( + `Transaction fee costs more combined UTXOs. Can't send transaction.` + ) + process.exit(1) + } + + // add output w/ address and amount to send + transactionBuilder.addOutput(RECV_ADDR, sendAmount - txFee) + + // Generate a change address from a Mnemonic of a private key. + const change = changeAddrFromMnemonic(SEND_MNEMONIC) + + // Generate a keypair from the change address. + const keyPair = bitbox.HDNode.toKeyPair(change) + + // sign w/ HDNode + let redeemScript + inputs.forEach((input, index) => { + transactionBuilder.sign( + index, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + input.satoshis + ) + }) + + // build tx + const tx = transactionBuilder.build() + + // output rawhex + const hex = tx.toHex() + console.log(`TX hex: ${hex}`) + console.log() + + // Broadcast transation to the network + const txid = await bitbox.RawTransactions.sendRawTransaction([hex]) + console.log(`Transaction ID: ${txid}`) + console.log(`Check the status of your transaction on this block explorer:`) + console.log(`https://explorer.bitcoin.com/tbch/tx/${txid}`) + } catch (err) { + console.log(`error: `, err) + } +} +sendAll() + +// Generate a change address from a Mnemonic of a private key. +function changeAddrFromMnemonic(mnemonic, network) { + const rootSeed = bitbox.Mnemonic.toSeed(mnemonic) + const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, network) + const account = bitbox.HDNode.derivePath(masterHDNode, "m/44'/145'/0'") + + // derive the first external change address HDNode which is going to spend utxo + const change = bitbox.HDNode.derivePath(account, "0/0") + return change +} diff --git a/examples/applications/wallet/send-bch/package.json b/examples/applications/wallet/send-bch/package.json new file mode 100644 index 00000000..bc08f0fe --- /dev/null +++ b/examples/applications/wallet/send-bch/package.json @@ -0,0 +1,29 @@ +{ + "name": "send-bch", + "version": "1.0.0", + "description": "Send some tBCH to another address.", + "main": "send-bch.js", + "scripts": { + "test": "echo no tests yet", + "start": "node send-bch.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Bitcoin-com/bitbox-javascript-sdk.git" + }, + "keywords": [ + "bitbox", + "example", + "bch", + "bitcoin", + "bitcoin cash", + "bitcoin.com", + "javascript" + ], + "author": "Chris Troutner ", + "license": "MIT", + "bugs": { + "url": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/issues" + }, + "homepage": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/blob/master/README.md" +} diff --git a/examples/applications/wallet/send-bch/send-bch-multiOutput.js b/examples/applications/wallet/send-bch/send-bch-multiOutput.js new file mode 100644 index 00000000..3ee735ed --- /dev/null +++ b/examples/applications/wallet/send-bch/send-bch-multiOutput.js @@ -0,0 +1,144 @@ +/* + * This example builds a multi-output transaction where the sender sends BCH to 3 other recipients + * in the same transaction. + */ +const senderAddress = '...'; // e.g. bchtest:qp4rhw2w8l... +const senderMnemonic = '...'; // "what does the fox say..." + +const recipient1 = '...'; // e.g. bchtest:qp4rhw2w8l... +const recipient2 = '...'; // e.g. bchtest:qasdf28l... +const recipient3 = '...'; // e.g. bchtest:q3hasd2w8l... + +const network = 'testnet'; + +// Initialise BITBOX based on chosen network +const { BITBOX } = require('bitbox-sdk'); +if (network === 'mainnet') + bitbox = new BITBOX({ restURL: 'https://rest.bitcoin.com/v2/' }) +else bitbox = new BITBOX({ restURL: 'https://trest.bitcoin.com/v2/' }); + +run(); +async function run() { + + try { + // convert cash addresses into legacy addresses + const SEND_ADDR_LEGACY = bitbox.Address.toLegacyAddress(senderAddress); + const RECV_ADDR_LEGACY1 = bitbox.Address.toLegacyAddress(recipient1); + const RECV_ADDR_LEGACY2 = bitbox.Address.toLegacyAddress(recipient2); + const RECV_ADDR_LEGACY3 = bitbox.Address.toLegacyAddress(recipient3); + + // set the BCH to send for each recipient + var rec1Amt = bitbox.BitcoinCash.toSatoshi(0.01); + var rec2Amt = bitbox.BitcoinCash.toSatoshi(0.01); + var rec3Amt = bitbox.BitcoinCash.toSatoshi(0.01); + var totalAmt = rec1Amt+rec2Amt+rec3Amt; + + // retrieve utxos of the sender's address + const u = await bitbox.Address.utxo(senderAddress); + const utxo = findBiggestUtxo(u.utxos); + + // initiates transaction builder based on the selected network + const transactionBuilder = new bitbox.TransactionBuilder(network); + + // since satoshi's can't be fractional at time of code + const satoshisToSend = Math.floor(totalAmt); + const originalAmount = utxo.satoshis; + const vout = utxo.vout; + const txid = utxo.txid; + + // add input with txid and index of vout + transactionBuilder.addInput(txid, vout) + + const outputTx = 4; // # of output transactions i.e. 3 recipients + change address + const byteCount = 300 * outputTx; // 300 bytes per TX output + console.log(`byteCount: ${byteCount}`); + const satoshisPerByte = 1.2; + const txFee = Math.floor(satoshisPerByte * byteCount); + console.log(`txFee: ${txFee}`); + + // amount to send back to the sending address. + // It's the original amount - 1.2 sat/byte for tx size + const remainder = originalAmount - satoshisToSend - txFee; + + // add output w/ address and amount to send + transactionBuilder.addOutput(recipient1, rec1Amt); + transactionBuilder.addOutput(recipient2, rec2Amt); + transactionBuilder.addOutput(recipient3, rec3Amt); + transactionBuilder.addOutput(senderAddress, remainder); + + // Generate a change address from a Mnemonic of a private key. + const change = changeAddrFromMnemonic(senderMnemonic); + + // Generate a keypair from the change address. + const keyPair = bitbox.HDNode.toKeyPair(change); + + // Sign the transaction with the HD node. + let redeemScript + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ); + + // build tx + const tx = transactionBuilder.build(); + // output rawhex + const hex = tx.toHex(); + + // Broadcast transation to the network + const txidStr = await bitbox.RawTransactions.sendRawTransaction([hex]); + console.log(`Transaction ID: ${txidStr}`); + } catch (err) { + console.log(`error: `, err); + } +} + +// Generate a change address from a Mnemonic of a private key. +function changeAddrFromMnemonic(mnemonic, network) { + const rootSeed = bitbox.Mnemonic.toSeed(mnemonic) + const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, network) + const account = bitbox.HDNode.derivePath(masterHDNode, "m/44'/145'/0'") + + // derive the first external change address HDNode which is going to spend utxo + const change = bitbox.HDNode.derivePath(account, "0/0") + return change +} + +// Get the balance in BCH of a BCH address. +async function getBCHBalance(addr, verbose) { + try { + const bchBalance = await bitbox.Address.details(addr) + + if (verbose) console.log(bchBalance) + + return bchBalance.balance + } catch (err) { + console.error(`Error in getBCHBalance: `, err) + console.log(`addr: ${addr}`) + throw err + } +} + +// Returns the utxo with the biggest balance from an array of utxos. +function findBiggestUtxo(utxos) { + let largestAmount = 0 + let largestIndex = 0 + + for (let i = 0; i < utxos.length; i++) { + const thisUtxo = utxos[i] + + if (thisUtxo.satoshis > largestAmount) { + largestAmount = thisUtxo.satoshis + largestIndex = i + } + } + + return utxos[largestIndex] +} + + +module.exports = { + run, +}; diff --git a/examples/applications/wallet/send-bch/send-bch.js b/examples/applications/wallet/send-bch/send-bch.js new file mode 100644 index 00000000..906620f0 --- /dev/null +++ b/examples/applications/wallet/send-bch/send-bch.js @@ -0,0 +1,165 @@ +/* + Send 1000 satoshis to RECV_ADDR. +*/ + +const BITBOX = require("../../../../lib/BITBOX").BITBOX + +// Set NETWORK to either testnet or mainnet +const NETWORK = `testnet` + +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) + +// Open the wallet generated with create-wallet. +let walletInfo +try { + walletInfo = require(`../create-wallet/wallet.json`) +} catch (err) { + console.log( + `Could not open wallet.json. Generate a wallet with create-wallet first.` + ) + process.exit(1) +} + +// Replace the address below with the address you want to send the BCH to. +let RECV_ADDR = `` +const SATOSHIS_TO_SEND = 1000 + +const SEND_ADDR = walletInfo.cashAddress +const SEND_MNEMONIC = walletInfo.mnemonic + +async function sendBch() { + try { + // Send the money back to yourself if the users hasn't specified a destination. + if (RECV_ADDR === "") RECV_ADDR = SEND_ADDR + + // Get the balance of the sending address. + const balance = await getBCHBalance(SEND_ADDR, false) + console.log(`balance: ${JSON.stringify(balance, null, 2)}`) + console.log(`Balance of sending address ${SEND_ADDR} is ${balance} BCH.`) + + // Exit if the balance is zero. + if (balance <= 0.0) { + console.log(`Balance of sending address is zero. Exiting.`) + process.exit(1) + } + + const SEND_ADDR_LEGACY = bitbox.Address.toLegacyAddress(SEND_ADDR) + const RECV_ADDR_LEGACY = bitbox.Address.toLegacyAddress(RECV_ADDR) + console.log(`Sender Legacy Address: ${SEND_ADDR_LEGACY}`) + console.log(`Receiver Legacy Address: ${RECV_ADDR_LEGACY}`) + + const balance2 = await getBCHBalance(RECV_ADDR, false) + console.log(`Balance of receiving address ${RECV_ADDR} is ${balance2} BCH.`) + + const u = await bitbox.Address.utxo(SEND_ADDR) + const utxo = findBiggestUtxo(u.utxos) + console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`) + + const transactionBuilder = new bitbox.TransactionBuilder(NETWORK) + + const satoshisToSend = SATOSHIS_TO_SEND + const originalAmount = utxo.satoshis + const vout = utxo.vout + const txid = utxo.txid + + // add input with txid and index of vout + transactionBuilder.addInput(txid, vout) + + // get byte count to calculate fee. paying 1.2 sat/byte + const byteCount = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 2 } + ) + console.log(`byteCount: ${byteCount}`) + const satoshisPerByte = 1.0 + const txFee = Math.floor(satoshisPerByte * byteCount) + console.log(`txFee: ${txFee}`) + + // amount to send back to the sending address. + // It's the original amount - 1 sat/byte for tx size + const remainder = originalAmount - satoshisToSend - txFee + + // add output w/ address and amount to send + transactionBuilder.addOutput(RECV_ADDR, satoshisToSend) + transactionBuilder.addOutput(SEND_ADDR, remainder) + + // Generate a change address from a Mnemonic of a private key. + const change = changeAddrFromMnemonic(SEND_MNEMONIC) + + // Generate a keypair from the change address. + const keyPair = bitbox.HDNode.toKeyPair(change) + + // Sign the transaction with the HD node. + let redeemScript + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + + // build tx + const tx = transactionBuilder.build() + // output rawhex + const hex = tx.toHex() + console.log(`TX hex: ${hex}`) + console.log() + + // Broadcast transation to the network + const txidStr = await bitbox.RawTransactions.sendRawTransaction([hex]) + console.log(`Transaction ID: ${txidStr}`) + console.log(`Check the status of your transaction on this block explorer:`) + console.log(`https://explorer.bitcoin.com/tbch/tx/${txidStr}`) + } catch (err) { + console.log(`error: `, err) + } +} +sendBch() + +// Generate a change address from a Mnemonic of a private key. +function changeAddrFromMnemonic(mnemonic, network) { + const rootSeed = bitbox.Mnemonic.toSeed(mnemonic) + const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, network) + const account = bitbox.HDNode.derivePath(masterHDNode, "m/44'/145'/0'") + + // derive the first external change address HDNode which is going to spend utxo + const change = bitbox.HDNode.derivePath(account, "0/0") + return change +} + +// Get the balance in BCH of a BCH address. +async function getBCHBalance(addr, verbose) { + try { + const bchBalance = await bitbox.Address.details(addr) + + if (verbose) console.log(bchBalance) + + return bchBalance.balance + } catch (err) { + console.error(`Error in getBCHBalance: `, err) + console.log(`addr: ${addr}`) + throw err + } +} + +// Returns the utxo with the biggest balance from an array of utxos. +function findBiggestUtxo(utxos) { + let largestAmount = 0 + let largestIndex = 0 + + for (let i = 0; i < utxos.length; i++) { + const thisUtxo = utxos[i] + + if (thisUtxo.satoshis > largestAmount) { + largestAmount = thisUtxo.satoshis + largestIndex = i + } + } + + return utxos[largestIndex] +} diff --git a/examples/low-level/OP_RETURN/op_return.js b/examples/low-level/OP_RETURN/op_return.js new file mode 100644 index 00000000..c10fddd9 --- /dev/null +++ b/examples/low-level/OP_RETURN/op_return.js @@ -0,0 +1,78 @@ +/* + Check the outputs of a given transaction for messages in OP_Return +*/ + +// Instantiate bitbox. +const BITBOX = require("../../../lib/BITBOX").BITBOX +const bitbox = new BITBOX() + +// Choose a transaction to parse for OP_Return + +// Long msg example (>20 char) +const txid = `5b81b332c8fa5a2b2e77bb928bd18072af4485f02a7325d346f1f28cf3d4a6bb` + +// Short msg example (<20 char) +// const txid = `d887132e3408f8d10e9b82bec447ca12e485cb6160af88d9b14f22ba865f6793` + +async function parseOP_RETURN(txid) { + console.log(`Parsing transaction ${txid} for messages in OP_RETURN...`) + console.log(``) + + // Get transaction details from txid + let tx + try { + tx = await bitbox.Transaction.details(txid) + } catch (err) { + console.log(`Error in bitbox.Transaction.details(${txid}):`) + console.log(err) + process.exit(1) + } + + // You may wish to log this tx info to the console to inspect and plan your parsing function + // console.log(tx) + + // Initialize an array to store any OP_Return messages + const messages = [] + + // Iterate over outputs looking for OP_Return outputs + tx.vout.forEach(vout => { + // Skip if this is not an OP_Return output + if (typeof vout.scriptPubKey.addresses !== `undefined`) return + + // Pretty print your raw transaction data to the console + // console.log(JSON.stringify(tx, null, 2)) + + try { + // Decode the OP_Return message + let message = vout.scriptPubKey.asm + + // If length is <= 20 characters, translate from hex + if (message.length <= 20) + message = `OP_RETURN ${vout.scriptPubKey.hex.substring(4)}` + + const fromAsm = bitbox.Script.fromASM(message) + const decoded = bitbox.Script.decode(fromAsm) + message = decoded[1].toString(`ascii`) + + // Add this decoded OP_Return message to an array, in case multiple outputs have OP_Return messages + messages.push(message) + } catch (err) { + console.log(`Error in parsing OP_RETURN:`) + console.log(err) + process.exit(1) + } + }) + + if (messages.length === 1) { + console.log(`Message found!`) + console.log() + console.log(`Message: ${messages[0]}`) + } else { + console.log(`${messages.length} messages found!`) + console.log() + for (let j = 0; j < messages.length; j++) + console.log(`Message ${j + 1} of ${messages.length + 1}: ${messages[j]}`) + } +} + +parseOP_RETURN(txid) diff --git a/examples/low-level/OP_RETURN/package.json b/examples/low-level/OP_RETURN/package.json new file mode 100644 index 00000000..da3e8ec8 --- /dev/null +++ b/examples/low-level/OP_RETURN/package.json @@ -0,0 +1,30 @@ +{ + "name": "op_return", + "version": "1.0.0", + "description": "Create a raw tx sending an op_return message", + "main": "op_return.js", + "scripts": { + "test": "echo no tests yet", + "start": "node op_return.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Bitcoin-com/bitbox-javascript-sdk.git" + }, + "keywords": [ + "bitbox", + "example", + "bch", + "bitcoin", + "bitcoin", + "cash", + "bitcoin.com", + "javascript" + ], + "author": "Joey King ", + "license": "MIT", + "bugs": { + "url": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/issues" + }, + "homepage": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/blob/master/README.md" +} diff --git a/examples/low-level/address-details/address-details.js b/examples/low-level/address-details/address-details.js new file mode 100644 index 00000000..5d9524a6 --- /dev/null +++ b/examples/low-level/address-details/address-details.js @@ -0,0 +1,24 @@ +/* + Check the balance of the root address of an HD node wallet generated + with the create-wallet example. +*/ + +// Instantiate bitbox. +const BITBOX = require("../../../lib/BITBOX").BITBOX +const bitbox = new BITBOX({ restURL: "https://trest.bitcoin.com/v2/" }) + +const ADDR = `bchtest:qr45kxqda7yw8atztvkc4ckqnrlhmp0kvsep4p345q` + +async function addressDetails() { + try { + // first get BCH balance + const balance = await bitbox.Address.details(ADDR) + + console.log(`BCH Balance information:`) + console.log(balance) + } catch (err) { + console.error(`Error in getBalance: `, err) + throw err + } +} +addressDetails() diff --git a/examples/low-level/address-details/package.json b/examples/low-level/address-details/package.json new file mode 100644 index 00000000..65f36677 --- /dev/null +++ b/examples/low-level/address-details/package.json @@ -0,0 +1,29 @@ +{ + "name": "address-details", + "version": "1.0.0", + "description": "Get details about an address", + "main": "address-details.js", + "scripts": { + "test": "echo no tests yet", + "start": "node address-details.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Bitcoin-com/bitbox-javascript-sdk.git" + }, + "keywords": [ + "bitbox", + "example", + "bch", + "bitcoin", + "bitcoin cash", + "bitcoin.com", + "javascript" + ], + "author": "Chris Troutner ", + "license": "MIT", + "bugs": { + "url": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/issues" + }, + "homepage": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/blob/master/README.md" +} diff --git a/index.js b/index.js deleted file mode 100755 index 21bc82ed..00000000 --- a/index.js +++ /dev/null @@ -1,239 +0,0 @@ -#!/usr/bin/env node -require("babel-register"); -let path = require('path'); -let program = require('commander'); -let chalk = require('chalk'); -let mkdirp = require('mkdirp'); -let cpFile = require('cp-file'); -let figlet = require('figlet'); -let clear = require('clear'); -let fs = require('fs'); -let os = require('os'); -let touch = require("touch"); -let emoji = require('node-emoji'); -let repl = require("repl"); -let ini = require('ini'); -let BITBOXCli = require('./lib/bitbox-cli').default; -let clone = require('git-clone'); -let corsproxy = require('corsproxy'); -let cmd = require('node-cmd'); - -// let request = require('superagent'); -// let co = require('co'); -// let prompt = require('co-prompt'); -// let fs = require('fs'); -// let ProgressBar = require('progress'); - -program - .version('1.1.0'); - -program - .command('new ') - .option('-s, --scaffold ', 'The framework to use. Options include react, angular, vuejs, nextjs and node.') - .option('-r, --restURL ', 'The rest URL to use. default: https://rest.bitbox.earth/v1/') - .option('-e, --environment ', 'environment of running BITBOX instance. Ex: production, staging. (Default: development)') - .description(`create a new BITBOX application`) - .action((name, options) => { - fs.readFile(os.homedir() + '/.bitboxrc', 'utf8', (err, contents) => { - let config; - if(contents) { - config = ini.parse(contents); - } - - let environment; - if(options && options.environment) { - environment = options.environment; - } else if(config && config.new && config.new.environment) { - environment = config.new.environment; - } else { - environment = 'development'; - } - - let restURL; - if(options && options.restURL) { - restURL = options.restURL; - } else { - restURL = 'https://rest.bitbox.earth/v1/'; - } - - if(options && options.scaffold) { - let scaffold = options.scaffold.toLowerCase(); - let repo; - let conf = {}; - if(scaffold === 'node') { - repo = 'https://github.com/Bitcoin-com/bitbox-scaffold-node.git'; - } else if(scaffold === 'angular') { - repo = 'https://github.com/Bitcoin-com/bitbox-scaffold-angular.git'; - } else if(scaffold === 'next') { - repo = 'https://github.com/Bitcoin-com/bitbox-scaffold-next.git'; - } else if(scaffold === 'react') { - repo = 'https://github.com/Bitcoin-com/bitbox-scaffold-react.git'; - } else if(scaffold === 'vue') { - repo = 'https://github.com/Bitcoin-com/bitbox-scaffold-vue.git'; - } else { - console.log(chalk.red(`Scaffold ${scaffold} not supported`)); - process.exit(1) - } - - if(options && options.repo) { - scaffold = 'custom repo'; - repo = options.repo.toLowerCase(); - } - - clear(); - console.log( - chalk.blue( - figlet.textSync('BITBOX', { - font: '3-D', - horizontalLayout: 'full' - }) - ) - ); - - console.log(chalk.blue(`Scaffolding ${scaffold} app in ${name}`)); - clone(repo, `./${name}`, [conf], (res) => { - if(res == "Error: 'git clone' failed with status 128") { - console.log(chalk.red('Must create new app in to an empty directory')); - } else { - console.log(chalk.green('All done.'), emoji.get(':white_check_mark:')); - console.log(chalk.blue('Now `cd` in to your new project and run `npm install && npm start`'), emoji.get(':rocket:')); - } - }); - return; - } - - console.log(chalk.green(`Creating ${name}/ directory`)); - console.log(chalk.green(`Creating src/ directory: ./${name}/src`)); - mkdirp(`./${name}/src`, (err) => {}); - - console.log(chalk.green(`Creating tests/ directory: ./${name}/tests`)); - mkdirp(`./${name}/tests`, (err) => {}); - - console.log(chalk.green(`Creating bitbox.js configuration file: ./${name}/bitbox.js`)); - - mkdirp(`./${name}`, (err) => {}); - touch(`./${name}/bitbox.js`); - fs.writeFileSync( `./${name}/bitbox.js`, `exports.config = { - networks: { - ${environment}: { - restURL: "${restURL}" - } - } -}; -`); - fs.appendFileSync( `./${name}/.gitignore`, '.console_history'); - console.log(chalk.blue('All done.'), emoji.get(':white_check_mark:')); - console.log(chalk.blue('Go get em! Remember--with great power comes great responsibility.'), emoji.get(':rocket:')); - }); - } -); - -program - .command('console') - .option('-e, --environment ', 'environment of running BITBOX instance. Ex: production, staging. (Default: development)') - .description('Run a console with Bitcoin Cash RPC commands available') - .action((options) => { - let config; - try { - config = require(process.cwd() + '/bitbox.js').config; - } catch(err) { - console.log(chalk.red('Console command must be run inside a bitbox project')); - process.exit(1); - } - let replServer = repl.start('> '); - let historyFile = path.join(process.cwd(), '.console_history'); - require('repl.history')(replServer, historyFile); - - fs.readFile(os.homedir() + '/.bitboxrc', 'utf8', (err, contents) => { - let conf; - if(contents) { - conf = ini.parse(contents); - } - - let environment; - if(options && options.environment) { - environment = options.environment; - } else if(conf && conf.new && conf.new.environment) { - environment = conf.new.environment; - } else { - environment = 'development'; - } - - replServer.context.BITBOX = new BITBOXCli(config.networks[environment]); - }); - } -); - -program - .command('paper') - .option('-e, --encoding ', 'The encoding to use. Options include "cashaddr" and "legacy". (Default: "cashaddr")') - .option('-l, --language ', 'language of mnemonic. Options: chinese_simplified, chinese_traditional, english, french, italian, japanese, korean, spanish. (Default: english)') - .description('Create a paper wallet for easy and safe back up') - .action((options) => { - if(!options.encoding || (options.encoding !== 'cashaddr' && options.encoding !== 'legacy')) { - options.encoding = 'cashaddr'; - } - - if(!options.language || (options.language !== 'chinese_simplified' && options.language !== 'chinese_traditional' && options.language !== 'english' && options.language !== 'french' && options.language !== 'italian' && options.language !== 'japanese' && options.language !== 'korean' && options.language !== 'spanish')) { - options.language = 'english'; - } - - console.log(chalk.blue(`Creating ${options.language} ${options.encoding} paper wallet`)); - let bitbox = new BITBOXCli(); - let mnemonic = bitbox.Mnemonic.generate(256, bitbox.Mnemonic.wordLists()[options.language]); - let keypair = bitbox.Mnemonic.toKeypairs(mnemonic, 1)[0]; - let privateKeyWIF = keypair.privateKeyWIF; - let address = keypair.address; - if(options.encoding === 'legacy') { - address = bitbox.Address.toLegacyAddress(address); - } - touch(`./paper-wallet.html`); - let QRCode = require('qrcode') - - QRCode.toDataURL(privateKeyWIF, (err, privateKeyWIFQR) => { - QRCode.toDataURL(address, (err, addressQR) => { - fs.writeFileSync( `./paper-wallet.html`, ` -
-

Private Key WIF

-

${privateKeyWIF}

-

-
-
-

Public address

-

${address}

-

-
-
-

Mnemonic: ${mnemonic}

-

HD Path: m/44'/145'/0'/0/0

-

Encoding: ${options.encoding}

-

Language: ${options.language}

-
- `); - }) - }) - } -); - -program - .command('proxy') - .description('localhost proxy for POSTing to full BCH node') - .action((options) => { - console.log(chalk.green(`CORS Proxy running at: http://localhost:1337`)); - cmd.run('npm install -g corsproxy'); - cmd.get( - 'corsproxy', - function(err, data, stderr){ - // console.log('') - } - ); - } -); - -program - .parse(process.argv); - -// print help if no command given -if (!process.argv.slice(2).length) { - program.outputHelp() -} diff --git a/index.ts b/index.ts new file mode 100644 index 00000000..cf04fc68 --- /dev/null +++ b/index.ts @@ -0,0 +1,50 @@ +/// + +export * from "./lib/Address" +export * from "./lib/BITBOX" +export * from "./lib/BitcoinCash" +export * from "./lib/Block" +export * from "./lib/Blockchain" +export * from "./lib/CashAccounts" +export * from "./lib/Control" +export * from "./lib/Crypto" +export * from "./lib/ECPair" +export * from "./lib/Generating" +export * from "./lib/HDNode" +export * from "./lib/Mining" +export * from "./lib/Mnemonic" +export * from "./lib/Price" +export * from "./lib/RawTransactions" +export * from "./lib/Schnorr" +export * from "./lib/Script" +export * from "./lib/Socket" +export * from "./lib/Transaction" +export * from "./lib/TransactionBuilder" +export * from "./lib/Util" + +export interface BchInfo { + hashGenesisBlock: string + port: number + portRpc: number + protocol: { + magic: number + } + seedsDns: string[] + versions: { + bip32: { + private: number + public: number + } + bip44: number + private: number + public: number + scripthash: number + messagePrefix: string + } + name: string + per1: number + unit: string + testnet: boolean + toBitcoinJS: any + toBitcore: any +} diff --git a/lib/Address.js b/lib/Address.js deleted file mode 100644 index ab308e8e..00000000 --- a/lib/Address.js +++ /dev/null @@ -1,187 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _axios = require('axios'); - -var _axios2 = _interopRequireDefault(_axios); - -var _bchaddrjs = require('bchaddrjs'); - -var _bchaddrjs2 = _interopRequireDefault(_bchaddrjs); - -var _bitcoincashjsLib = require('bitcoincashjs-lib'); - -var _bitcoincashjsLib2 = _interopRequireDefault(_bitcoincashjsLib); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Address = function () { - function Address(restURL) { - _classCallCheck(this, Address); - - this.restURL = restURL; - } - - // Translate address from any address format into a specific format. - - - _createClass(Address, [{ - key: 'toLegacyAddress', - value: function toLegacyAddress(address) { - return _bchaddrjs2.default.toLegacyAddress(address); - } - }, { - key: 'toCashAddress', - value: function toCashAddress(address) { - var prefix = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; - - if (prefix) { - return _bchaddrjs2.default.toCashAddress(address); - } else { - return _bchaddrjs2.default.toCashAddress(address).split(':')[1]; - } - } - - // Test for address format. - - }, { - key: 'isLegacyAddress', - value: function isLegacyAddress(address) { - return _bchaddrjs2.default.isLegacyAddress(address); - } - }, { - key: 'isCashAddress', - value: function isCashAddress(address) { - return _bchaddrjs2.default.isCashAddress(address); - } - - // Test for address network. - - }, { - key: 'isMainnetAddress', - value: function isMainnetAddress(address) { - if (address[0] === 'x') { - return true; - } else if (address[0] === 't') { - return false; - } else { - return _bchaddrjs2.default.isMainnetAddress(address); - } - } - }, { - key: 'isTestnetAddress', - value: function isTestnetAddress(address) { - if (address[0] === 'x') { - return false; - } else if (address[0] === 't') { - return true; - } else { - return _bchaddrjs2.default.isTestnetAddress(address); - } - } - - // Test for address type. - - }, { - key: 'isP2PKHAddress', - value: function isP2PKHAddress(address) { - return _bchaddrjs2.default.isP2PKHAddress(address); - } - }, { - key: 'isP2SHAddress', - value: function isP2SHAddress(address) { - return _bchaddrjs2.default.isP2SHAddress(address); - } - - // Detect address format. - - }, { - key: 'detectAddressFormat', - value: function detectAddressFormat(address) { - return _bchaddrjs2.default.detectAddressFormat(address); - } - - // Detect address network. - - }, { - key: 'detectAddressNetwork', - value: function detectAddressNetwork(address) { - if (address[0] === 'x') { - return 'mainnet'; - } else if (address[0] === 't') { - return 'testnet'; - } else { - return _bchaddrjs2.default.detectAddressNetwork(address); - } - } - - // Detect address type. - - }, { - key: 'detectAddressType', - value: function detectAddressType(address) { - return _bchaddrjs2.default.detectAddressType(address); - } - }, { - key: 'fromXPub', - value: function fromXPub(xpub) { - var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "0/0"; - - var HDNode = _bitcoincashjsLib2.default.HDNode.fromBase58(xpub, _bitcoincashjsLib2.default.networks[this.detectAddressNetwork(xpub)]); - var address = HDNode.derivePath(path); - return this.toCashAddress(address.getAddress()); - } - }, { - key: 'fromOutputScript', - value: function fromOutputScript(scriptPubKey) { - return _bchaddrjs2.default.toCashAddress(_bitcoincashjsLib2.default.address.fromOutputScript(scriptPubKey)); - } - }, { - key: 'details', - value: function details(address) { - if (typeof address !== 'string') { - address = JSON.stringify(address); - } - return _axios2.default.get(this.restURL + 'address/details/' + address).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'utxo', - value: function utxo(address) { - if (typeof address !== 'string') { - address = JSON.stringify(address); - } - return _axios2.default.get(this.restURL + 'address/utxo/' + address).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'unconfirmed', - value: function unconfirmed(address) { - if (typeof address !== 'string') { - address = JSON.stringify(address); - } - return _axios2.default.get(this.restURL + 'address/unconfirmed/' + address).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }]); - - return Address; -}(); - -exports.default = Address; \ No newline at end of file diff --git a/lib/Address.ts b/lib/Address.ts new file mode 100644 index 00000000..84d36acb --- /dev/null +++ b/lib/Address.ts @@ -0,0 +1,493 @@ +// imports +import axios, { AxiosResponse } from "axios" +import { + AddressDetailsResult, + AddressUnconfirmedResult, + AddressUtxoResult +} from "bitcoin-com-rest" +import * as bcl from "bitcoincashjs-lib" +import { BchInfo } from ".." +import { REST_URL } from "./BITBOX" + +// consts +// TODO: port require statements to impprt +const Bitcoin = require("@bitcoin-dot-com/bitcoincashjs2-lib") +const cashaddr = require("cashaddrjs") +const coininfo = require("coininfo") + +interface Hash { + hash: Buffer +} + +interface Bytes extends Hash { + version: number +} + +interface Decoded extends Hash { + prefix: string + type: string + format: string +} + +interface DecodedHash160 { + legacyAddress: string + cashAddress: string + format: string +} + +export class Address { + public restURL: string + constructor(restURL: string = REST_URL) { + this.restURL = restURL + } + + // Translate address from any address format into a specific format. + public toLegacyAddress(address: string): string { + const { prefix, type, hash }: Decoded = this._decode(address) + let bitcoincash: BchInfo = coininfo.bitcoincash.main + switch (prefix) { + case "bitcoincash": + bitcoincash = coininfo.bitcoincash.main + break + case "bchtest": + bitcoincash = coininfo.bitcoincash.test + break + case "bchreg": + bitcoincash = coininfo.bitcoincash.regtest + break + } + + let version: number = bitcoincash.versions.public + switch (type) { + case "P2PKH": + version = bitcoincash.versions.public + break + case "P2SH": + version = bitcoincash.versions.scripthash + break + } + + const hashBuf: Buffer = Buffer.from(hash) + + return Bitcoin.address.toBase58Check(hashBuf, version) + } + + public toCashAddress( + address: string, + prefix: boolean = true, + regtest: boolean = false + ): string { + const decoded: Decoded = this._decode(address) + + let prefixString: string + if (regtest) prefixString = "bchreg" + else prefixString = decoded.prefix + + const cashAddress: string = cashaddr.encode( + prefixString, + decoded.type, + decoded.hash + ) + + if (prefix) return cashAddress + return cashAddress.split(":")[1] + } + + // Converts legacy address format to hash160 + public legacyToHash160(address: string): string { + const bytes: Bytes = Bitcoin.address.fromBase58Check(address) + return bytes.hash.toString("hex") + } + + // Converts cash address format to hash160 + public cashToHash160(address: string): string { + const legacyAddress: string = this.toLegacyAddress(address) + const bytes: Bytes = Bitcoin.address.fromBase58Check(legacyAddress) + return bytes.hash.toString("hex") + } + + // Converts regtest address format to hash160 + // regtestToHash160(address: string): string { + // const legacyAddress = this.toLegacyAddress(address) + // const bytes = Bitcoin.address.fromBase58Check(legacyAddress) + // return bytes.hash.toString("hex") + // } + + // Converts hash160 to Legacy Address + public hash160ToLegacy( + hash160: string, + network: number = Bitcoin.networks.bitcoin.pubKeyHash + ): string { + const buffer: Buffer = Buffer.from(hash160, "hex") + return Bitcoin.address.toBase58Check(buffer, network) + } + + // Converts hash160 to Cash Address + public hash160ToCash( + hash160: string, + network: number = Bitcoin.networks.bitcoin.pubKeyHash, + regtest: boolean = false + ): string { + const legacyAddress: string = this.hash160ToLegacy(hash160, network) + return this.toCashAddress(legacyAddress, true, regtest) + } + + public isLegacyAddress(address: string): boolean { + return this.detectAddressFormat(address) === "legacy" + } + + public isCashAddress(address: string): boolean { + return this.detectAddressFormat(address) === "cashaddr" + } + + public isHash160(address: string): boolean { + return this._detectHash160Format(address) === "hash160" + } + + // Test for address network. + public isMainnetAddress(address: string): boolean { + if (address[0] === "x") return true + else if (address[0] === "t") return false + + return this.detectAddressNetwork(address) === "mainnet" + } + + public isTestnetAddress(address: string): boolean { + if (address[0] === "x") return false + else if (address[0] === "t") return true + + return this.detectAddressNetwork(address) === "testnet" + } + + public isRegTestAddress(address: string): boolean { + return this.detectAddressNetwork(address) === "regtest" + } + + // Test for address type. + public isP2PKHAddress(address: string): boolean { + return this.detectAddressType(address) === "p2pkh" + } + + public isP2SHAddress(address: string): boolean { + return this.detectAddressType(address) === "p2sh" + } + + public detectAddressFormat(address: string): string { + const decoded: Decoded = this._decode(address) + return decoded.format + } + + public detectAddressNetwork(address: string): string { + if (address[0] === "x") return "mainnet" + else if (address[0] === "t") return "testnet" + + const decoded: Decoded = this._decode(address) + let prefix: string = "" + + switch (decoded.prefix) { + case "bitcoincash": + prefix = "mainnet" + break + case "bchtest": + prefix = "testnet" + break + case "bchreg": + prefix = "regtest" + break + } + + return prefix + } + + public detectAddressType(address: string): string { + const decoded: Decoded = this._decode(address) + return decoded.type.toLowerCase() + } + + public fromXPub(xpub: string, path: string = "0/0"): string { + let bitcoincash: BchInfo + if (xpub[0] === "x") bitcoincash = coininfo.bitcoincash.main + else bitcoincash = coininfo.bitcoincash.test + + const bitcoincashBitcoinJSLib: any = bitcoincash.toBitcoinJS() + const HDNode: bcl.HDNode = Bitcoin.HDNode.fromBase58( + xpub, + bitcoincashBitcoinJSLib + ) + const address: bcl.HDNode = HDNode.derivePath(path) + return this.toCashAddress(address.getAddress()) + } + + public fromXPriv(xpriv: string, path: string = "0'/0"): string { + let bitcoincash: BchInfo + if (xpriv[0] === "x") bitcoincash = coininfo.bitcoincash.main + else bitcoincash = coininfo.bitcoincash.test + + const bitcoincashBitcoinJSLib: any = bitcoincash.toBitcoinJS() + const HDNode: bcl.HDNode = Bitcoin.HDNode.fromBase58( + xpriv, + bitcoincashBitcoinJSLib + ) + const address: bcl.HDNode = HDNode.derivePath(path) + return this.toCashAddress(address.getAddress()) + } + + public fromOutputScript( + scriptPubKey: Buffer, + network: string = "mainnet" + ): string { + let netParam: any + if (network !== "bitcoincash" && network !== "mainnet") + netParam = Bitcoin.networks.testnet + + const regtest: boolean = network === "bchreg" + + return this.toCashAddress( + Bitcoin.address.fromOutputScript(scriptPubKey, netParam), + true, + regtest + ) + } + + public async details( + address: string | string[] + ): Promise { + try { + + // Handle single address. + if (typeof address === "string") { + const response: AxiosResponse = await axios.get( + `${this.restURL}address/details/${address}` + ) + + return response.data + + // Handle array of addresses. + } else if (Array.isArray(address)) { + + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}address/details`, + { + addresses: address + } + ) + + return response.data + } + + throw new Error(`Input address must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async utxo( + address: string | string[] + ): Promise { + try { + // Handle single address. + if (typeof address === "string") { + const response: AxiosResponse = await axios.get( + `${this.restURL}address/utxo/${address}` + ) + return response.data + } else if (Array.isArray(address)) { + + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}address/utxo`, + { + addresses: address + } + ) + + return response.data + } + + throw new Error(`Input address must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async unconfirmed( + address: string | string[] + ): Promise { + try { + // Handle single address. + if (typeof address === "string") { + const response: AxiosResponse = await axios.get( + `${this.restURL}address/unconfirmed/${address}` + ) + return response.data + + // Handle an array of addresses + } else if (Array.isArray(address)) { + + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}address/unconfirmed`, + { + addresses: address + } + ) + + return response.data + } + + throw new Error(`Input address must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async transactions(address: string | string[]): Promise { + try { + // Handle single address. + if (typeof address === "string") { + const response: AxiosResponse = await axios.get( + `${this.restURL}address/transactions/${address}` + ) + return response.data + + // Handle an array of addresses + } else if (Array.isArray(address)) { + + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}address/transactions`, + { + addresses: address + } + ) + + return response.data + } + + throw new Error(`Input address must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + private _detectHash160Format(address: string): string { + const decoded: DecodedHash160 = this._decodeHash160(address) + return decoded.format + } + + private _decode(address: string): Decoded { + try { + return this._decodeLegacyAddress(address) + } catch (error) {} + + try { + return this._decodeCashAddress(address) + } catch (error) {} + + throw new Error(`Unsupported address format : ${address}`) + } + + private _decodeHash160(address: string): DecodedHash160 { + try { + return this._decodeAddressFromHash160(address) + } catch (error) {} + + throw new Error(`Unsupported address format : ${address}`) + } + + private _decodeLegacyAddress(address: string): Decoded { + const { version, hash }: Bytes = Bitcoin.address.fromBase58Check(address) + const info: { + main: any + test: any + } = coininfo.bitcoincash + + let decoded: Decoded = { + prefix: "", + type: "", + hash: hash, + format: "" + } + switch (version) { + case info.main.versions.public: + decoded = { + prefix: "bitcoincash", + type: "P2PKH", + hash: hash, + format: "legacy" + } + break + case info.main.versions.scripthash: + decoded = { + prefix: "bitcoincash", + type: "P2SH", + hash: hash, + format: "legacy" + } + break + case info.test.versions.public: + decoded = { + prefix: "bchtest", + type: "P2PKH", + hash: hash, + format: "legacy" + } + break + case info.test.versions.scripthash: + decoded = { + prefix: "bchtest", + type: "P2SH", + hash: hash, + format: "legacy" + } + break + } + return decoded + } + + private _decodeCashAddress(address: string): Decoded { + if (address.indexOf(":") !== -1) { + const decoded: Decoded = cashaddr.decode(address) + decoded.format = "cashaddr" + return decoded + } + + const prefixes: string[] = ["bitcoincash", "bchtest", "bchreg"] + for (let i: number = 0; i < prefixes.length; ++i) { + try { + const decoded: Decoded = cashaddr.decode(`${prefixes[i]}:${address}`) + decoded.format = "cashaddr" + return decoded + } catch (error) {} + } + + throw new Error(`Invalid format : ${address}`) + } + + private _decodeAddressFromHash160(address: string): DecodedHash160 { + let decodedHash160: DecodedHash160 = { + legacyAddress: "", + cashAddress: "", + format: "" + } + if (address.length === 40) { + decodedHash160 = { + legacyAddress: this.hash160ToLegacy(address), + cashAddress: this.hash160ToCash(address), + format: "hash160" + } + } else if (this.isCashAddress(address) || this.isLegacyAddress(address)) { + decodedHash160 = { + legacyAddress: this.toLegacyAddress(address), + cashAddress: this.toCashAddress(address), + format: "nonHash160" + } + } + return decodedHash160 + } +} diff --git a/lib/BITBOX.ts b/lib/BITBOX.ts new file mode 100644 index 00000000..2206e51e --- /dev/null +++ b/lib/BITBOX.ts @@ -0,0 +1,96 @@ +/// + +// imports +import { Address } from "./Address" +import { BitcoinCash } from "./BitcoinCash" +import { BitDB } from "./BitDB" +import { Block } from "./Block" +import { Blockchain } from "./Blockchain" +import { CashAccounts } from "./CashAccounts" +import { Control } from "./Control" +import { Crypto } from "./Crypto" +import { ECPair } from "./ECPair" +import { Generating } from "./Generating" +import { HDNode } from "./HDNode" +import { IConfig } from "./interfaces/BITBOXInterfaces" +import { Mining } from "./Mining" +import { Mnemonic } from "./Mnemonic" +import { Price } from "./Price" +import { RawTransactions } from "./RawTransactions" +import { Schnorr } from "./Schnorr" +import { Script } from "./Script" +import { Socket } from "./Socket" +import { Transaction } from "./Transaction" +import { TransactionBuilder } from "./TransactionBuilder" +import { Util } from "./Util" + +// Defaults +export const WS_URL = "wss://ws.bitcoin.com" +export const TWS_URL = "wss://tws.bitcoin.com" +export const BITSOCKET_URL = "https://bitsocket.bch.sx" +export const TBITSOCKET_URL = "https://tbitsocket.bitcoin.com" +export const REST_URL = "https://rest.bitcoin.com/v2/" +export const TREST_URL = "https://trest.bitcoin.com/v2/" +export const BITDB_URL = "https://bitdb.bitcoin.com/" +export const TBITDB_URL = "https://tbitdb.bitcoin.com/" + +export class BITBOX { + public restURL: string + public bitdbURL: string + public wsURL: string + public Address: Address + public BitcoinCash: BitcoinCash + public BitDB: BitDB + public Block: Block + public Blockchain: Blockchain + public CashAccounts: CashAccounts + public Control: Control + public Crypto: Crypto + public ECPair: any + public Generating: Generating + public HDNode: HDNode + public Mining: Mining + public Mnemonic: Mnemonic + public Price: Price + public RawTransactions: RawTransactions + public Script: Script + public Transaction: Transaction + public TransactionBuilder: any + public Util: Util + public Socket: any + public Schnorr: Schnorr + constructor(config: IConfig = {}) { + if (config && config.restURL && config.restURL !== "") + this.restURL = config.restURL + else this.restURL = REST_URL + + if (config && config.wsURL && config.wsURL !== "") this.wsURL = config.wsURL + else this.wsURL = WS_URL + + if (config && config.bitdbURL && config.bitdbURL !== "") + this.bitdbURL = config.bitdbURL + else this.bitdbURL = BITDB_URL + + this.Address = new Address(this.restURL) + this.BitcoinCash = new BitcoinCash(this.Address) + this.BitDB = new BitDB(this.bitdbURL) + this.Block = new Block(this.restURL) + this.Blockchain = new Blockchain(this.restURL) + this.CashAccounts = new CashAccounts(this.restURL) + this.Control = new Control(this.restURL) + this.Crypto = new Crypto() + this.ECPair = new ECPair(this.Address) + this.Generating = new Generating(this.restURL) + this.HDNode = new HDNode(this.Address) + this.Mining = new Mining(this.restURL) + this.Mnemonic = new Mnemonic(this.Address) + this.Price = new Price() + this.RawTransactions = new RawTransactions(this.restURL) + this.Script = new Script() + this.Transaction = new Transaction(this.restURL) + this.TransactionBuilder = TransactionBuilder + this.Util = new Util(this.restURL) + this.Socket = Socket + this.Schnorr = new Schnorr() + } +} diff --git a/lib/BitDB.ts b/lib/BitDB.ts new file mode 100644 index 00000000..f37be990 --- /dev/null +++ b/lib/BitDB.ts @@ -0,0 +1,27 @@ +// imports +import axios, { AxiosResponse } from "axios" +import { BITDB_URL } from "./BITBOX" +import { BitDBResponse, QueryInterface } from "./interfaces/BITBOXInterfaces" + +// consts +const Buffer = require("safe-buffer").Buffer + +export class BitDB { + public bitdbURL: string + constructor(bitdbURL: string = BITDB_URL) { + this.bitdbURL = bitdbURL + } + + public async get(query: QueryInterface): Promise { + try { + const s: string = JSON.stringify(query) + const b64: string = Buffer.from(s).toString("base64") + const url: string = `${this.bitdbURL}q/${b64}` + const tokenRes: AxiosResponse = await axios.get(url) + return tokenRes.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } +} diff --git a/lib/BitcoinCash.js b/lib/BitcoinCash.js deleted file mode 100644 index 3f93ee22..00000000 --- a/lib/BitcoinCash.js +++ /dev/null @@ -1,224 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _bitcoincashjsLib = require('bitcoincashjs-lib'); - -var _bitcoincashjsLib2 = _interopRequireDefault(_bitcoincashjsLib); - -var _bchaddrjs = require('bchaddrjs'); - -var _bchaddrjs2 = _interopRequireDefault(_bchaddrjs); - -var _satoshiBitcoin = require('satoshi-bitcoin'); - -var _satoshiBitcoin2 = _interopRequireDefault(_satoshiBitcoin); - -var _bitcoinjsMessage = require('bitcoinjs-message'); - -var _bitcoinjsMessage2 = _interopRequireDefault(_bitcoinjsMessage); - -var _bs = require('bs58'); - -var _bs2 = _interopRequireDefault(_bs); - -var _bip = require('bip21'); - -var _bip2 = _interopRequireDefault(_bip); - -var _coininfo = require('coininfo'); - -var _coininfo2 = _interopRequireDefault(_coininfo); - -var _bip3 = require('bip38'); - -var _bip4 = _interopRequireDefault(_bip3); - -var _wif = require('wif'); - -var _wif2 = _interopRequireDefault(_wif); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Buffer = require('safe-buffer').Buffer; - -var BitcoinCash = function () { - function BitcoinCash() { - _classCallCheck(this, BitcoinCash); - } - - _createClass(BitcoinCash, [{ - key: 'toSatoshi', - - // Translate coins to satoshi value - value: function toSatoshi(coins) { - return _satoshiBitcoin2.default.toSatoshi(coins); - } - - // Translate satoshi to coin value - - }, { - key: 'toBitcoinCash', - value: function toBitcoinCash(satoshis) { - return _satoshiBitcoin2.default.toBitcoin(satoshis); - } - - // Translate satoshi to bits denomination - - }, { - key: 'toBits', - value: function toBits(satoshis) { - return parseFloat(satoshis) / 100000; - } - - // Translate bits to satoshi denomination - - }, { - key: 'fromBits', - value: function fromBits(bits) { - return Math.ceil(bits * 100000); - } - - // sign message - - }, { - key: 'signMessageWithPrivKey', - value: function signMessageWithPrivKey(privateKeyWIF, message) { - var network = privateKeyWIF.charAt(0) === 'c' ? 'testnet' : 'bitcoincash'; - var bitcoincash = void 0; - if (network === 'bitcoincash') { - bitcoincash = _coininfo2.default.bitcoincash.main; - } else { - bitcoincash = _coininfo2.default.bitcoincash.test; - } - var bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS(); - var keyPair = _bitcoincashjsLib2.default.ECPair.fromWIF(privateKeyWIF, bitcoincashBitcoinJSLib); - var privateKey = keyPair.d.toBuffer(32); - return _bitcoinjsMessage2.default.sign(message, privateKey, keyPair.compressed).toString('base64'); - } - - // verify message - - }, { - key: 'verifyMessage', - value: function verifyMessage(address, signature, message) { - return _bitcoinjsMessage2.default.verify(message, _bchaddrjs2.default.toLegacyAddress(address), signature); - } - - // encode base58Check - - }, { - key: 'encodeBase58Check', - value: function encodeBase58Check(hex) { - return _bs2.default.encode(Buffer.from(hex, 'hex')); - } - - // decode base58Check - - }, { - key: 'decodeBase58Check', - value: function decodeBase58Check(address) { - return _bs2.default.decode(address).toString('hex'); - } - - // encode bip21 url - - }, { - key: 'encodeBIP21', - value: function encodeBIP21(address, options) { - return _bip2.default.encode(_bchaddrjs2.default.toCashAddress(address), options); - } - - // decode bip21 url - - }, { - key: 'decodeBIP21', - value: function decodeBIP21(url) { - return _bip2.default.decode(url); - } - }, { - key: 'getByteCount', - value: function getByteCount(inputs, outputs) { - // from https://github.com/bitcoinjs/bitcoinjs-lib/issues/921#issuecomment-354394004 - var totalWeight = 0; - var hasWitness = false; - // assumes compressed pubkeys in all cases. - var types = { - 'inputs': { - 'MULTISIG-P2SH': 49 * 4, - 'MULTISIG-P2WSH': 6 + 41 * 4, - 'MULTISIG-P2SH-P2WSH': 6 + 76 * 4, - 'P2PKH': 148 * 4, - 'P2WPKH': 108 + 41 * 4, - 'P2SH-P2WPKH': 108 + 64 * 4 - }, - 'outputs': { - 'P2SH': 32 * 4, - 'P2PKH': 34 * 4, - 'P2WPKH': 31 * 4, - 'P2WSH': 43 * 4 - } - }; - - Object.keys(inputs).forEach(function (key) { - if (key.slice(0, 8) === 'MULTISIG') { - // ex. "MULTISIG-P2SH:2-3" would mean 2 of 3 P2SH MULTISIG - var keyParts = key.split(':'); - if (keyParts.length !== 2) throw new Error('invalid input: ' + key); - var newKey = keyParts[0]; - var mAndN = keyParts[1].split('-').map(function (item) { - return parseInt(item); - }); - - totalWeight += types.inputs[newKey] * inputs[key]; - var multiplyer = newKey === 'MULTISIG-P2SH' ? 4 : 1; - totalWeight += (73 * mAndN[0] + 34 * mAndN[1]) * multiplyer; - } else { - totalWeight += types.inputs[key] * inputs[key]; - } - if (key.indexOf('W') >= 0) hasWitness = true; - }); - - Object.keys(outputs).forEach(function (key) { - totalWeight += types.outputs[key] * outputs[key]; - }); - - if (hasWitness) totalWeight += 2; - - totalWeight += 10 * 4; - - return Math.ceil(totalWeight / 4); - } - }, { - key: 'encryptBIP38', - value: function encryptBIP38(privKeyWIF, passphrase) { - var decoded = _wif2.default.decode(privKeyWIF); - - return _bip4.default.encrypt(decoded.privateKey, decoded.compressed, passphrase); - } - }, { - key: 'decryptBIP38', - value: function decryptBIP38(encryptedKey, passphrase) { - var network = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'mainnet'; - - var decryptedKey = _bip4.default.decrypt(encryptedKey, passphrase); - var prefix = void 0; - if (network === 'testnet') { - prefix = 0xEF; - } else { - prefix = 0x80; - } - return _wif2.default.encode(prefix, decryptedKey.privateKey, decryptedKey.compressed); - } - }]); - - return BitcoinCash; -}(); - -exports.default = BitcoinCash; \ No newline at end of file diff --git a/lib/BitcoinCash.ts b/lib/BitcoinCash.ts new file mode 100644 index 00000000..1508a532 --- /dev/null +++ b/lib/BitcoinCash.ts @@ -0,0 +1,184 @@ +// imports +import { Address } from "./Address" + +// consts +const Bitcoin = require("@bitcoin-dot-com/bitcoincashjs2-lib") +const sb = require("satoshi-bitcoin") +const bitcoinMessage = require("bitcoinjs-message") +const bs58 = require("bs58") +const bip21 = require("bip21") +const coininfo = require("coininfo") +const bip38 = require("bip38") +const wif = require("wif") + +const Buffer = require("safe-buffer").Buffer + +export interface EncodeBIP21Options { + amount?: number + label?: string + message?: string +} + +export interface BIP21Object { + address: string + options?: EncodeBIP21Options +} + +export interface ByteCountInput { + P2PKH?: number +} + +export interface ByteCountOutput { + P2PKH?: number + P2SH?: number +} + +export class BitcoinCash { + private _address: Address + constructor(address: Address = new Address()) { + this._address = address + } + + public toSatoshi(coins: number): number { + return sb.toSatoshi(coins) + } + + public toBitcoinCash(satoshis: number): number { + return sb.toBitcoin(satoshis) + } + + public toBits(satoshis: number): number { + return satoshis / 100 + } + + public satsToBits(satoshis: number): number { + return satoshis / 100 + } + + public signMessageWithPrivKey( + privateKeyWIF: string, + message: string + ): string { + const network: string = + privateKeyWIF.charAt(0) === "c" ? "testnet" : "mainnet" + let bitcoincash: any + if (network === "mainnet") bitcoincash = coininfo.bitcoincash.main + else bitcoincash = coininfo.bitcoincash.test + + const bitcoincashBitcoinJSLib: any = bitcoincash.toBitcoinJS() + const keyPair: any = Bitcoin.ECPair.fromWIF( + privateKeyWIF, + bitcoincashBitcoinJSLib + ) + const privateKey: any = keyPair.d.toBuffer(32) + return bitcoinMessage + .sign(message, privateKey, keyPair.compressed) + .toString("base64") + } + + public verifyMessage( + address: string, + signature: string, + message: string + ): boolean { + return bitcoinMessage.verify( + message, + this._address.toLegacyAddress(address), + signature + ) + } + + public encodeBase58Check(hex: string): string { + return bs58.encode(Buffer.from(hex, "hex")) + } + + public decodeBase58Check(address: string): string { + return bs58.decode(address).toString("hex") + } + + public encodeBIP21( + address: string, + options: EncodeBIP21Options, + regtest: boolean = false + ): string { + return bip21.encode( + this._address.toCashAddress(address, true, regtest), + options + ) + } + + public decodeBIP21(url: string): BIP21Object { + return bip21.decode(url) + } + + public getByteCount(inputs: any, outputs: any): number { + // from https://github.com/bitcoinjs/bitcoinjs-lib/issues/921#issuecomment-354394004 + let totalWeight: number = 0 + let hasWitness: boolean = false + // assumes compressed pubkeys in all cases. + const types: any = { + inputs: { + "MULTISIG-P2SH": 49 * 4, + "MULTISIG-P2WSH": 6 + 41 * 4, + "MULTISIG-P2SH-P2WSH": 6 + 76 * 4, + P2PKH: 148 * 4, + P2WPKH: 108 + 41 * 4, + "P2SH-P2WPKH": 108 + 64 * 4 + }, + outputs: { + P2SH: 32 * 4, + P2PKH: 34 * 4, + P2WPKH: 31 * 4, + P2WSH: 43 * 4 + } + } + + Object.keys(inputs).forEach(function(key) { + if (key.slice(0, 8) === "MULTISIG") { + // ex. "MULTISIG-P2SH:2-3" would mean 2 of 3 P2SH MULTISIG + const keyParts = key.split(":") + if (keyParts.length !== 2) throw new Error(`invalid input: ${key}`) + const newKey = keyParts[0] + const mAndN = keyParts[1].split("-").map(function(item) { + return parseInt(item) + }) + + totalWeight += types.inputs[newKey] * inputs[key] + const multiplyer = newKey === "MULTISIG-P2SH" ? 4 : 1 + totalWeight += (73 * mAndN[0] + 34 * mAndN[1]) * multiplyer + } else { + totalWeight += types.inputs[key] * inputs[key] + } + if (key.indexOf("W") >= 0) hasWitness = true + }) + + Object.keys(outputs).forEach(function(key) { + totalWeight += types.outputs[key] * outputs[key] + }) + + if (hasWitness) totalWeight += 2 + + totalWeight += 10 * 4 + + return Math.ceil(totalWeight / 4) + } + + public encryptBIP38(privKeyWIF: string, passphrase: string): string { + const decoded: any = wif.decode(privKeyWIF) + + return bip38.encrypt(decoded.privateKey, decoded.compressed, passphrase) + } + + public decryptBIP38( + encryptedKey: string, + passphrase: string, + network: string = "mainnet" + ): string { + const decryptedKey: any = bip38.decrypt(encryptedKey, passphrase) + let prefix: any + if (network === "testnet") prefix = 0xef + else prefix = 0x80 + + return wif.encode(prefix, decryptedKey.privateKey, decryptedKey.compressed) + } +} diff --git a/lib/Block.js b/lib/Block.js deleted file mode 100644 index 4f09336e..00000000 --- a/lib/Block.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _axios = require('axios'); - -var _axios2 = _interopRequireDefault(_axios); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Block = function () { - function Block(restURL) { - _classCallCheck(this, Block); - - this.restURL = restURL; - } - - _createClass(Block, [{ - key: 'details', - value: function details(id) { - return _axios2.default.get(this.restURL + 'block/details/' + id).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }]); - - return Block; -}(); - -exports.default = Block; \ No newline at end of file diff --git a/lib/Block.ts b/lib/Block.ts new file mode 100644 index 00000000..52217255 --- /dev/null +++ b/lib/Block.ts @@ -0,0 +1,74 @@ +import axios, { AxiosRequestConfig, AxiosResponse } from "axios" +import { BlockDetailsResult } from "bitcoin-com-rest" +import { REST_URL } from "./BITBOX" + +export class Block { + public restURL: string + constructor(restURL: string = REST_URL) { + this.restURL = restURL + } + + public async detailsByHeight( + id: number | number[] + ): Promise { + try { + // Single block + if (typeof id === "number") { + const response: AxiosResponse = await axios.get( + `${this.restURL}block/detailsByHeight/${id}` + ) + return response.data + + // Array of blocks. + } else if (Array.isArray(id)) { + + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}block/detailsByHeight`, + { + heights: id + } + ) + + return response.data + } + + throw new Error(`Input must be a number or array of numbers.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async detailsByHash( + hash: string | string[] + ): Promise { + try { + // Single block + if (typeof hash === "string") { + const response: AxiosResponse = await axios.get( + `${this.restURL}block/detailsByHash/${hash}` + ) + return response.data + + // Array of hashes. + } else if (Array.isArray(hash)) { + + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}block/detailsByHash`, + { + hashes: hash + } + ) + + return response.data + } + + throw new Error(`Input must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } +} diff --git a/lib/Blockchain.js b/lib/Blockchain.js deleted file mode 100644 index 09c26307..00000000 --- a/lib/Blockchain.js +++ /dev/null @@ -1,538 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _axios = require('axios'); - -var _axios2 = _interopRequireDefault(_axios); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Blockchain = function () { - function Blockchain(restURL) { - _classCallCheck(this, Blockchain); - - this.restURL = restURL; - } - - _createClass(Blockchain, [{ - key: 'getBestBlockHash', - value: function getBestBlockHash() { - // Returns the hash of the best (tip) block in the longest blockchain. - // - // Result: - // "hex" (string) the block hash hex encoded - return _axios2.default.get(this.restURL + 'blockchain/getBestBlockHash').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getBlock', - value: function getBlock(blockhash) { - var verbose = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; - - // If verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'. - // If verbose is true, returns an Object with information about block . - // - // Arguments: - // 1. "blockhash" (string, required) The block hash - // 2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data - // - // Result (for verbose = true): - // { - // "hash" : "hash", (string) the block hash (same as provided) - // "confirmations" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain - // "size" : n, (numeric) The block size - // "height" : n, (numeric) The block height or index - // "version" : n, (numeric) The block version - // "versionHex" : "00000000", (string) The block version formatted in hexadecimal - // "merkleroot" : "xxxx", (string) The merkle root - // "tx" : [ (array of string) The transaction ids - // "transactionid" (string) The transaction id - // ,... - // ], - // "time" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT) - // "mediantime" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT) - // "nonce" : n, (numeric) The nonce - // "bits" : "1d00ffff", (string) The bits - // "difficulty" : x.xxx, (numeric) The difficulty - // "chainwork" : "xxxx", (string) Expected number of hashes required to produce the chain up to this block (in hex) - // "previousblockhash" : "hash", (string) The hash of the previous block - // "nextblockhash" : "hash" (string) The hash of the next block - // } - // - // Result (for verbose=false): - // "data" (string) A string that is serialized, hex-encoded data for block 'hash'. - - return _axios2.default.get(this.restURL + 'blockchain/getBlock/' + blockhash + '?verbose=' + verbose).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getBlockchainInfo', - value: function getBlockchainInfo() { - // Returns an object containing various state info regarding blockchain processing. - return _axios2.default.get(this.restURL + 'blockchain/getBlockchainInfo').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getBlockCount', - value: function getBlockCount() { - // Returns the number of blocks in the longest blockchain. - // - // Result: - // n (numeric) The current block count - return _axios2.default.get(this.restURL + 'blockchain/getBlockCount').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getBlockHash', - value: function getBlockHash() { - var height = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; - - // Returns hash of block in best-block-chain at height provided. - // - // Arguments: - // 1. height (numeric, required) The height index - // - // Result: - // "hash" (string) The block hash - return _axios2.default.get(this.restURL + 'blockchain/getBlockHash/' + height).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getBlockHeader', - value: function getBlockHeader(hash) { - var verbose = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; - - - // If verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'. - // If verbose is true, returns an Object with information about blockheader . - // - // Arguments: - // 1. "hash" (string, required) The block hash - // 2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data - // - // Result (for verbose = true): - // { - // "hash" : "hash", (string) the block hash (same as provided) - // "confirmations" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain - // "height" : n, (numeric) The block height or index - // "version" : n, (numeric) The block version - // "versionHex" : "00000000", (string) The block version formatted in hexadecimal - // "merkleroot" : "xxxx", (string) The merkle root - // "time" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT) - // "mediantime" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT) - // "nonce" : n, (numeric) The nonce - // "bits" : "1d00ffff", (string) The bits - // "difficulty" : x.xxx, (numeric) The difficulty - // "chainwork" : "0000...1f3" (string) Expected number of hashes required to produce the current chain (in hex) - // "previousblockhash" : "hash", (string) The hash of the previous block - // "nextblockhash" : "hash", (string) The hash of the next block - // } - // - // Result (for verbose=false): - // "data" (string) A string that is serialized, hex-encoded data for block 'hash'. - return _axios2.default.get(this.restURL + 'blockchain/getBlockHeader/' + hash + '?verbose=' + verbose).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getChainTips', - value: function getChainTips() { - // Return information about all known tips in the block tree, including the main chain as well as orphaned branches. - // - // Result: - // [ - // { - // "height": xxxx, (numeric) height of the chain tip - // "hash": "xxxx", (string) block hash of the tip - // "branchlen": 0 (numeric) zero for main chain - // "status": "active" (string) "active" for the main chain - // }, - // { - // "height": xxxx, - // "hash": "xxxx", - // "branchlen": 1 (numeric) length of branch connecting the tip to the main chain - // "status": "xxxx" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid) - // } - // ] - // Possible values for status: - // 1. "invalid" This branch contains at least one invalid block - // 2. "headers-only" Not all blocks for this branch are available, but the headers are valid - // 3. "valid-headers" All blocks are available for this branch, but they were never fully validated - // 4. "valid-fork" This branch is not part of the active chain, but is fully validated - // 5. "active" This is the tip of the active main chain, which is certainly valid - - return _axios2.default.get(this.restURL + 'blockchain/getChainTips').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getDifficulty', - value: function getDifficulty() { - - // Returns the proof-of-work difficulty as a multiple of the minimum difficulty. - // - // Result: - // n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty. - - return _axios2.default.get(this.restURL + 'blockchain/getDifficulty').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getMempoolAncestors', - value: function getMempoolAncestors(txid) { - var verbose = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; - - // If txid is in the mempool, returns all in-mempool ancestors. - // - // Arguments: - // 1. "txid" (string, required) The transaction id (must be in mempool) - // 2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids - // - // Result (for verbose=false): - // [ (json array of strings) - // "transactionid" (string) The transaction id of an in-mempool ancestor transaction - // ,... - // ] - // - // Result (for verbose=true): - // { (json object) - // "transactionid" : { (json object) - // "size" : n, (numeric) transaction size. - // "fee" : n, (numeric) transaction fee in BCH - // "modifiedfee" : n, (numeric) transaction fee with fee deltas used for mining priority - // "time" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT - // "height" : n, (numeric) block height when transaction entered pool - // "startingpriority" : n, (numeric) DEPRECATED. Priority when transaction entered pool - // "currentpriority" : n, (numeric) DEPRECATED. Transaction priority now - // "descendantcount" : n, (numeric) number of in-mempool descendant transactions (including this one) - // "descendantsize" : n, (numeric) virtual transaction size of in-mempool descendants (including this one) - // "descendantfees" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one) - // "ancestorcount" : n, (numeric) number of in-mempool ancestor transactions (including this one) - // "ancestorsize" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one) - // "ancestorfees" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one) - // "depends" : [ (array) unconfirmed transactions used as inputs for this transaction - // "transactionid", (string) parent transaction id - // ... ] - // }, ... - // } - return _axios2.default.get(this.restURL + 'blockchain/getMempoolAncestors/' + txid + '?verbose=' + verbose).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getMempoolDescendants', - value: function getMempoolDescendants(txid) { - var verbose = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; - - // If txid is in the mempool, returns all in-mempool descendants. - // - // Arguments: - // 1. "txid" (string, required) The transaction id (must be in mempool) - // 2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids - // - // Result (for verbose=false): - // [ (json array of strings) - // "transactionid" (string) The transaction id of an in-mempool descendant transaction - // ,... - // ] - // - // Result (for verbose=true): - // { (json object) - // "transactionid" : { (json object) - // "size" : n, (numeric) transaction size. - // "fee" : n, (numeric) transaction fee in BCH - // "modifiedfee" : n, (numeric) transaction fee with fee deltas used for mining priority - // "time" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT - // "height" : n, (numeric) block height when transaction entered pool - // "startingpriority" : n, (numeric) DEPRECATED. Priority when transaction entered pool - // "currentpriority" : n, (numeric) DEPRECATED. Transaction priority now - // "descendantcount" : n, (numeric) number of in-mempool descendant transactions (including this one) - // "descendantsize" : n, (numeric) virtual transaction size of in-mempool descendants (including this one) - // "descendantfees" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one) - // "ancestorcount" : n, (numeric) number of in-mempool ancestor transactions (including this one) - // "ancestorsize" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one) - // "ancestorfees" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one) - // "depends" : [ (array) unconfirmed transactions used as inputs for this transaction - // "transactionid", (string) parent transaction id - // ... ] - // }, ... - // } - - return _axios2.default.get(this.restURL + 'blockchain/getMempoolDescendants/' + txid + '?verbose=' + verbose).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getMempoolEntry', - value: function getMempoolEntry(txid) { - // Returns mempool data for given transaction - // - // Arguments: - // 1. "txid" (string, required) The transaction id (must be in mempool) - // - // Result: - // { (json object) - // "size" : n, (numeric) transaction size. - // "fee" : n, (numeric) transaction fee in BCH - // "modifiedfee" : n, (numeric) transaction fee with fee deltas used for mining priority - // "time" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT - // "height" : n, (numeric) block height when transaction entered pool - // "startingpriority" : n, (numeric) DEPRECATED. Priority when transaction entered pool - // "currentpriority" : n, (numeric) DEPRECATED. Transaction priority now - // "descendantcount" : n, (numeric) number of in-mempool descendant transactions (including this one) - // "descendantsize" : n, (numeric) virtual transaction size of in-mempool descendants (including this one) - // "descendantfees" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one) - // "ancestorcount" : n, (numeric) number of in-mempool ancestor transactions (including this one) - // "ancestorsize" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one) - // "ancestorfees" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one) - // "depends" : [ (array) unconfirmed transactions used as inputs for this transaction - // "transactionid", (string) parent transaction id - // ... ] - // } - - return _axios2.default.get(this.restURL + 'blockchain/getMempoolEntry/' + txid).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getMempoolInfo', - value: function getMempoolInfo() { - // Returns details on the active state of the TX memory pool. - // - // Result: - // { - // "size": xxxxx, (numeric) Current tx count - // "bytes": xxxxx, (numeric) Transaction size. - // "usage": xxxxx, (numeric) Total memory usage for the mempool - // "maxmempool": xxxxx, (numeric) Maximum memory usage for the mempool - // "mempoolminfee": xxxxx (numeric) Minimum fee for tx to be accepted - // } - - return _axios2.default.get(this.restURL + 'blockchain/getMempoolInfo').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getRawMempool', - value: function getRawMempool() { - var verbose = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; - - // Returns all transaction ids in memory pool as a json array of string transaction ids. - // - // Arguments: - // 1. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids - // - // Result: (for verbose = false): - // [ (json array of string) - // "transactionid" (string) The transaction id - // ,... - // ] - // - // Result: (for verbose = true): - // { (json object) - // "transactionid" : { (json object) - // "size" : n, (numeric) transaction size. - // "fee" : n, (numeric) transaction fee in BCH - // "modifiedfee" : n, (numeric) transaction fee with fee deltas used for mining priority - // "time" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT - // "height" : n, (numeric) block height when transaction entered pool - // "startingpriority" : n, (numeric) DEPRECATED. Priority when transaction entered pool - // "currentpriority" : n, (numeric) DEPRECATED. Transaction priority now - // "descendantcount" : n, (numeric) number of in-mempool descendant transactions (including this one) - // "descendantsize" : n, (numeric) virtual transaction size of in-mempool descendants (including this one) - // "descendantfees" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one) - // "ancestorcount" : n, (numeric) number of in-mempool ancestor transactions (including this one) - // "ancestorsize" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one) - // "ancestorfees" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one) - // "depends" : [ (array) unconfirmed transactions used as inputs for this transaction - // "transactionid", (string) parent transaction id - // ... ] - // }, ... - // } - return _axios2.default.get(this.restURL + 'blockchain/getRawMempool?vebose=' + verbose).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getTxOut', - value: function getTxOut(txid, n) { - var include_mempool = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; - - // Returns details about an unspent transaction output. - // - // Arguments: - // 1. "txid" (string, required) The transaction id - // 2. n (numeric, required) vout number - // 3. include_mempool (boolean, optional) Whether to include the mempool - // - // Result: - // { - // "bestblock" : "hash", (string) the block hash - // "confirmations" : n, (numeric) The number of confirmations - // "value" : x.xxx, (numeric) The transaction value in BCH - // "scriptPubKey" : { (json object) - // "asm" : "code", (string) - // "hex" : "hex", (string) - // "reqSigs" : n, (numeric) Number of required signatures - // "type" : "pubkeyhash", (string) The type, eg pubkeyhash - // "addresses" : [ (array of string) array of bitcoin addresses - // "address" (string) bitcoin address - // ,... - // ] - // }, - // "coinbase" : true|false (boolean) Coinbase or not - // } - // - - return _axios2.default.get(this.restURL + 'blockchain/getTxOut/' + txid + '/n?include_mempool=' + include_mempool).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getTxOutProof', - value: function getTxOutProof(txids, blockhash) { - var path = this.restURL + 'blockchain/getTxOutProof/' + txids; - if (blockhash) { - path = path + '?blockhash=' + blockhash; - } - // Returns a hex-encoded proof that "txid" was included in a block. - // - // NOTE: By default this function only works sometimes. This is when there is an - // unspent output in the utxo for this transaction. To make it always work, - // you need to maintain a transaction index, using the -txindex command line option or - // specify the block in which the transaction is included manually (by blockhash). - // - // Arguments: - // 1. "txids" (string) A json array of txids to filter - // [ - // "txid" (string) A transaction hash - // ,... - // ] - // 2. "blockhash" (string, optional) If specified, looks for txid in the block with this hash - // - // Result: - // "data" (string) A string that is a serialized, hex-encoded data for the proof. - return _axios2.default.get(path).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'preciousBlock', - value: function preciousBlock(blockhash) { - // Treats a block as if it were received before others with the same work. - // - // A later preciousblock call can override the effect of an earlier one. - // - // The effects of preciousblock are not retained across restarts. - // - // Arguments: - // 1. "blockhash" (string, required) the hash of the block to mark as precious - - return _axios2.default.get(this.restURL + 'blockchain/preciousBlock/' + blockhash).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'pruneBlockchain', - value: function pruneBlockchain(height) { - // Arguments: - // 1. "height" (numeric, required) The block height to prune up to. May be set to a discrete height, or a unix timestamp - // to prune blocks whose block time is at least 2 hours older than the provided timestamp. - // - // Result: - // n (numeric) Height of the last block pruned. - return _axios2.default.post(this.restURL + 'blockchain/pruneBlockchain/' + height).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'verifyChain', - value: function verifyChain() { - var checklevel = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 3; - var nblocks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 6; - - // Verifies blockchain database. - // - // Arguments: - // 1. checklevel (numeric, optional, 0-4, default=3) How thorough the block verification is. - // 2. nblocks (numeric, optional, default=6, 0=all) The number of blocks to check. - // - // Result: - // true|false (boolean) Verified or not - return _axios2.default.get(this.restURL + 'blockchain/verifyChain?checklevel=' + checklevel + '&nblocks=' + nblocks).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'verifyTxOutProof', - value: function verifyTxOutProof(proof) { - // Verifies that a proof points to a transaction in a block, returning the transaction it commits to - // and throwing an RPC error if the block is not in our best chain - // - // Arguments: - // 1. "proof" (string, required) The hex-encoded proof generated by gettxoutproof - // - // Result: - // ["txid"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof is invalid - - return _axios2.default.get(this.restURL + 'blockchain/verifyTxOutProof/proof').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }]); - - return Blockchain; -}(); - -exports.default = Blockchain; \ No newline at end of file diff --git a/lib/Blockchain.ts b/lib/Blockchain.ts new file mode 100644 index 00000000..b9415c7c --- /dev/null +++ b/lib/Blockchain.ts @@ -0,0 +1,367 @@ +/* + TODO + - Add blockhash functionality back into getTxOutProof +*/ + +import axios, { AxiosRequestConfig, AxiosResponse } from "axios" +import { + BlockchainInfoResult, + BlockDetailsResult, + BlockHeaderResult, + ChainTipResult, + MempoolEntryResult, + MempoolInfoResult, + TxOutResult +} from "bitcoin-com-rest" +import { REST_URL } from "./BITBOX" + +export class Blockchain { + public restURL: string + constructor(restURL: string = REST_URL) { + this.restURL = restURL + } + + public async getBestBlockHash(): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/getBestBlockHash` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getBlock( + blockhash: string, + verbose: boolean = true + ): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/getBlock/${blockhash}?verbose=${verbose}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getBlockchainInfo(): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/getBlockchainInfo` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getBlockCount(): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/getBlockCount` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getBlockHash(height: number = 1): Promise { + // if (typeof height !== "string") height = JSON.stringify(height) + + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/getBlockHash/${height}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getBlockHeader( + hash: string | string[], + verbose: boolean = true + ): Promise { + try { + // Handle single hash. + if (typeof hash === "string") { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/getBlockHeader/${hash}?verbose=${verbose}` + ) + + return response.data + + // Handle array of hashes. + } else if (Array.isArray(hash)) { + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}blockchain/getBlockHeader`, + { + hashes: hash, + verbose: verbose + } + ) + + return response.data + } + + throw new Error(`Input hash must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getChainTips(): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/getChainTips` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getDifficulty(): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/getDifficulty` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + // TODO: add back to REST + public async getMempoolAncestors( + txid: string, + verbose: boolean = false + ): Promise { + if (typeof txid !== "string") txid = JSON.stringify(txid) + + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/getMempoolAncestors/${txid}?verbose=${verbose}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + // TODO: add back to REST + public async getMempoolDescendants( + txid: string, + verbose: boolean = false + ): Promise { + if (typeof txid !== "string") txid = JSON.stringify(txid) + + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/getMempoolDescendants/${txid}?verbose=${verbose}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getMempoolEntry( + txid: string | string[] + ): Promise { + try { + if (typeof txid === "string") { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/getMempoolEntry/${txid}` + ) + + return response.data + } else if (Array.isArray(txid)) { + const options: AxiosRequestConfig = { + method: "POST", + url: `${this.restURL}blockchain/getMempoolEntry`, + data: { + txids: txid + } + } + const response: AxiosResponse = await axios(options) + + return response.data + } + + throw new Error(`Input must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getMempoolInfo(): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/getMempoolInfo` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getRawMempool(verbose: boolean = false): Promise { + // TODO fix verbose + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/getRawMempool?vebose=${verbose}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + // Returns details about an unspent transaction output. + public async getTxOut( + txid: string, + n: any, + include_mempool: boolean = true + ): Promise { + // Input validation + if (typeof txid !== "string" || txid.length !== 64) + throw new Error(`txid needs to be a proper transaction ID`) + + if (isNaN(n)) throw new Error(`n must be an integer`) + + if (typeof include_mempool !== "boolean") + throw new Error(`include_mempool input must be of type boolean`) + + try { + const path: string = `${this.restURL}blockchain/getTxOut/${txid}/${n}?include_mempool=${include_mempool}` + // console.log(`path: ${path}`) + + const response: AxiosResponse = await axios.get(path) + + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getTxOutProof( + txids: string | string[] + ): Promise { + try { + // Single txid. + if (typeof txids === "string") { + const path = `${this.restURL}blockchain/getTxOutProof/${txids}` + //if (blockhash) path = `${path}?blockhash=${blockhash}` + + const response: AxiosResponse = await axios.get(path) + return response.data + + // Array of txids. + } else if (Array.isArray(txids)) { + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}blockchain/getTxOutProof`, + { + txids: txids + } + ) + + return response.data + } + + throw new Error(`Input must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async preciousBlock(blockhash: string): Promise { + // TODO bring this back to REST + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/preciousBlock/${blockhash}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async pruneBlockchain(height: number): Promise { + // TODO bring this back to REST + try { + const response: AxiosResponse = await axios.post( + `${this.restURL}blockchain/pruneBlockchain/${height}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async verifyChain( + checklevel: number = 3, + nblocks: number = 6 + ): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/verifyChain?checklevel=${checklevel}&nblocks=${nblocks}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async verifyTxOutProof(proof: string | string[]): Promise { + try { + // Single block + if (typeof proof === "string") { + const response: AxiosResponse = await axios.get( + `${this.restURL}blockchain/verifyTxOutProof/${proof}` + ) + return response.data + + // Array of hashes. + } else if (Array.isArray(proof)) { + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}blockchain/verifyTxOutProof`, + { + proofs: proof + } + ) + + return response.data + } + + throw new Error(`Input must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } +} diff --git a/lib/CashAccounts.ts b/lib/CashAccounts.ts new file mode 100644 index 00000000..943c8ea3 --- /dev/null +++ b/lib/CashAccounts.ts @@ -0,0 +1,63 @@ +import axios, { AxiosResponse } from "axios" +import { + CashAccountCheckResult, + CashAccountLookupResult, + CashAccountReverseLookupResult +} from "bitcoin-com-rest" +import { REST_URL } from "./BITBOX" + +export class CashAccounts { + public restURL: string + constructor(restURL: string = REST_URL) { + this.restURL = restURL + } + + public async lookup( + account: string, + number: number, + collision?: number + ): Promise { + try { + let col: string = "" + if (collision) { + col = collision.toString() + } + const response: AxiosResponse = await axios.get( + `${this.restURL}cashAccounts/lookup/${account}/${number}/${col}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async check( + account: string, + number: number + ): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}cashAccounts/check/${account}/${number}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async reverseLookup( + cashAddress: string + ): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}cashAccounts/reverseLookup/${cashAddress}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } +} diff --git a/lib/Control.js b/lib/Control.js deleted file mode 100644 index 0f3cdbf8..00000000 --- a/lib/Control.js +++ /dev/null @@ -1,97 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _axios = require('axios'); - -var _axios2 = _interopRequireDefault(_axios); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Control = function () { - function Control(restURL) { - _classCallCheck(this, Control); - - this.restURL = restURL; - } - - _createClass(Control, [{ - key: 'getInfo', - value: function getInfo() { - // DEPRECATED. Returns an object containing various state info. - // - // Result: - // { - // "version": xxxxx, (numeric) the server version - // "protocolversion": xxxxx, (numeric) the protocol version - // "walletversion": xxxxx, (numeric) the wallet version - // "balance": xxxxxxx, (numeric) the total bitcoin balance of the wallet - // "blocks": xxxxxx, (numeric) the current number of blocks processed in the server - // "timeoffset": xxxxx, (numeric) the time offset - // "connections": xxxxx, (numeric) the number of connections - // "proxy": "host:port", (string, optional) the proxy used by the server - // "difficulty": xxxxxx, (numeric) the current difficulty - // "testnet": true|false, (boolean) if the server is using testnet or not - // "keypoololdest": xxxxxx, (numeric) the timestamp (seconds since Unix epoch) of the oldest pre-generated key in the key pool - // "keypoolsize": xxxx, (numeric) how many new keys are pre-generated - // "unlocked_until": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked - // "paytxfee": x.xxxx, (numeric) the transaction fee set in BCH/kB - // "relayfee": x.xxxx, (numeric) minimum relay fee for non-free transactions in BCH/kB - // "errors": "..." (string) any error messages - // } - - return _axios2.default.get(this.restURL + 'control/getInfo').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getMemoryInfo', - value: function getMemoryInfo() { - - // Returns an object containing information about memory usage. - // - // Result: - // { - // "locked": { (json object) Information about locked memory manager - // "used": xxxxx, (numeric) Number of bytes used - // "free": xxxxx, (numeric) Number of bytes available in current arenas - // "total": xxxxxxx, (numeric) Total number of bytes managed - // "locked": xxxxxx, (numeric) Amount of bytes that succeeded locking. If this number is smaller than total, locking pages failed at some point and key data could be swapped to disk. - // "chunks_used": xxxxx, (numeric) Number allocated chunks - // "chunks_free": xxxxx, (numeric) Number unused chunks - // } - // } - // - - return _axios2.default.get(this.restURL + 'control/getMemoryInfo').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - // - // stop() { - // // Stop Bitcoin Cash server. - // return axios.post(`${this.restURL}control/stop`) - // .then((response) => { - // return response.data; - // }) - // .catch((error) => { - // return JSON.stringify(error.response.data.error.message); - // }); - // } - - }]); - - return Control; -}(); - -exports.default = Control; \ No newline at end of file diff --git a/lib/Control.ts b/lib/Control.ts new file mode 100644 index 00000000..85fb6745 --- /dev/null +++ b/lib/Control.ts @@ -0,0 +1,58 @@ +import axios, { AxiosResponse } from "axios" +import { NodeInfoResult } from "bitcoin-com-rest" +import { REST_URL } from "./BITBOX" + +export class Control { + public restURL: string + constructor(restURL: string = REST_URL) { + this.restURL = restURL + } + + public async getInfo(): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}control/getInfo` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getNetworkInfo(): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}control/getNetworkInfo` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + // async getMemoryInfo(): Promise { + // // TODO add back to REST + // try { + // const response: any = await axios.get( + // `${this.restURL}control/getMemoryInfo` + // ) + // return response.data + // } catch (error) { + // if (error.response && error.response.data) throw error.response.data + // else throw error + // } + // } + // + // stop() { + // // Stop Bitcoin Cash server. + // return axios.post(`${this.restURL}control/stop`) + // .then((response) => { + // return response.data; + // }) + // .catch((error) => { + // return JSON.stringify(error.response.data.error.message); + // }); + // } +} diff --git a/lib/Crypto.js b/lib/Crypto.js deleted file mode 100644 index 6760b6b7..00000000 --- a/lib/Crypto.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _randombytes = require('randombytes'); - -var _randombytes2 = _interopRequireDefault(_randombytes); - -var _BitcoinCash = require('./BitcoinCash'); - -var _BitcoinCash2 = _interopRequireDefault(_BitcoinCash); - -var _bitcoincashjsLib = require('bitcoincashjs-lib'); - -var _bitcoincashjsLib2 = _interopRequireDefault(_bitcoincashjsLib); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var bc = new _BitcoinCash2.default(); - -var Crypto = function () { - function Crypto() { - _classCallCheck(this, Crypto); - } - - _createClass(Crypto, null, [{ - key: 'sha256', - - // Utility class to wrap NodeJS's crypto module - // https://nodejs.org/api/crypto.html - value: function sha256(buffer) { - return _bitcoincashjsLib2.default.crypto.sha256(buffer); - } - }, { - key: 'ripemd160', - value: function ripemd160(buffer) { - return _bitcoincashjsLib2.default.crypto.ripemd160(buffer); - } - }, { - key: 'hash256', - value: function hash256(buffer) { - return _bitcoincashjsLib2.default.crypto.hash256(buffer); - } - }, { - key: 'hash160', - value: function hash160(buffer) { - return _bitcoincashjsLib2.default.crypto.hash160(buffer); - } - }, { - key: 'randomBytes', - value: function randomBytes() { - var size = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 16; - - return (0, _randombytes2.default)(size); - } - }]); - - return Crypto; -}(); - -exports.default = Crypto; \ No newline at end of file diff --git a/lib/Crypto.ts b/lib/Crypto.ts new file mode 100644 index 00000000..8ce5235d --- /dev/null +++ b/lib/Crypto.ts @@ -0,0 +1,28 @@ +import randomBytes from "randombytes" +const Bitcoin = require("@bitcoin-dot-com/bitcoincashjs2-lib") + +export class Crypto { + public sha1(buffer: Buffer): Buffer { + return Bitcoin.crypto.sha1(buffer) + } + + public sha256(buffer: Buffer): Buffer { + return Bitcoin.crypto.sha256(buffer) + } + + public ripemd160(buffer: Buffer): Buffer { + return Bitcoin.crypto.ripemd160(buffer) + } + + public hash256(buffer: Buffer): Buffer { + return Bitcoin.crypto.hash256(buffer) + } + + public hash160(buffer: Buffer): Buffer { + return Bitcoin.crypto.hash160(buffer) + } + + public randomBytes(size: number = 16): Buffer { + return randomBytes(size) + } +} diff --git a/lib/ECPair.js b/lib/ECPair.js deleted file mode 100644 index 942e9577..00000000 --- a/lib/ECPair.js +++ /dev/null @@ -1,89 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _bitcoincashjsLib = require('bitcoincashjs-lib'); - -var _bitcoincashjsLib2 = _interopRequireDefault(_bitcoincashjsLib); - -var _bchaddrjs = require('bchaddrjs'); - -var _bchaddrjs2 = _interopRequireDefault(_bchaddrjs); - -var _coininfo = require('coininfo'); - -var _coininfo2 = _interopRequireDefault(_coininfo); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var ECPair = function () { - function ECPair() { - _classCallCheck(this, ECPair); - } - - _createClass(ECPair, null, [{ - key: 'fromWIF', - value: function fromWIF(privateKeyWIF) { - var network = void 0; - if (privateKeyWIF[0] === 'L' || privateKeyWIF[0] === 'K') { - network = 'bitcoincash'; - } else if (privateKeyWIF[0] === 'c') { - network = 'testnet'; - } - var bitcoincash = void 0; - if (network === 'bitcoincash') { - bitcoincash = _coininfo2.default.bitcoincash.main; - } else { - bitcoincash = _coininfo2.default.bitcoincash.test; - } - var bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS(); - - return _bitcoincashjsLib2.default.ECPair.fromWIF(privateKeyWIF, bitcoincashBitcoinJSLib); - } - }, { - key: 'toWIF', - value: function toWIF(ecpair) { - return ecpair.toWIF(); - } - }, { - key: 'sign', - value: function sign(ecpair, buffer) { - return ecpair.sign(buffer); - } - }, { - key: 'verify', - value: function verify(ecpair, buffer, signature) { - return ecpair.verify(buffer, signature); - } - }, { - key: 'fromPublicKey', - value: function fromPublicKey(pubkeyBuffer) { - return _bitcoincashjsLib2.default.ECPair.fromPublicKeyBuffer(pubkeyBuffer); - } - }, { - key: 'toPublicKey', - value: function toPublicKey(ecpair) { - return ecpair.getPublicKeyBuffer(); - } - }, { - key: 'toLegacyAddress', - value: function toLegacyAddress(ecpair) { - return ecpair.getAddress(); - } - }, { - key: 'toCashAddress', - value: function toCashAddress(ecpair) { - return _bchaddrjs2.default.toCashAddress(ecpair.getAddress()); - } - }]); - - return ECPair; -}(); - -exports.default = ECPair; \ No newline at end of file diff --git a/lib/ECPair.ts b/lib/ECPair.ts new file mode 100644 index 00000000..f342bb97 --- /dev/null +++ b/lib/ECPair.ts @@ -0,0 +1,63 @@ +import * as bcl from "bitcoincashjs-lib" +import { Address } from "./Address" + +const Bitcoin = require("@bitcoin-dot-com/bitcoincashjs2-lib") +const coininfo = require("coininfo") + +export class ECPair { + private _address: Address + constructor(address: Address = new Address()) { + this._address = address + } + + public fromWIF(privateKeyWIF: string): bcl.ECPair { + let network: string = "mainnet" + if (privateKeyWIF[0] === "L" || privateKeyWIF[0] === "K") + network = "mainnet" + else if (privateKeyWIF[0] === "c") network = "testnet" + + let bitcoincash: any + if (network === "mainnet") bitcoincash = coininfo.bitcoincash.main + else bitcoincash = coininfo.bitcoincash.test + + const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS() + + return Bitcoin.ECPair.fromWIF(privateKeyWIF, bitcoincashBitcoinJSLib) + } + + public toWIF(ecpair: bcl.ECPair): string { + return ecpair.toWIF() + } + + public sign( + ecpair: bcl.ECPair, + buffer: Buffer, + signatureAlgorithm?: number + ): bcl.ECSignature { + return ecpair.sign(buffer, signatureAlgorithm) + } + + public verify( + ecpair: bcl.ECPair, + buffer: Buffer, + signature: bcl.ECSignature + ): boolean { + return ecpair.verify(buffer, signature) + } + + public fromPublicKey(pubkeyBuffer: Buffer): bcl.ECPair { + return Bitcoin.ECPair.fromPublicKeyBuffer(pubkeyBuffer) + } + + public toPublicKey(ecpair: bcl.ECPair): Buffer { + return ecpair.getPublicKeyBuffer() + } + + public toLegacyAddress(ecpair: bcl.ECPair): string { + return ecpair.getAddress() + } + + public toCashAddress(ecpair: bcl.ECPair, regtest: boolean = false): string { + return this._address.toCashAddress(ecpair.getAddress(), true, regtest) + } +} diff --git a/lib/Generating.js b/lib/Generating.js deleted file mode 100644 index 02e4908f..00000000 --- a/lib/Generating.js +++ /dev/null @@ -1,51 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _axios = require('axios'); - -var _axios2 = _interopRequireDefault(_axios); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Generating = function () { - function Generating(restURL) { - _classCallCheck(this, Generating); - - this.restURL = restURL; - } - - _createClass(Generating, [{ - key: 'generateToAddress', - value: function generateToAddress(blocks, address) { - var maxtries = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1000000; - - - // Mine blocks immediately to a specified address (before the RPC call returns) - // - // Arguments: - // 1. nblocks (numeric, required) How many blocks are generated immediately. - // 2. address (string, required) The address to send the newly generated bitcoin to. - // 3. maxtries (numeric, optional) How many iterations to try (default = 1000000). - // - // Result: - // [ blockhashes ] (array) hashes of blocks generated - // - return _axios2.default.post(this.restURL + 'generating/generateToAddress/' + blocks + '/' + address + '?maxtries=' + maxtries).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }]); - - return Generating; -}(); - -exports.default = Generating; \ No newline at end of file diff --git a/lib/Generating.ts b/lib/Generating.ts new file mode 100644 index 00000000..9b4c4f9d --- /dev/null +++ b/lib/Generating.ts @@ -0,0 +1,27 @@ +import axios, { AxiosResponse } from "axios" +import { REST_URL } from "./BITBOX" + +export class Generating { + public restURL: string + constructor(restURL: string = REST_URL) { + this.restURL = restURL + } + + public async generateToAddress( + blocks: number, + address: string, + maxtries: number = 1000000 + ): Promise { + try { + const response: AxiosResponse = await axios.post( + `${ + this.restURL + }generating/generateToAddress/${blocks}/${address}?maxtries=${maxtries}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } +} diff --git a/lib/HDNode.js b/lib/HDNode.js deleted file mode 100644 index 5b926f57..00000000 --- a/lib/HDNode.js +++ /dev/null @@ -1,161 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _bitcoincashjsLib = require('bitcoincashjs-lib'); - -var _bitcoincashjsLib2 = _interopRequireDefault(_bitcoincashjsLib); - -var _bchaddrjs = require('bchaddrjs'); - -var _bchaddrjs2 = _interopRequireDefault(_bchaddrjs); - -var _coininfo = require('coininfo'); - -var _coininfo2 = _interopRequireDefault(_coininfo); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -// let bip32utils = require('bip32-utils') - -var HDNode = function () { - function HDNode() { - _classCallCheck(this, HDNode); - } - - _createClass(HDNode, [{ - key: 'fromSeed', - value: function fromSeed(rootSeedBuffer) { - var network = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'bitcoincash'; - - var bitcoincash = void 0; - if (network === 'bitcoincash') { - bitcoincash = _coininfo2.default.bitcoincash.main; - } else { - bitcoincash = _coininfo2.default.bitcoincash.test; - } - var bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS(); - return _bitcoincashjsLib2.default.HDNode.fromSeedBuffer(rootSeedBuffer, bitcoincashBitcoinJSLib); - } - }, { - key: 'toLegacyAddress', - value: function toLegacyAddress(hdNode) { - return hdNode.getAddress(); - } - }, { - key: 'toCashAddress', - value: function toCashAddress(hdNode) { - return _bchaddrjs2.default.toCashAddress(hdNode.getAddress()); - } - }, { - key: 'toWIF', - value: function toWIF(hdNode) { - return hdNode.keyPair.toWIF(); - } - }, { - key: 'toXPub', - value: function toXPub(hdNode) { - return hdNode.neutered().toBase58(); - } - }, { - key: 'toXPriv', - value: function toXPriv(hdNode) { - return hdNode.toBase58(); - } - }, { - key: 'toKeyPair', - value: function toKeyPair(hdNode) { - return hdNode.keyPair; - } - }, { - key: 'toPublicKey', - value: function toPublicKey(hdNode) { - return hdNode.getPublicKeyBuffer(); - } - }, { - key: 'fromXPriv', - value: function fromXPriv(xpriv) { - var bitcoincash = void 0; - if (xpriv[0] === 'x') { - bitcoincash = _coininfo2.default.bitcoincash.main; - } else if (xpriv[0] === 't') { - bitcoincash = _coininfo2.default.bitcoincash.test; - } - var bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS(); - return _bitcoincashjsLib2.default.HDNode.fromBase58(xpriv, bitcoincashBitcoinJSLib); - } - }, { - key: 'fromXPub', - value: function fromXPub(xpub) { - var bitcoincash = void 0; - if (xpub[0] === 'x') { - bitcoincash = _coininfo2.default.bitcoincash.main; - } else if (xpub[0] === 't') { - bitcoincash = _coininfo2.default.bitcoincash.test; - } - var bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS(); - return _bitcoincashjsLib2.default.HDNode.fromBase58(xpub, bitcoincashBitcoinJSLib); - } - }, { - key: 'derivePath', - value: function derivePath(hdnode, path) { - return hdnode.derivePath(path); - } - }, { - key: 'derive', - value: function derive(hdnode, path) { - return hdnode.derive(path); - } - }, { - key: 'deriveHardened', - value: function deriveHardened(hdnode, path) { - return hdnode.deriveHardened(path); - } - }, { - key: 'sign', - value: function sign(hdnode, buffer) { - return hdnode.sign(buffer); - } - }, { - key: 'verify', - value: function verify(hdnode, buffer, signature) { - return hdnode.verify(buffer, signature); - } - }, { - key: 'isPublic', - value: function isPublic(hdnode) { - return hdnode.isNeutered(); - } - }, { - key: 'isPrivate', - value: function isPrivate(hdnode) { - return !hdnode.isNeutered(); - } - }, { - key: 'toIdentifier', - value: function toIdentifier(hdnode) { - return hdnode.getIdentifier(); - } - }, { - key: 'fromBase58', - value: function fromBase58(base58, network) { - return _bitcoincashjsLib2.default.HDNode.fromBase58(base58, network); - } - - // - // createChain(hdNode) { - // return new bip32utils.Chain(hdNode); - // } - - }]); - - return HDNode; -}(); - -exports.default = HDNode; \ No newline at end of file diff --git a/lib/HDNode.ts b/lib/HDNode.ts new file mode 100644 index 00000000..636866fb --- /dev/null +++ b/lib/HDNode.ts @@ -0,0 +1,128 @@ +// imports +import * as bcl from "bitcoincashjs-lib" +import { Address } from "./Address" + +// consts +const Bitcoin = require("@bitcoin-dot-com/bitcoincashjs2-lib") +const coininfo = require("coininfo") +const bip32utils = require("bip32-utils") + +export class HDNode { + private _address: Address + constructor(address: Address = new Address()) { + this._address = address + } + + public fromSeed( + rootSeedBuffer: any, + network: string = "mainnet" + ): bcl.HDNode { + let bitcoincash: any + if (network === "bitcoincash" || network === "mainnet") + bitcoincash = coininfo.bitcoincash.main + else bitcoincash = coininfo.bitcoincash.test + + const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS() + return Bitcoin.HDNode.fromSeedBuffer( + rootSeedBuffer, + bitcoincashBitcoinJSLib + ) + } + + public toLegacyAddress(hdNode: bcl.HDNode): string { + return hdNode.getAddress() + } + + public toCashAddress(hdNode: bcl.HDNode, regtest: boolean = false): string { + return this._address.toCashAddress(hdNode.getAddress(), true, regtest) + } + + public toWIF(hdNode: bcl.HDNode): string { + return hdNode.keyPair.toWIF() + } + + public toXPub(hdNode: bcl.HDNode): string { + return hdNode.neutered().toBase58() + } + + public toXPriv(hdNode: bcl.HDNode): string { + return hdNode.toBase58() + } + + public toKeyPair(hdNode: bcl.HDNode): bcl.ECPair { + return hdNode.keyPair + } + + public toPublicKey(hdNode: bcl.HDNode): Buffer { + return hdNode.getPublicKeyBuffer() + } + + public fromXPriv(xpriv: string): bcl.HDNode { + let bitcoincash: any + if (xpriv[0] === "x") bitcoincash = coininfo.bitcoincash.main + else if (xpriv[0] === "t") bitcoincash = coininfo.bitcoincash.test + + const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS() + return Bitcoin.HDNode.fromBase58(xpriv, bitcoincashBitcoinJSLib) + } + + public fromXPub(xpub: string): bcl.HDNode { + let bitcoincash: any + if (xpub[0] === "x") bitcoincash = coininfo.bitcoincash.main + else if (xpub[0] === "t") bitcoincash = coininfo.bitcoincash.test + + const bitcoincashBitcoinJSLib: any = bitcoincash.toBitcoinJS() + return Bitcoin.HDNode.fromBase58(xpub, bitcoincashBitcoinJSLib) + } + + public derivePath(hdnode: bcl.HDNode, path: string): bcl.HDNode { + return hdnode.derivePath(path) + } + + public derive(hdnode: bcl.HDNode, path: number): bcl.HDNode { + return hdnode.derive(path) + } + + public deriveHardened(hdnode: bcl.HDNode, path: number): bcl.HDNode { + return hdnode.deriveHardened(path) + } + + public sign(hdnode: bcl.HDNode, buffer: Buffer): bcl.ECSignature { + return hdnode.sign(buffer) + } + + public verify( + hdnode: bcl.HDNode, + buffer: Buffer, + signature: bcl.ECSignature + ): boolean { + return hdnode.verify(buffer, signature) + } + + public isPublic(hdnode: bcl.HDNode): boolean { + return JSON.parse(hdnode.isNeutered()) + } + + public isPrivate(hdnode: bcl.HDNode): boolean { + return !hdnode.isNeutered() + } + + public toIdentifier(hdnode: bcl.HDNode): Buffer { + return hdnode.getIdentifier() + } + + public fromBase58(base58: string, network: string): string { + return Bitcoin.HDNode.fromBase58(base58, network) + } + + public createAccount(hdNodes: bcl.HDNode[]): object { + const arr: any = hdNodes.map( + (item: any, index: number) => new bip32utils.Chain(item.neutered()) + ) + return new bip32utils.Account(arr) + } + + public createChain(hdNode: bcl.HDNode): object { + return new bip32utils.Chain(hdNode) + } +} diff --git a/lib/Mining.js b/lib/Mining.js deleted file mode 100644 index 8f2d5d90..00000000 --- a/lib/Mining.js +++ /dev/null @@ -1,129 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _axios = require('axios'); - -var _axios2 = _interopRequireDefault(_axios); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Mining = function () { - function Mining(restURL) { - _classCallCheck(this, Mining); - - this.restURL = restURL; - } - - _createClass(Mining, [{ - key: 'getBlockTemplate', - value: function getBlockTemplate(template_request) { - - // If the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'. - // It returns data needed to construct a block to work on. - // For full specification, see BIPs 22, 23, 9, and 145: - // https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki - // https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki - // https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes - // https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki - // - // Arguments: - // 1. template_request (json object, optional) A json object in the following spec - // { - // "mode":"template" (string, optional) This must be set to "template", "proposal" (see BIP 23), or omitted - // "capabilities":[ (array, optional) A list of strings - // "support" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid' - // ,... - // ], - // "rules":[ (array, optional) A list of strings - // "support" (string) client side supported softfork deployment - // ,... - // ] - // } - - return _axios2.default.get(this.restURL + 'mining/getBlockTemplate/' + template_request).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.message); - }); - } - }, { - key: 'getMiningInfo', - value: function getMiningInfo() { - // Returns a json object containing mining-related information. - // Result: - // { - // "blocks": nnn, (numeric) The current block - // "currentblocksize": nnn, (numeric) The last block size - // "currentblocktx": nnn, (numeric) The last block transaction - // "difficulty": xxx.xxxxx (numeric) The current difficulty - // "errors": "..." (string) Current errors - // "networkhashps": nnn, (numeric) The network hashes per second - // "pooledtx": n (numeric) The size of the mempool - // "chain": "xxxx", (string) current network name as defined in BIP70 (main, test, regtest) - // } - - return _axios2.default.get(this.restURL + 'mining/getMiningInfo').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getNetworkHashps', - value: function getNetworkHashps() { - var nblocks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 120; - var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; - - // Returns the estimated network hashes per second based on the last n blocks. - // Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change. - // Pass in [height] to estimate the network speed at the time when a certain block was found. - // - // Arguments: - // 1. nblocks (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change. - // 2. height (numeric, optional, default=-1) To estimate at the time of the given height. - // - // Result: - // x (numeric) Hashes per second estimated - return _axios2.default.get(this.restURL + 'mining/getNetworkHashps?nblocks=' + nblocks + '&height=' + height).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'submitBlock', - value: function submitBlock(hex, parameters) { - // Attempts to submit new block to network. - // The 'jsonparametersobject' parameter is currently ignored. - // See https://en.bitcoin.it/wiki/BIP_0022 for full specification. - // - // Arguments - // 1. "hex" (string, required) the hex-encoded block data to submit - // 2. "parameters" (string, optional) object of optional parameters - // { - // "workid" : "id" (string, optional) if the server provided a workid, it MUST be included with submissions - // } - // - var path = this.restURL + 'mining/submitBlock/' + hex; - if (parameters) { - path = path + '?parameters=' + parameters; - } - return _axios2.default.post(path).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }]); - - return Mining; -}(); - -exports.default = Mining; \ No newline at end of file diff --git a/lib/Mining.ts b/lib/Mining.ts new file mode 100644 index 00000000..7c68d49e --- /dev/null +++ b/lib/Mining.ts @@ -0,0 +1,63 @@ +import axios, { AxiosResponse } from "axios" +import { REST_URL } from "./BITBOX" + +export class Mining { + public restURL: string + constructor(restURL: string = REST_URL) { + this.restURL = restURL + } + + public async getBlockTemplate(template_request: any): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}mining/getBlockTemplate/${template_request}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getMiningInfo(): Promise { + try { + const response: AxiosResponse = await axios.get( + `${this.restURL}mining/getMiningInfo` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getNetworkHashps( + nblocks: number = 120, + height: number = 1 + ): Promise { + try { + const response: AxiosResponse = await axios.get( + `${ + this.restURL + }mining/getNetworkHashps?nblocks=${nblocks}&height=${height}` + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async submitBlock(hex: string, parameters: any): Promise { + let path: string = `${this.restURL}mining/submitBlock/${hex}` + if (parameters) path = `${path}?parameters=${parameters}` + + try { + const response: AxiosResponse = await axios.post(path) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } +} diff --git a/lib/Mnemonic.js b/lib/Mnemonic.js deleted file mode 100644 index f6848409..00000000 --- a/lib/Mnemonic.js +++ /dev/null @@ -1,338 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _Crypto = require('./Crypto'); - -var _Crypto2 = _interopRequireDefault(_Crypto); - -var _bip = require('bip39'); - -var _bip2 = _interopRequireDefault(_bip); - -var _randombytes = require('randombytes'); - -var _randombytes2 = _interopRequireDefault(_randombytes); - -var _bitcoincashjsLib = require('bitcoincashjs-lib'); - -var _bitcoincashjsLib2 = _interopRequireDefault(_bitcoincashjsLib); - -var _bchaddrjs = require('bchaddrjs'); - -var _bchaddrjs2 = _interopRequireDefault(_bchaddrjs); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Buffer = require('safe-buffer').Buffer; - -var Mnemonic = function () { - function Mnemonic() { - _classCallCheck(this, Mnemonic); - } - - _createClass(Mnemonic, [{ - key: 'generate', - value: function generate() { - var bits = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 128; - var wordlist = arguments[1]; - - return _bip2.default.generateMnemonic(bits, _randombytes2.default, wordlist); - } - }, { - key: 'fromEntropy', - value: function fromEntropy(bytes, wordlist) { - return _bip2.default.entropyToMnemonic(bytes, wordlist); - } - }, { - key: 'toEntropy', - value: function toEntropy(mnemonic, wordlist) { - return Buffer.from(_bip2.default.mnemonicToEntropy(mnemonic, wordlist), 'hex'); - } - }, { - key: 'validate', - value: function validate(mnemonic, wordlist) { - // Preprocess the words - var words = mnemonic.split(' '); - // Detect blank phrase - if (words.length == 0) { - return "Blank mnemonic"; - } - // Check each word - for (var i = 0; i < words.length; i++) { - var word = words[i]; - if (wordlist.indexOf(word) == -1) { - // Finding closest match to word - var nearestWord = this.findNearestWord(word, wordlist); - return word + ' is not in wordlist, did you mean ' + nearestWord + '?'; - } - } - // Check the words are valid - var properPhrase = words.join(); - var isValid = _bip2.default.validateMnemonic(mnemonic, wordlist); - if (!isValid) { - return "Invalid mnemonic"; - } else { - return 'Valid mnemonic'; - } - } - }, { - key: 'toSeed', - value: function toSeed(mnemonic) { - var password = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; - - return _bip2.default.mnemonicToSeed(mnemonic, password); - } - }, { - key: 'wordLists', - value: function wordLists() { - return _bip2.default.wordlists; - } - }, { - key: 'toKeypairs', - value: function toKeypairs(mnemonic) { - var numberOfKeypairs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; - - var rootSeedBuffer = this.toSeed(mnemonic, ''); - var hdNode = _bitcoincashjsLib2.default.HDNode.fromSeedBuffer(rootSeedBuffer); - var HDPath = '44\'/145\'/0\'/0/'; - - var accounts = []; - - for (var i = 0; i < numberOfKeypairs; i++) { - var childHDNode = hdNode.derivePath('' + HDPath + i); - accounts.push({ - privateKeyWIF: childHDNode.keyPair.toWIF(), - address: _bchaddrjs2.default.toCashAddress(childHDNode.getAddress()) - }); - }; - return accounts; - } - }, { - key: 'findNearestWord', - value: function findNearestWord(word, wordlist) { - var minDistance = 99; - var closestWord = wordlist[0]; - for (var i = 0; i < wordlist.length; i++) { - var comparedTo = wordlist[i]; - if (comparedTo.indexOf(word) == 0) { - return comparedTo; - } - var distance = Levenshtein.get(word, comparedTo); - if (distance < minDistance) { - closestWord = comparedTo; - minDistance = distance; - } - } - return closestWord; - } - }]); - - return Mnemonic; -}(); - -exports.default = Mnemonic; - -// The following code is from: https://raw.githubusercontent.com/iancoleman/bip39/7ff86d4c983f1e8c80b87b31acfd69fcf98c1b82/src/js/levenshtein.js - -/** - * Extend an Object with another Object's properties. - * - * The source objects are specified as additional arguments. - * - * @param dst Object the object to extend. - * - * @return Object the final object. - */ - -var _extend = function _extend(dst) { - var sources = Array.prototype.slice.call(arguments, 1); - for (var i = 0; i < sources.length; ++i) { - var src = sources[i]; - for (var p in src) { - if (src.hasOwnProperty(p)) dst[p] = src[p]; - } - } - return dst; -}; - -/** - * Defer execution of given function. - * @param {Function} func - */ -var _defer = function _defer(func) { - if (typeof setImmediate === 'function') { - return setImmediate(func); - } else { - return setTimeout(func, 0); - } -}; - -/** -* Based on the algorithm at http://en.wikipedia.org/wiki/Levenshtein_distance. -*/ -var Levenshtein = { - /** - * Calculate levenshtein distance of the two strings. - * - * @param str1 String the first string. - * @param str2 String the second string. - * @return Integer the levenshtein distance (0 and above). - */ - get: function get(str1, str2) { - // base cases - if (str1 === str2) return 0; - if (str1.length === 0) return str2.length; - if (str2.length === 0) return str1.length; - - // two rows - var prevRow = new Array(str2.length + 1), - curCol, - nextCol, - i, - j, - tmp; - - // initialise previous row - for (i = 0; i < prevRow.length; ++i) { - prevRow[i] = i; - } - - // calculate current row distance from previous row - for (i = 0; i < str1.length; ++i) { - nextCol = i + 1; - - for (j = 0; j < str2.length; ++j) { - curCol = nextCol; - - // substution - nextCol = prevRow[j] + (str1.charAt(i) === str2.charAt(j) ? 0 : 1); - // insertion - tmp = curCol + 1; - if (nextCol > tmp) { - nextCol = tmp; - } - // deletion - tmp = prevRow[j + 1] + 1; - if (nextCol > tmp) { - nextCol = tmp; - } - - // copy current col value into previous (in preparation for next iteration) - prevRow[j] = curCol; - } - - // copy last col value into previous (in preparation for next iteration) - prevRow[j] = nextCol; - } - - return nextCol; - }, - - /** - * Asynchronously calculate levenshtein distance of the two strings. - * - * @param str1 String the first string. - * @param str2 String the second string. - * @param cb Function callback function with signature: function(Error err, int distance) - * @param [options] Object additional options. - * @param [options.progress] Function progress callback with signature: function(percentComplete) - */ - getAsync: function getAsync(str1, str2, cb, options) { - options = _extend({}, { - progress: null - }, options); - - // base cases - if (str1 === str2) return cb(null, 0); - if (str1.length === 0) return cb(null, str2.length); - if (str2.length === 0) return cb(null, str1.length); - - // two rows - var prevRow = new Array(str2.length + 1), - curCol, - nextCol, - i, - j, - tmp, - startTime, - currentTime; - - // initialise previous row - for (i = 0; i < prevRow.length; ++i) { - prevRow[i] = i; - } - - nextCol = 1; - i = 0; - j = -1; - - var __calculate = function __calculate() { - // reset timer - startTime = new Date().valueOf(); - currentTime = startTime; - - // keep going until one second has elapsed - while (currentTime - startTime < 1000) { - // reached end of current row? - if (str2.length <= ++j) { - // copy current into previous (in preparation for next iteration) - prevRow[j] = nextCol; - - // if already done all chars - if (str1.length <= ++i) { - return cb(null, nextCol); - } - // else if we have more left to do - else { - nextCol = i + 1; - j = 0; - } - } - - // calculation - curCol = nextCol; - - // substution - nextCol = prevRow[j] + (str1.charAt(i) === str2.charAt(j) ? 0 : 1); - // insertion - tmp = curCol + 1; - if (nextCol > tmp) { - nextCol = tmp; - } - // deletion - tmp = prevRow[j + 1] + 1; - if (nextCol > tmp) { - nextCol = tmp; - } - - // copy current into previous (in preparation for next iteration) - prevRow[j] = curCol; - - // get current time - currentTime = new Date().valueOf(); - } - - // send a progress update? - if (null !== options.progress) { - try { - options.progress.call(null, i * 100.0 / str1.length); - } catch (err) { - return cb('Progress callback: ' + err.toString()); - } - } - - // next iteration - _defer(__calculate); - }; - - __calculate(); - } - -}; \ No newline at end of file diff --git a/lib/Mnemonic.ts b/lib/Mnemonic.ts new file mode 100644 index 00000000..c98b5dc8 --- /dev/null +++ b/lib/Mnemonic.ts @@ -0,0 +1,304 @@ +import * as BIP39 from "bip39" +import * as bcl from "bitcoincashjs-lib" +// import * as Bitcoin from "bitcoincashjs-lib" +import { Buffer } from "buffer" +import randomBytes from "randombytes" +import * as wif from "wif" +import { Address } from "./Address" +// TODO: convert "bitcoincashjs-lib" require to import +const Bitcoin = require("@bitcoin-dot-com/bitcoincashjs2-lib") + +export class Mnemonic { + private _address: Address + constructor(address: Address = new Address()) { + this._address = address + } + + public generate( + bits: number = 128, + wordlist: string[] = this.wordLists().english + ): string { + return BIP39.generateMnemonic(bits, randomBytes, wordlist) + } + + public fromEntropy( + bytes: Buffer, + wordlist: string[] = this.wordLists().english + ): string { + return BIP39.entropyToMnemonic(bytes, wordlist) + } + + public toEntropy( + mnemonic: string, + wordlist: string[] = this.wordLists().english + ): Buffer { + return Buffer.from(BIP39.mnemonicToEntropy(mnemonic, wordlist), "hex") + } + + public validate( + mnemonic: string, + wordlist: string[] = this.wordLists().english + ): string { + // Preprocess the words + const words = mnemonic.split(" ") + // Detect blank phrase + if (words.length === 0) return "Blank mnemonic" + + // Check each word + for (let i = 0; i < words.length; i++) { + const word = words[i] + if (wordlist.indexOf(word) == -1) { + // Finding closest match to word + const nearestWord = this.findNearestWord(word, wordlist) + return `${word} is not in wordlist, did you mean ${nearestWord}?` + } + } + // Check the words are valid + const isValid = BIP39.validateMnemonic(mnemonic, wordlist) + if (!isValid) return "Invalid mnemonic" + + return "Valid mnemonic" + } + + public toSeed(mnemonic: string, password: string = ""): Buffer { + return BIP39.mnemonicToSeed(mnemonic, password) + } + + public wordLists(): any { + return BIP39.wordlists + } + + public toKeypairs( + mnemonic: string, + numberOfKeypairs: number = 1, + regtest: boolean = false + ): any { + const rootSeedBuffer: Buffer = this.toSeed(mnemonic, "") + const hdNode: bcl.HDNode = Bitcoin.HDNode.fromSeedBuffer(rootSeedBuffer) + const HDPath: string = `44'/145'/0'/0/` + + const accounts: any[] = [] + + for (let i = 0; i < numberOfKeypairs; i++) { + const childHDNode: bcl.HDNode = hdNode.derivePath(`${HDPath}${i}`) + + let prefix: number = 128 + if (regtest === true) prefix = 239 + + accounts.push({ + privateKeyWIF: wif.encode( + prefix, + childHDNode.keyPair.d.toBuffer(32), + true + ), + address: this._address.toCashAddress( + childHDNode.getAddress(), + true, + regtest + ) + }) + } + return accounts + } + + public findNearestWord(word: string, wordlist: string[]): string { + let minDistance: number = 99 + let closestWord: string = wordlist[0] + for (let i: number = 0; i < wordlist.length; i++) { + const comparedTo: string = wordlist[i] + if (comparedTo.indexOf(word) == 0) return comparedTo + + const distance: number = Levenshtein.get(word, comparedTo) + if (distance < minDistance) { + closestWord = comparedTo + minDistance = distance + } + } + return closestWord + } +} + +// The following code is from: https://raw.githubusercontent.com/iancoleman/bip39/7ff86d4c983f1e8c80b87b31acfd69fcf98c1b82/src/js/levenshtein.js + +/** + * Extend an Object with another Object's properties. + * + * The source objects are specified as additional arguments. + * + * @param dst Object the object to extend. + * + * @return Object the final object. + */ + +const _extend: any = function(dst: any): any { + const sources: any = Array.prototype.slice.call(arguments, 1) + for (let i: number = 0; i < sources.length; ++i) { + const src = sources[i] + for (const p in src) if (src.hasOwnProperty(p)) dst[p] = src[p] + } + return dst +} + +/** + * Defer execution of given function. + * @param {Function} func + */ +const _defer: any = function(func: any): any { + if (typeof setImmediate === "function") return setImmediate(func) + + return setTimeout(func, 0) +} + +/** + * Based on the algorithm at http://en.wikipedia.org/wiki/Levenshtein_distance. + */ +var Levenshtein: any = { + /** + * Calculate levenshtein distance of the two strings. + * + * @param str1 String the first string. + * @param str2 String the second string. + * @return Integer the levenshtein distance (0 and above). + */ + get: function(str1: any, str2: any) { + // base cases + if (str1 === str2) return 0 + if (str1.length === 0) return str2.length + if (str2.length === 0) return str1.length + + // two rows + let prevRow: any[] = new Array(str2.length + 1), + curCol, + nextCol, + i, + j, + tmp + + // initialise previous row + for (i = 0; i < prevRow.length; ++i) prevRow[i] = i + + // calculate current row distance from previous row + for (i = 0; i < str1.length; ++i) { + nextCol = i + 1 + + for (j = 0; j < str2.length; ++j) { + curCol = nextCol + + // substution + nextCol = prevRow[j] + (str1.charAt(i) === str2.charAt(j) ? 0 : 1) + // insertion + tmp = curCol + 1 + if (nextCol > tmp) nextCol = tmp + + // deletion + tmp = prevRow[j + 1] + 1 + if (nextCol > tmp) nextCol = tmp + + // copy current col value into previous (in preparation for next iteration) + prevRow[j] = curCol + } + + // copy last col value into previous (in preparation for next iteration) + prevRow[j] = nextCol + } + + return nextCol + }, + + /** + * Asynchronously calculate levenshtein distance of the two strings. + * + * @param str1 String the first string. + * @param str2 String the second string. + * @param cb Function callback function with signature: function(Error err, int distance) + * @param [options] Object additional options. + * @param [options.progress] Function progress callback with signature: function(percentComplete) + */ + getAsync: function(str1: any, str2: any, cb: any, options: any) { + options = _extend( + {}, + { + progress: null + }, + options + ) + + // base cases + if (str1 === str2) return cb(null, 0) + if (str1.length === 0) return cb(null, str2.length) + if (str2.length === 0) return cb(null, str1.length) + + // two rows + const prevRow: any[] = new Array(str2.length + 1) + let curCol: any + let nextCol: any + let i: any + let j: any + let tmp: any + let startTime: any + let currentTime: any + + // initialise previous row + for (i = 0; i < prevRow.length; ++i) prevRow[i] = i + + nextCol = 1 + i = 0 + j = -1 + + var __calculate = function() { + // reset timer + startTime = new Date().valueOf() + currentTime = startTime + + // keep going until one second has elapsed + while (currentTime - startTime < 1000) { + // reached end of current row? + if (str2.length <= ++j) { + // copy current into previous (in preparation for next iteration) + prevRow[j] = nextCol + + // if already done all chars + if (str1.length <= ++i) return cb(null, nextCol) + + // else if we have more left to do + + nextCol = i + 1 + j = 0 + } + + // calculation + curCol = nextCol + + // substution + nextCol = prevRow[j] + (str1.charAt(i) === str2.charAt(j) ? 0 : 1) + // insertion + tmp = curCol + 1 + if (nextCol > tmp) nextCol = tmp + + // deletion + tmp = prevRow[j + 1] + 1 + if (nextCol > tmp) nextCol = tmp + + // copy current into previous (in preparation for next iteration) + prevRow[j] = curCol + + // get current time + currentTime = new Date().valueOf() + } + + // send a progress update? + if (null !== options.progress) { + try { + options.progress.call(null, (i * 100.0) / str1.length) + } catch (err) { + return cb(`Progress callback: ${err.toString()}`) + } + } + + // next iteration + _defer(__calculate) + } + + __calculate() + } +} diff --git a/lib/Network.js b/lib/Network.js deleted file mode 100644 index b831261f..00000000 --- a/lib/Network.js +++ /dev/null @@ -1,313 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _axios = require('axios'); - -var _axios2 = _interopRequireDefault(_axios); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Network = function () { - function Network(restURL) { - _classCallCheck(this, Network); - - this.restURL = restURL; - } - - _createClass(Network, [{ - key: 'addNode', - value: function addNode(node, command) { - // Attempts add or remove a node from the addnode list. - // Or try a connection to a node once. - // - // Arguments: - // 1. "node" (string, required) The node (see getpeerinfo for nodes) - // 2. "command" (string, required) 'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once - // - - return _axios2.default.post(this.restURL + 'network/addNode/' + node + '/' + command).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'clearBanned', - value: function clearBanned() { - //The clearbanned RPC clears list of banned nodes. - - // Parameters: none - - // Result—null on success - // JSON null when the list was cleared - - return _axios2.default.post(this.restURL + 'clearBanned').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'disconnectNode', - value: function disconnectNode(configuration) { - // Immediately disconnects from the specified peer node. - // - // Strictly one out of 'configuration.address' and 'configuration.nodeid' can be provided to identify the node. - // - // To disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only. - // - // Arguments: - // 1. "configuration" (object, optional) - // Properties - // 1. "address" (string, optional) The IP address/port of the node - // 2. "nodeid" (number, optional) The node ID (see getpeerinfo for node IDs) - return _axios2.default.post(this.restURL + 'disconnectNode/' + configuration).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getAddedNodeInfo', - value: function getAddedNodeInfo(node) { - // Returns information about the given added node, or all added nodes - // (note that onetry addnodes are not listed here) - // - // Arguments: - // 1. "node" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned. - // - // Result: - // [ - // { - // "addednode" : "192.168.0.201", (string) The node ip address or name (as provided to addnode) - // "connected" : true|false, (boolean) If connected - // "addresses" : [ (list of objects) Only when connected = true - // { - // "address" : "192.168.0.201:8333", (string) The bitcoin server IP and port we're connected to - // "connected" : "outbound" (string) connection, inbound or outbound - // } - // ] - // } - // ,... - // ] - var path = this.restURL + 'network/getAddedNodeInfo'; - if (node) { - path = path + '?node=' + node; - } - - return _axios2.default.get(path).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getConnectionCount', - value: function getConnectionCount() { - // Returns the number of connections to other nodes. - // - // Result: - // n (numeric) The connection count - - return _axios2.default.get(this.restURL + 'network/getConnectionCount').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getNetTotals', - value: function getNetTotals() { - // Returns information about network traffic, including bytes in, bytes out, and current time. - // - // Result: - // { - // "totalbytesrecv": n, (numeric) Total bytes received - // "totalbytessent": n, (numeric) Total bytes sent - // "timemillis": t, (numeric) Current UNIX time in milliseconds - // "uploadtarget": - // { - // "timeframe": n, (numeric) Length of the measuring timeframe in seconds - // "target": n, (numeric) Target in bytes - // "target_reached": true|false, (boolean) True if target is reached - // "serve_historical_blocks": true|false, (boolean) True if serving historical blocks - // "bytes_left_in_cycle": t, (numeric) Bytes left in current time cycle - // "time_left_in_cycle": t (numeric) Seconds left in current time cycle - // } - // } - - return _axios2.default.get(this.restURL + 'network/getNetTotals').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getNetworkInfo', - value: function getNetworkInfo() { - // Returns an object containing various state info regarding P2P networking. - // - // Result: - // { - // "version": xxxxx, (numeric) the server version - // "subversion": "/Satoshi:x.x.x/", (string) the server subversion string - // "protocolversion": xxxxx, (numeric) the protocol version - // "localservices": "xxxxxxxxxxxxxxxx", (string) the services we offer to the network - // "localrelay": true|false, (bool) true if transaction relay is requested from peers - // "timeoffset": xxxxx, (numeric) the time offset - // "connections": xxxxx, (numeric) the number of connections - // "networkactive": true|false, (bool) whether p2p networking is enabled - // "networks": [ (array) information per network - // { - // "name": "xxx", (string) network (ipv4, ipv6 or onion) - // "limited": true|false, (boolean) is the network limited using -onlynet? - // "reachable": true|false, (boolean) is the network reachable? - // "proxy": "host:port" (string) the proxy that is used for this network, or empty if none - // "proxy_randomize_credentials": true|false, (string) Whether randomized credentials are used - // } - // ,... - // ], - // "relayfee": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in BCH/kB - // "incrementalfee": x.xxxxxxxx, (numeric) minimum fee increment for mempool limiting or BIP 125 replacement in BCH/kB - // "localaddresses": [ (array) list of local addresses - // { - // "address": "xxxx", (string) network address - // "port": xxx, (numeric) network port - // "score": xxx (numeric) relative score - // } - // ,... - // ] - // "warnings": "..." (string) any network warnings - // } - - return _axios2.default.get(this.restURL + 'network/getNetworkInfo').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getPeerInfo', - value: function getPeerInfo() { - // Returns data about each connected network node as a json array of objects. - // - // Result: - // [ - // { - // "id": n, (numeric) Peer index - // "addr":"host:port", (string) The ip address and port of the peer - // "addrlocal":"ip:port", (string) local address - // "services":"xxxxxxxxxxxxxxxx", (string) The services offered - // "relaytxes":true|false, (boolean) Whether peer has asked us to relay transactions to it - // "lastsend": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send - // "lastrecv": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive - // "bytessent": n, (numeric) The total bytes sent - // "bytesrecv": n, (numeric) The total bytes received - // "conntime": ttt, (numeric) The connection time in seconds since epoch (Jan 1 1970 GMT) - // "timeoffset": ttt, (numeric) The time offset in seconds - // "pingtime": n, (numeric) ping time (if available) - // "minping": n, (numeric) minimum observed ping time (if any at all) - // "pingwait": n, (numeric) ping wait (if non-zero) - // "version": v, (numeric) The peer version, such as 7001 - // "subver": "/Satoshi:0.8.5/", (string) The string version - // "inbound": true|false, (boolean) Inbound (true) or Outbound (false) - // "addnode": true|false, (boolean) Whether connection was due to addnode and is using an addnode slot - // "startingheight": n, (numeric) The starting height (block) of the peer - // "banscore": n, (numeric) The ban score - // "synced_headers": n, (numeric) The last header we have in common with this peer - // "synced_blocks": n, (numeric) The last block we have in common with this peer - // "inflight": [ - // n, (numeric) The heights of blocks we're currently asking from this peer - // ... - // ], - // "whitelisted": true|false, (boolean) Whether the peer is whitelisted - // "bytessent_per_msg": { - // "addr": n, (numeric) The total bytes sent aggregated by message type - // ... - // }, - // "bytesrecv_per_msg": { - // "addr": n, (numeric) The total bytes received aggregated by message type - // ... - // } - // } - // ,... - // ] - - return _axios2.default.get(this.restURL + 'network/getPeerInfo').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - // - // listBanned() { - // // List all banned IPs/Subnets. - // return axios.get(`${this.restURL}network/listBanned`) - // .then((response) => { - // return response.data; - // }) - // .catch((error) => { - // return JSON.stringify(error.response.data.error.message); - // }); - // } - - }, { - key: 'ping', - value: function ping() { - // Requests that a ping be sent to all other nodes, to measure ping time. - // Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds. - // Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping. - - return _axios2.default.get(this.restURL + 'network/ping').then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - // - // setBan(subnet, command, bantime, absolute) { - // // Attempts add or remove a IP/Subnet from the banned list. - // // - // // Arguments: - // // 1. "subnet" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip) - // // 2. "command" (string, required) 'add' to add a IP/Subnet to the list, 'remove' to remove a IP/Subnet from the list - // // 3. "bantime" (numeric, optional) time in seconds how long (or until when if [absolute] is set) the ip is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument) - // // 4. "absolute" (boolean, optional) If set, the bantime must be a absolute timestamp in seconds since epoch (Jan 1 1970 GMT) - // - // return axios.post(`${this.baseurl}network/setban/${subnet}/${command}`) - // .then((response) => { - // return response.data; - // }) - // .catch((error) => { - // return JSON.stringify(error.response.data.error.message); - // }); - // } - // - // setNetworkActive(state) { - // // Disable/enable all p2p network activity. - // // - // // Arguments: - // // 1. "state" (boolean, required) true to enable networking, false to disable - // - // return axios.post(`${this.baseurl}network/setNetworkActive/${state}`) - // .then((response) => { - // return response.data; - // }) - // .catch((error) => { - // return JSON.stringify(error.response.data.error.message); - // }); - // } - - }]); - - return Network; -}(); - -exports.default = Network; \ No newline at end of file diff --git a/lib/Price.ts b/lib/Price.ts new file mode 100644 index 00000000..8dd0530b --- /dev/null +++ b/lib/Price.ts @@ -0,0 +1,15 @@ +import axios, { AxiosResponse } from "axios" + +export class Price { + public async current(currency: string = "usd"): Promise { + try { + const response: AxiosResponse = await axios.get( + `https://index-api.bitcoin.com/api/v0/cash/price/${currency.toLowerCase()}` + ) + return response.data.price + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } +} diff --git a/lib/RawTransactions.js b/lib/RawTransactions.js deleted file mode 100644 index 2786dbc5..00000000 --- a/lib/RawTransactions.js +++ /dev/null @@ -1,110 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _axios = require('axios'); - -var _axios2 = _interopRequireDefault(_axios); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var RawTransactions = function () { - function RawTransactions(restURL) { - _classCallCheck(this, RawTransactions); - - this.restURL = restURL; - } - - _createClass(RawTransactions, [{ - key: 'decodeRawTransaction', - value: function decodeRawTransaction(hex) { - // decodes a serialized transaction hex string into a JSON object describing the transaction. - - // Parameter #1—serialized transaction in hex - - // Result—the decoded transaction - - return _axios2.default.get(this.restURL + 'rawtransactions/decodeRawTransaction/' + hex).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'decodeScript', - value: function decodeScript(hex) { - // decodes a hex-encoded P2SH redeem script. - - // Parameter #1—a hex-encoded redeem script - - // Result—the decoded script - // console.log('decode script called *****', redeemScript) - - return _axios2.default.get(this.restURL + 'rawtransactions/decodeScript/' + hex).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'getRawTransaction', - value: function getRawTransaction(txid) { - var verbose = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; - - // NOTE: By default this function only works for mempool transactions. If the -txindex option is - // enabled, it also works for blockchain transactions. - // DEPRECATED: for now, it also works for transactions with unspent outputs. - // - // Return the raw transaction data. - // - // If verbose is 'true', returns an Object with information about 'txid'. - // If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'. - // - // Arguments: - // 1. "txid" (string, required) The transaction id - // 2. verbose (bool, optional, default=false) If false, return a string, otherwise return a json object - // - // Result (if verbose is not set or set to false): - // "data" (string) The serialized, hex-encoded data for 'txid' - - return _axios2.default.get(this.restURL + 'rawtransactions/getRawTransaction/' + txid + '?verbose=' + verbose).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }, { - key: 'sendRawTransaction', - value: function sendRawTransaction(hex) { - var allowhighfees = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; - - // Submits raw transaction (serialized, hex-encoded) to local node and network. - // - // Also see createrawtransaction and signrawtransaction calls. - // - // Arguments: - // 1. "hexstring" (string, required) The hex string of the raw transaction) - // 2. allowhighfees (boolean, optional, default=false) Allow high fees - // - // Result: - // "hex" (string) The transaction hash in hex - // - - return _axios2.default.post(this.restURL + 'rawtransactions/sendRawTransaction/' + hex + '?allowhighfees=' + allowhighfees).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }]); - - return RawTransactions; -}(); - -exports.default = RawTransactions; \ No newline at end of file diff --git a/lib/RawTransactions.ts b/lib/RawTransactions.ts new file mode 100644 index 00000000..b339d3be --- /dev/null +++ b/lib/RawTransactions.ts @@ -0,0 +1,151 @@ +import axios, { AxiosRequestConfig, AxiosResponse } from "axios" +import { VerboseRawTransactionResult } from "bitcoin-com-rest" +import { REST_URL } from "./BITBOX" + +export class RawTransactions { + public restURL: string + constructor(restURL: string = REST_URL) { + this.restURL = restURL + } + + public async decodeRawTransaction( + hex: string | string[] + ): Promise { + try { + // Single hex + if (typeof hex === "string") { + const response: AxiosResponse = await axios.get( + `${this.restURL}rawtransactions/decodeRawTransaction/${hex}` + ) + + return response.data + + // Array of hexes + } else if (Array.isArray(hex)) { + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}rawtransactions/decodeRawTransaction`, + { + hexes: hex + } + ) + + return response.data + } + + throw new Error(`Input must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async decodeScript(script: string | string[]): Promise { + //if (typeof script !== "string") script = JSON.stringify(script) + + try { + if (typeof script === "string") { + const response: AxiosResponse = await axios.get( + `${this.restURL}rawtransactions/decodeScript/${script}` + ) + + return response.data + } else if (Array.isArray(script)) { + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}rawtransactions/decodeScript`, + { + hexes: script + } + ) + + return response.data + } + + throw new Error(`Input must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async getRawTransaction( + txid: string | string[], + verbose: boolean = false + ): Promise< + | VerboseRawTransactionResult + | VerboseRawTransactionResult[] + | string + | string[] + > { + try { + if (typeof txid === "string") { + const response: AxiosResponse = await axios.get( + `${ + this.restURL + }rawtransactions/getRawTransaction/${txid}?verbose=${verbose}` + ) + + return response.data + } else if (Array.isArray(txid)) { + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}rawtransactions/getRawTransaction`, + { + txids: txid, + verbose: verbose + } + ) + + return response.data + } + + throw new Error(`Input must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + public async sendRawTransaction( + hex: string | string[], + allowhighfees: boolean = false + ): Promise { + try { + // Single tx hex. + if (typeof hex === "string") { + const response: AxiosResponse = await axios.get( + `${this.restURL}rawtransactions/sendRawTransaction/${hex}` + ) + + if (response.data === "66: insufficient priority") { + console.warn( + `WARN: Insufficient Priority! This is likely due to a fee that is too low, or insufficient funds. + Please ensure that there is BCH in the given wallet. If you are running on the testnet, get some + BCH from the testnet faucet at https://developer.bitcoin.com/faucets/bch` + ) + } + + return response.data + + // Array input + } else if (Array.isArray(hex)) { + + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}rawtransactions/sendRawTransaction`, + { + hexes: hex + } + ) + + return response.data + } + + throw new Error(`Input hex must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } +} diff --git a/lib/Schnorr.ts b/lib/Schnorr.ts new file mode 100644 index 00000000..a877a7b8 --- /dev/null +++ b/lib/Schnorr.ts @@ -0,0 +1,128 @@ +// imports +import * as BigInteger from "bigi" + +// consts +const schnorr = require("bip-schnorr") + +export interface Session { + sessionId: Buffer + message: Buffer + pubKeyCombined: Buffer + ell: Buffer + idx: number +} + +export class Schnorr { + public sign(privateKey: BigInteger, message: Buffer): Buffer { + return schnorr.sign(privateKey, message) + } + + public verify( + publicKey: Buffer, + message: Buffer, + signatureToVerify: Buffer + ): void { + return schnorr.verify(publicKey, message, signatureToVerify) + } + + public batchVerify( + publicKeys: Buffer[], + messages: Buffer[], + signaturesToVerify: Buffer[] + ): void { + return schnorr.batchVerify(publicKeys, messages, signaturesToVerify) + } + + public nonInteractive(privateKeys: BigInteger, message: Buffer): Buffer { + return schnorr.muSig.nonInteractive(privateKeys, message) + } + + public computeEll(publicKeys: BigInteger): Buffer { + return schnorr.muSig.computeEll(publicKeys) + } + + public publicKeyCombine(publicKeys: Buffer[], publicKeyHash: Buffer): Buffer { + return schnorr.muSig.pubKeyCombine(publicKeys, publicKeyHash) + } + + public sessionInitialize( + sessionId: Buffer, + privateKey: BigInteger, + message: Buffer, + pubKeyCombined: Buffer, + ell: Buffer, + idx: number + ): Session { + return schnorr.muSig.sessionInitialize( + sessionId, + privateKey, + message, + pubKeyCombined, + ell, + idx + ) + } + + public sessionNonceCombine(session: Session, nonces: Buffer[]): Buffer { + return schnorr.muSig.sessionNonceCombine(session, nonces) + } + + public partialSign( + session: Session, + message: Buffer, + nonceCombined: Buffer, + pubKeyCombined: Buffer + ): void { + return schnorr.muSig.partialSign( + session, + message, + nonceCombined, + pubKeyCombined + ) + } + + public partialSignatureVerify( + session: Session, + partialSignature: Buffer, + nonceCombined: Buffer, + idx: number, + pubKey: Buffer, + nonce: Buffer + ): void { + return schnorr.muSig.partialSigVerify( + session, + partialSignature, + nonceCombined, + idx, + pubKey, + nonce + ) + } + + public partialSignaturesCombine( + nonceCombined: Buffer, + partialSignatures: Buffer + ): Buffer { + return schnorr.muSig.partialSigCombine(nonceCombined, partialSignatures) + } + + public bufferToInt(buffer: Buffer): BigInteger { + return schnorr.convert.bufferToInt(buffer) + } + + public intToBuffer(bigInteger: BigInteger): Buffer { + return schnorr.convert.intToBuffer(bigInteger) + } + + public hash(buffer: Buffer): Buffer { + return schnorr.convert.hash(buffer) + } + + public pointToBuffer(point: any): any { + return schnorr.convert.pointToBuffer(point) + } + + public pubKeyToPoint(publicKey: any): any { + return schnorr.convert.pubKeyToPoint(publicKey) + } +} diff --git a/lib/Script.js b/lib/Script.js deleted file mode 100644 index 149718ef..00000000 --- a/lib/Script.js +++ /dev/null @@ -1,95 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _bitcoincashjsLib = require('bitcoincashjs-lib'); - -var _bitcoincashjsLib2 = _interopRequireDefault(_bitcoincashjsLib); - -var _bitcoinOps = require('bitcoin-ops'); - -var _bitcoinOps2 = _interopRequireDefault(_bitcoinOps); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Script = function () { - function Script() { - _classCallCheck(this, Script); - - this.opcodes = _bitcoinOps2.default; - this.nullData = _bitcoincashjsLib2.default.script.nullData; - this.multisig = { - input: { - encode: function encode(signatures) { - var sigs = []; - signatures.forEach(function (sig) { - sigs.push(sig); - }); - return _bitcoincashjsLib2.default.script.multisig.input.encode(sigs); - }, - decode: _bitcoincashjsLib2.default.script.multisig.input.decode, - check: _bitcoincashjsLib2.default.script.multisig.input.check - }, - output: { - encode: function encode(m, pubKeys) { - var pks = []; - pubKeys.forEach(function (pubKey) { - pks.push(pubKey); - }); - return _bitcoincashjsLib2.default.script.multisig.output.encode(m, pks); - }, - decode: _bitcoincashjsLib2.default.script.multisig.output.decode, - check: _bitcoincashjsLib2.default.script.multisig.output.check - } - }; - this.pubKey = _bitcoincashjsLib2.default.script.pubKey; - this.pubKeyHash = _bitcoincashjsLib2.default.script.pubKeyHash; - this.scriptHash = _bitcoincashjsLib2.default.script.scriptHash; - } - - _createClass(Script, [{ - key: 'classifyInput', - value: function classifyInput(script) { - return _bitcoincashjsLib2.default.script.classifyInput(script); - } - }, { - key: 'classifyOutput', - value: function classifyOutput(script) { - return _bitcoincashjsLib2.default.script.classifyOutput(script); - } - }, { - key: 'decode', - value: function decode(scriptBuffer) { - return _bitcoincashjsLib2.default.script.decompile(scriptBuffer); - } - }, { - key: 'encode', - value: function encode(scriptChunks) { - var arr = []; - scriptChunks.forEach(function (chunk) { - arr.push(chunk); - }); - return _bitcoincashjsLib2.default.script.compile(arr); - } - }, { - key: 'toASM', - value: function toASM(buffer) { - return _bitcoincashjsLib2.default.script.toASM(buffer); - } - }, { - key: 'fromASM', - value: function fromASM(asm) { - return _bitcoincashjsLib2.default.script.fromASM(asm); - } - }]); - - return Script; -}(); - -exports.default = Script; \ No newline at end of file diff --git a/lib/Script.ts b/lib/Script.ts new file mode 100644 index 00000000..3b5f122b --- /dev/null +++ b/lib/Script.ts @@ -0,0 +1,415 @@ +// consts +const Bitcoin = require("@bitcoin-dot-com/bitcoincashjs2-lib") +const opcodes = require("bitcoincash-ops") + +export interface opcodes { + OP_FALSE: 0 + OP_0: 0 + OP_PUSHDATA1: 76 + OP_PUSHDATA2: 77 + OP_PUSHDATA4: 78 + OP_1NEGATE: 79 + OP_RESERVED: 80 + OP_TRUE: 81 + OP_1: 81 + OP_2: 82 + OP_3: 83 + OP_4: 84 + OP_5: 85 + OP_6: 86 + OP_7: 87 + OP_8: 88 + OP_9: 89 + OP_10: 90 + OP_11: 91 + OP_12: 92 + OP_13: 93 + OP_14: 94 + OP_15: 95 + OP_16: 96 + + OP_NOP: 97 + OP_VER: 98 + OP_IF: 99 + OP_NOTIF: 100 + OP_VERIF: 101 + OP_VERNOTIF: 102 + OP_ELSE: 103 + OP_ENDIF: 104 + OP_VERIFY: 105 + OP_RETURN: 106 + OP_TOALTSTACK: 107 + OP_FROMALTSTACK: 108 + OP_2DROP: 109 + OP_2DUP: 110 + OP_3DUP: 111 + OP_2OVER: 112 + OP_2ROT: 113 + OP_2SWAP: 114 + OP_IFDUP: 115 + OP_DEPTH: 116 + OP_DROP: 117 + OP_DUP: 118 + OP_NIP: 119 + OP_OVER: 120 + OP_PICK: 121 + OP_ROLL: 122 + OP_ROT: 123 + OP_SWAP: 124 + OP_TUCK: 125 + OP_CAT: 126 + OP_SPLIT: 127 + OP_NUM2BIN: 128 + OP_BIN2NUM: 129 + OP_SIZE: 130 + OP_INVERT: 131 + OP_AND: 132 + OP_OR: 133 + OP_XOR: 134 + OP_EQUAL: 135 + OP_EQUALVERIFY: 136 + OP_RESERVED1: 137 + OP_RESERVED2: 138 + OP_1ADD: 139 + OP_1SUB: 140 + OP_2MUL: 141 + OP_2DIV: 142 + OP_NEGATE: 143 + OP_ABS: 144 + OP_NOT: 145 + OP_0NOTEQUAL: 146 + OP_ADD: 147 + OP_SUB: 148 + OP_MUL: 149 + OP_DIV: 150 + OP_MOD: 151 + OP_LSHIFT: 152 + OP_RSHIFT: 153 + OP_BOOLAND: 154 + OP_BOOLOR: 155 + OP_NUMEQUAL: 156 + OP_NUMEQUALVERIFY: 157 + OP_NUMNOTEQUAL: 158 + OP_LESSTHAN: 159 + OP_GREATERTHAN: 160 + OP_LESSTHANOREQUAL: 161 + OP_GREATERTHANOREQUAL: 162 + OP_MIN: 163 + OP_MAX: 164 + OP_WITHIN: 165 + OP_RIPEMD160: 166 + OP_SHA1: 167 + OP_SHA256: 168 + OP_HASH160: 169 + OP_HASH256: 170 + OP_CODESEPARATOR: 171 + OP_CHECKSIG: 172 + OP_CHECKSIGVERIFY: 173 + OP_CHECKMULTISIG: 174 + OP_CHECKMULTISIGVERIFY: 175 + OP_NOP1: 176 + OP_NOP2: 177 + OP_CHECKLOCKTIMEVERIFY: 177 + OP_NOP3: 178 + OP_CHECKSEQUENCEVERIFY: 178 + OP_NOP4: 179 + OP_NOP5: 180 + OP_NOP6: 181 + OP_NOP7: 182 + OP_NOP8: 183 + OP_NOP9: 184 + OP_NOP10: 185 + OP_CHECKDATASIG: 186 + OP_CHECKDATASIGVERIFY: 187 + OP_PUBKEYHASH: 253 + OP_PUBKEY: 254 + OP_INVALIDOPCODE: 255 +} + +export interface DecodedP2PKHInput { + signature: Buffer + pubKey: Buffer +} + +export interface DecodedP2MSOutput { + m: number + pubKeys: Buffer[] +} + +export interface DecodedP2SHInput { + redeemScript: Buffer + redeemScriptSig: Buffer +} + +export interface nullData { + output: { + encode(data: Buffer): Buffer + decode(output: Buffer): Buffer + check(output: Buffer): boolean + } +} + +export interface pubKey { + input: { + encode(signature: Buffer): Buffer + decode(input: Buffer): Buffer + check(input: Buffer): boolean + decodeStack(data: Buffer): Buffer + encodeStack(data: Buffer): Buffer + } + output: { + encode(pubKey: Buffer): Buffer + decode(output: Buffer): Buffer + check(output: Buffer): boolean + } +} + +export interface pubKeyHash { + input: { + encode(signature: Buffer, pubKey: Buffer): Buffer + decode(data: Buffer): DecodedP2PKHInput + check(data: Buffer): boolean + decodeStack(data: Buffer): Buffer + encodeStack(data: Buffer): Buffer + } + output: { + encode(identifier: Buffer): Buffer + decode(output: Buffer): Buffer + check(output: Buffer): boolean + } +} + +export interface multisig { + input: { + encode(signatures: Buffer[]): Buffer + decode(input: Buffer): Buffer[] + check(input: Buffer): boolean + } + output: { + encode(m: number, pubKeys: Buffer[]): Buffer + decode(output: Buffer): DecodedP2MSOutput + check(output: Buffer): boolean + } +} + +export interface scriptHash { + input: { + encode(redeemScriptSig: Buffer, redeemScript: Buffer): Buffer + decode(input: Buffer): DecodedP2SHInput + check(data: Buffer): boolean + decodeStack(data: Buffer): Buffer + encodeStack(data: Buffer): Buffer + } + output: { + encode(scriptHash: Buffer): Buffer + decode(output: Buffer): Buffer + check(output: Buffer): boolean + } +} + +export interface scriptNumber { + encode(number: number): Buffer + decode(buffer: Buffer, maxLength?: number, minimal?: boolean): number +} + +export class Script { + public opcodes: opcodes + public nullData: nullData + public pubKey: pubKey + public pubKeyHash: pubKeyHash + public multisig: multisig + public scriptHash: scriptHash + public number: scriptNumber + + constructor() { + this.opcodes = opcodes + this.nullData = Bitcoin.script.nullData + this.multisig = { + input: { + encode: (signatures: Buffer[]): Buffer => { + const sigs: any[] = [] + signatures.forEach((sig: any) => { + sigs.push(sig) + }) + return Bitcoin.script.multisig.input.encode(sigs) + }, + decode: Bitcoin.script.multisig.input.decode, + check: Bitcoin.script.multisig.input.check + }, + output: { + encode: (m: number, pubKeys: Buffer[]): Buffer => { + const pks: any[] = [] + pubKeys.forEach((pubKey: any) => { + pks.push(pubKey) + }) + return Bitcoin.script.multisig.output.encode(m, pks) + }, + decode: Bitcoin.script.multisig.output.decode, + check: Bitcoin.script.multisig.output.check + } + } + this.pubKey = Bitcoin.script.pubKey + this.pubKeyHash = Bitcoin.script.pubKeyHash + this.scriptHash = Bitcoin.script.scriptHash + this.number = Bitcoin.script.number + } + + public encode(scriptChunks: Array): Buffer { + const arr: Array = [] + scriptChunks.forEach((chunk: number | Buffer) => { + arr.push(chunk) + }) + return Bitcoin.script.compile(arr) + } + + public encode2(scriptChunks: Array): Buffer { + const arr: Array = [] + scriptChunks.forEach((chunk: number | Buffer) => { + arr.push(chunk) + }) + return Bitcoin.script.compile2(arr) + } + + public decode(scriptBuffer: Buffer): Array { + return Bitcoin.script.decompile(scriptBuffer) + } + + public toASM(buffer: Buffer): string { + return Bitcoin.script.toASM(buffer) + } + + public fromASM(asm: string): Buffer { + return Bitcoin.script.fromASM(asm) + } + + public classifyInput(script: Buffer): string { + return Bitcoin.script.classifyInput(script) + } + + public classifyOutput(script: Buffer): string { + return Bitcoin.script.classifyOutput(script) + } + + public encodeNullDataOutput(data: Buffer): Buffer { + return this.nullData.output.encode(data) + } + + public decodeNullDataOutput(output: Buffer): Buffer { + return this.nullData.output.decode(output) + } + + public checkNullDataOutput(output: Buffer): boolean { + return this.nullData.output.check(output) + } + + public encodeP2PKInput(signature: Buffer): Buffer { + return this.pubKey.input.encode(signature) + } + + public decodeP2PKInput(input: Buffer): Buffer { + return this.pubKey.input.decode(input) + } + + public checkP2PKInput(input: Buffer): boolean { + return this.pubKey.input.check(input) + } + + public encodeP2PKOutput(pubKey: Buffer): Buffer { + return this.pubKey.output.encode(pubKey) + } + + public decodeP2PKOutput(output: Buffer): Buffer { + return this.pubKey.output.decode(output) + } + + public checkP2PKOutput(output: Buffer): boolean { + return this.pubKey.output.check(output) + } + + public encodeP2PKHInput(signature: Buffer, pubKey: Buffer): Buffer { + return this.pubKeyHash.input.encode(signature, pubKey) + } + + public decodeP2PKHInput(input: Buffer): DecodedP2PKHInput { + return this.pubKeyHash.input.decode(input) + } + + public checkP2PKHInput(input: Buffer): boolean { + return this.pubKeyHash.input.check(input) + } + + public encodeP2PKHOutput(identifier: Buffer): Buffer { + return this.pubKeyHash.output.encode(identifier) + } + + public decodeP2PKHOutput(output: Buffer): Buffer { + return this.pubKeyHash.output.decode(output) + } + + public checkP2PKHOutput(output: Buffer): boolean { + return this.pubKeyHash.output.check(output) + } + + public encodeP2MSInput(signatures: Buffer[]): Buffer { + return this.multisig.input.encode(signatures) + } + + public decodeP2MSInput(input: Buffer): Buffer[] { + return this.multisig.input.decode(input) + } + + public checkP2MSInput(input: Buffer): boolean { + return this.multisig.input.check(input) + } + + public encodeP2MSOutput(m: number, pubKeys: Buffer[]): Buffer { + return this.multisig.output.encode(m, pubKeys) + } + + public decodeP2MSOutput(output: Buffer): DecodedP2MSOutput { + return this.multisig.output.decode(output) + } + + public checkP2MSOutput(output: Buffer): boolean { + return this.multisig.output.check(output) + } + + public encodeP2SHInput( + redeemScriptSig: Buffer, + redeemScript: Buffer + ): Buffer { + return this.scriptHash.input.encode(redeemScriptSig, redeemScript) + } + + public decodeP2SHInput(input: Buffer): DecodedP2SHInput { + return this.scriptHash.input.decode(input) + } + + public checkP2SHInput(input: Buffer): boolean { + return this.scriptHash.input.check(input) + } + + public encodeP2SHOutput(scriptHash: Buffer): Buffer { + return this.scriptHash.output.encode(scriptHash) + } + + public decodeP2SHOutput(output: Buffer): Buffer { + return this.scriptHash.output.decode(output) + } + + public checkP2SHOutput(output: Buffer): boolean { + return this.scriptHash.output.check(output) + } + + public encodeNumber(number: number): Buffer { + return this.number.encode(number) + } + + public decodeNumber( + buffer: Buffer, + maxLength?: number, + minimal?: boolean + ): number { + return this.number.decode(buffer, maxLength, minimal) + } +} diff --git a/lib/Socket.ts b/lib/Socket.ts new file mode 100644 index 00000000..37bd498b --- /dev/null +++ b/lib/Socket.ts @@ -0,0 +1,54 @@ +import { BITSOCKET_URL, WS_URL } from "./BITBOX" +import { SocketConfig } from "./interfaces/BITBOXInterfaces" + +const io: any = require("socket.io-client") +export class Socket { + socket: any + websocketURL: string + bitsocketURL: string + constructor(config: SocketConfig = {}) { + if (config.wsURL) { + // default to passed in wsURL + this.websocketURL = config.wsURL + } else if (config.restURL) { + // 2nd option deprecated restURL + this.websocketURL = config.restURL + } else { + // fallback to WS_URL + this.websocketURL = WS_URL + } + + if (config.bitsocketURL) { + this.bitsocketURL = config.bitsocketURL + } else { + this.bitsocketURL = BITSOCKET_URL + } + + if (config.callback) config.callback() + } + + public listen(query: string, cb: Function): void { + if (query === "blocks" || query === "transactions") { + this.socket = io(this.websocketURL, { transports: ["websocket"] }) + this.socket.emit(query) + + if (query === "blocks") this.socket.on("blocks", (msg: any) => cb(msg)) + else if (query === "transactions") + this.socket.on("transactions", (msg: any) => cb(msg)) + } else { + let EventSource = require("eventsource") + let b64 = Buffer.from(JSON.stringify(query)).toString("base64") + this.socket = new EventSource(`${this.bitsocketURL}/s/${b64}`) + this.socket.onmessage = (msg: any) => { + cb(msg.data) + } + } + } + + public close(cb?: Function): void { + this.socket.close() + if (cb) { + cb() + } + } +} diff --git a/lib/Transaction.js b/lib/Transaction.js deleted file mode 100644 index 6075222a..00000000 --- a/lib/Transaction.js +++ /dev/null @@ -1,68 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _bitcoincashjsLib = require('bitcoincashjs-lib'); - -var _bitcoincashjsLib2 = _interopRequireDefault(_bitcoincashjsLib); - -var _axios = require('axios'); - -var _axios2 = _interopRequireDefault(_axios); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Transaction = function () { - function Transaction(restURL) { - _classCallCheck(this, Transaction); - - this.restURL = restURL; - } - - _createClass(Transaction, [{ - key: 'transaction', - value: function transaction() { - return new _bitcoincashjsLib2.default.Transaction(); - } - }, { - key: 'fromHex', - value: function fromHex(hex) { - return _bitcoincashjsLib2.default.Transaction.fromHex(hex); - } - }, { - key: 'transactionBuilder', - value: function transactionBuilder() { - var network = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'bitcoin'; - - return new _bitcoincashjsLib2.default.TransactionBuilder(_bitcoincashjsLib2.default.networks[network]); - } - }, { - key: 'fromTransaction', - value: function fromTransaction(tx) { - return _bitcoincashjsLib2.default.TransactionBuilder.fromTransaction(tx); - } - }, { - key: 'details', - value: function details(txid) { - if (typeof txid !== 'string') { - txid = JSON.stringify(txid); - } - - return _axios2.default.get(this.restURL + 'transaction/details/' + txid).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }]); - - return Transaction; -}(); - -exports.default = Transaction; \ No newline at end of file diff --git a/lib/Transaction.ts b/lib/Transaction.ts new file mode 100644 index 00000000..e46799f6 --- /dev/null +++ b/lib/Transaction.ts @@ -0,0 +1,41 @@ +import axios, { AxiosRequestConfig, AxiosResponse } from "axios" +import { TxnDetailsResult } from "bitcoin-com-rest" +import { REST_URL } from "./BITBOX" + +export class Transaction { + public restURL: string + constructor(restURL: string = REST_URL) { + this.restURL = restURL + } + + public async details( + txid: string | string[] + ): Promise { + try { + // Handle single address. + if (typeof txid === "string") { + const response: AxiosResponse = await axios.get( + `${this.restURL}transaction/details/${txid}` + ) + return response.data + + // Array of addresses + } else if (Array.isArray(txid)) { + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}transaction/details`, + { + txids: txid + } + ) + + return response.data + } + + throw new Error(`Input txid must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } +} diff --git a/lib/TransactionBuilder.js b/lib/TransactionBuilder.js deleted file mode 100644 index 9d17b3d8..00000000 --- a/lib/TransactionBuilder.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _bitcoincashjsLib = require('bitcoincashjs-lib'); - -var _bitcoincashjsLib2 = _interopRequireDefault(_bitcoincashjsLib); - -var _bchaddrjs = require('bchaddrjs'); - -var _bchaddrjs2 = _interopRequireDefault(_bchaddrjs); - -var _coininfo = require('coininfo'); - -var _coininfo2 = _interopRequireDefault(_coininfo); - -var _bip = require('bip68'); - -var _bip2 = _interopRequireDefault(_bip); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var TransactionBuilder = function () { - function TransactionBuilder() { - var network = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'bitcoincash'; - - _classCallCheck(this, TransactionBuilder); - - var bitcoincash = void 0; - if (network === 'bitcoincash') { - bitcoincash = _coininfo2.default.bitcoincash.main; - } else { - bitcoincash = _coininfo2.default.bitcoincash.test; - } - var bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS(); - this.transaction = new _bitcoincashjsLib2.default.TransactionBuilder(bitcoincashBitcoinJSLib); - this.DEFAULT_SEQUENCE = 0xffffffff; - this.hashTypes = { - SIGHASH_ALL: 0x01, - SIGHASH_NONE: 0x02, - SIGHASH_SINGLE: 0x03, - SIGHASH_ANYONECANPAY: 0x80, - SIGHASH_BITCOINCASH_BIP143: 0x40, - ADVANCED_TRANSACTION_MARKER: 0x00, - ADVANCED_TRANSACTION_FLAG: 0x01 - }; - this.bip68 = _bip2.default; - } - - _createClass(TransactionBuilder, [{ - key: 'addInput', - value: function addInput(txHash, vout) { - var sequence = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.DEFAULT_SEQUENCE; - var prevOutScript = arguments[3]; - - this.transaction.addInput(txHash, vout, sequence, prevOutScript); - } - }, { - key: 'addOutput', - value: function addOutput(scriptPubKey, amount) { - try { - this.transaction.addOutput(_bchaddrjs2.default.toLegacyAddress(scriptPubKey), amount); - } catch (error) { - this.transaction.addOutput(scriptPubKey, amount); - } - } - }, { - key: 'sign', - value: function sign(vin, keyPair, redeemScript) { - var hashType = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : this.hashTypes.SIGHASH_ALL; - var value = arguments[4]; - - var witnessScript = void 0; - - this.transaction.sign(vin, keyPair, redeemScript, hashType, value, witnessScript); - } - }, { - key: 'build', - value: function build() { - return this.transaction.build(); - } - }]); - - return TransactionBuilder; -}(); - -exports.default = TransactionBuilder; \ No newline at end of file diff --git a/lib/TransactionBuilder.ts b/lib/TransactionBuilder.ts new file mode 100644 index 00000000..b3b4b152 --- /dev/null +++ b/lib/TransactionBuilder.ts @@ -0,0 +1,137 @@ +// imports +import { ECPair } from "bitcoincashjs-lib" +import { BchInfo } from ".." +import { Address } from "./Address" +import { TREST_URL } from "./BITBOX" + +// consts +const Bitcoin = require("@bitcoin-dot-com/bitcoincashjs2-lib") +const coininfo = require("coininfo") +const bip66 = require("bip66") +const bip68 = require("bc-bip68") + +declare interface SignatureAlgorithms { + ECDSA: number + SCHNORR: number +} + +declare interface HashTypes { + SIGHASH_ALL: number + SIGHASH_NONE: number + SIGHASH_SINGLE: number + SIGHASH_ANYONECANPAY: number + SIGHASH_BITCOINCASH_BIP143: number + ADVANCED_TRANSACTION_MARKER: number + ADVANCED_TRANSACTION_FLAG: number +} + +export class TransactionBuilder { + transaction: any + DEFAULT_SEQUENCE: any + hashTypes: HashTypes + signatureAlgorithms: SignatureAlgorithms + bip66: any + bip68: any + p2shInput: any + tx: any + private _address: Address + + constructor(network: string = "mainnet") { + let bitcoincash: BchInfo + if (network === "mainnet") { + this._address = new Address() + } else { + this._address = new Address(TREST_URL) + } + if (network === "bitcoincash" || network === "mainnet") + bitcoincash = coininfo.bitcoincash.main + else bitcoincash = coininfo.bitcoincash.test + + const bitcoincashBitcoinJSLib: any = bitcoincash.toBitcoinJS() + this.transaction = new Bitcoin.TransactionBuilder(bitcoincashBitcoinJSLib) + this.DEFAULT_SEQUENCE = 0xffffffff + this.hashTypes = { + SIGHASH_ALL: 0x01, + SIGHASH_NONE: 0x02, + SIGHASH_SINGLE: 0x03, + SIGHASH_ANYONECANPAY: 0x80, + SIGHASH_BITCOINCASH_BIP143: 0x40, + ADVANCED_TRANSACTION_MARKER: 0x00, + ADVANCED_TRANSACTION_FLAG: 0x01 + } + this.signatureAlgorithms = { + ECDSA: Bitcoin.ECSignature.ECDSA, + SCHNORR: Bitcoin.ECSignature.SCHNORR + } + this.bip66 = bip66 + this.bip68 = bip68 + this.p2shInput = false + this.tx + } + + public addInput( + txHash: string, + vout: number, + sequence: number = this.DEFAULT_SEQUENCE, + prevOutScript: string | Buffer | null = null + ): void { + this.transaction.addInput(txHash, vout, sequence, prevOutScript) + } + + public addInputScript(vout: number, script: any): void { + this.tx = this.transaction.buildIncomplete() + this.tx.setInputScript(vout, script) + this.p2shInput = true + } + + public addInputScripts(scripts: any): void { + this.tx = this.transaction.buildIncomplete() + scripts.forEach((script: any) => { + this.tx.setInputScript(script.vout, script.script) + }) + this.p2shInput = true + } + + public addOutput(scriptPubKey: string | Buffer, amount: number): void { + try { + this.transaction.addOutput( + // @ts-ignore + this._address.toLegacyAddress(scriptPubKey), + amount + ) + } catch (error) { + this.transaction.addOutput(scriptPubKey, amount) + } + } + + public setLockTime(locktime: number): void { + this.transaction.setLockTime(locktime) + } + + public sign( + vin: number, + keyPair: ECPair, + redeemScript: Buffer | undefined, + hashType: number = this.hashTypes.SIGHASH_ALL, + value: number, + signatureAlgorithm: number = 0 + ): void { + let witnessScript + + this.transaction.sign( + vin, + keyPair, + redeemScript, + hashType, + value, + witnessScript, + signatureAlgorithm + ) + } + + public build(): any { + if (this.p2shInput === true) return this.tx + + return this.transaction.build() + } +} diff --git a/lib/Util.js b/lib/Util.js deleted file mode 100644 index 7cecc053..00000000 --- a/lib/Util.js +++ /dev/null @@ -1,58 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _axios = require('axios'); - -var _axios2 = _interopRequireDefault(_axios); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Util = function () { - function Util(restURL) { - _classCallCheck(this, Util); - - this.restURL = restURL; - } - - _createClass(Util, [{ - key: 'validateAddress', - value: function validateAddress(address) { - // Return information about the given bitcoin address. - // - // Arguments: - // 1. "address" (string, required) The bitcoin address to validate - // - // Result: - // { - // "isvalid" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned. - // "address" : "address", (string) The bitcoin address validated - // "scriptPubKey" : "hex", (string) The hex encoded scriptPubKey generated by the address - // "ismine" : true|false, (boolean) If the address is yours or not - // "iswatchonly" : true|false, (boolean) If the address is watchonly - // "isscript" : true|false, (boolean) If the key is a script - // "pubkey" : "publickeyhex", (string) The hex value of the raw public key - // "iscompressed" : true|false, (boolean) If the address is compressed - // "account" : "account" (string) DEPRECATED. The account associated with the address, "" is the default account - // "timestamp" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT) - // "hdkeypath" : "keypath" (string, optional) The HD keypath if the key is HD and available - // "hdmasterkeyid" : "" (string, optional) The Hash160 of the HD master pubkey - // } - return _axios2.default.get(this.restURL + 'util/validateAddress/' + address).then(function (response) { - return response.data; - }).catch(function (error) { - return JSON.stringify(error.response.data.error.message); - }); - } - }]); - - return Util; -}(); - -exports.default = Util; \ No newline at end of file diff --git a/lib/Util.ts b/lib/Util.ts new file mode 100644 index 00000000..6cd975c5 --- /dev/null +++ b/lib/Util.ts @@ -0,0 +1,48 @@ +import axios, { AxiosResponse } from "axios" +import { REST_URL } from "./BITBOX" + +export interface AddressDetails { + isvalid: boolean + address: string + scriptPubKey: string + ismine: boolean + iswatchonly: boolean + isscript: boolean + pubkey: string + iscompressed: boolean + account: string +} + +export class Util { + public restURL: string + constructor(restURL: string = REST_URL) { + this.restURL = restURL + } + public async validateAddress( + address: string | string[] + ): Promise { + try { + // Single block + if (typeof address === "string") { + const response: AxiosResponse = await axios.get( + `${this.restURL}util/validateAddress/${address}` + ) + return response.data + // Array of blocks. + } else if (Array.isArray(address)) { + // Dev note: must use axios.post for unit test stubbing. + const response: AxiosResponse = await axios.post( + `${this.restURL}util/validateAddress`, + { + addresses: address + } + ) + return response.data + } + throw new Error(`Input must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } +} diff --git a/lib/bitbox-cli.js b/lib/bitbox-cli.js deleted file mode 100644 index d89147f3..00000000 --- a/lib/bitbox-cli.js +++ /dev/null @@ -1,119 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _axios = require('axios'); - -var _axios2 = _interopRequireDefault(_axios); - -var _bitcoincashjsLib = require('bitcoincashjs-lib'); - -var _bitcoincashjsLib2 = _interopRequireDefault(_bitcoincashjsLib); - -var _BitcoinCash = require('./BitcoinCash'); - -var _BitcoinCash2 = _interopRequireDefault(_BitcoinCash); - -var _Crypto = require('./Crypto'); - -var _Crypto2 = _interopRequireDefault(_Crypto); - -var _Util = require('./Util'); - -var _Util2 = _interopRequireDefault(_Util); - -var _Block = require('./Block'); - -var _Block2 = _interopRequireDefault(_Block); - -var _Blockchain = require('./Blockchain'); - -var _Blockchain2 = _interopRequireDefault(_Blockchain); - -var _Control = require('./Control'); - -var _Control2 = _interopRequireDefault(_Control); - -var _Generating = require('./Generating'); - -var _Generating2 = _interopRequireDefault(_Generating); - -var _Mining = require('./Mining'); - -var _Mining2 = _interopRequireDefault(_Mining); - -var _Network = require('./Network'); - -var _Network2 = _interopRequireDefault(_Network); - -var _RawTransactions = require('./RawTransactions'); - -var _RawTransactions2 = _interopRequireDefault(_RawTransactions); - -var _Mnemonic = require('./Mnemonic'); - -var _Mnemonic2 = _interopRequireDefault(_Mnemonic); - -var _Address = require('./Address'); - -var _Address2 = _interopRequireDefault(_Address); - -var _HDNode = require('./HDNode'); - -var _HDNode2 = _interopRequireDefault(_HDNode); - -var _Transaction = require('./Transaction'); - -var _Transaction2 = _interopRequireDefault(_Transaction); - -var _TransactionBuilder = require('./TransactionBuilder'); - -var _TransactionBuilder2 = _interopRequireDefault(_TransactionBuilder); - -var _ECPair = require('./ECPair'); - -var _ECPair2 = _interopRequireDefault(_ECPair); - -var _Script = require('./Script'); - -var _Script2 = _interopRequireDefault(_Script); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // 3rd party deps - - -// local deps - - -var BITBOXCli = function BITBOXCli(config) { - _classCallCheck(this, BITBOXCli); - - if (config && config.restURL && config.restURL !== '') { - this.restURL = config.restURL; - } else { - this.restURL = 'https://rest.bitbox.earth/v1/'; - } - - this.Address = new _Address2.default(this.restURL); - this.BitcoinCash = new _BitcoinCash2.default(); - this.Block = new _Block2.default(this.restURL); - this.Blockchain = new _Blockchain2.default(this.restURL); - this.Control = new _Control2.default(this.restURL); - this.Crypto = _Crypto2.default; - this.ECPair = _ECPair2.default; - this.Generating = new _Generating2.default(this.restURL); - this.HDNode = new _HDNode2.default(); - this.Mining = new _Mining2.default(this.restURL); - this.Mnemonic = new _Mnemonic2.default(); - this.Network = new _Network2.default(this.restURL); - this.RawTransactions = new _RawTransactions2.default(this.restURL); - this.Script = new _Script2.default(); - this.Transaction = new _Transaction2.default(this.restURL); - this.TransactionBuilder = _TransactionBuilder2.default; - this.Util = new _Util2.default(this.restURL); -}; - -exports.default = BITBOXCli; \ No newline at end of file diff --git a/lib/interfaces/BITBOXInterfaces.ts b/lib/interfaces/BITBOXInterfaces.ts new file mode 100644 index 00000000..ce6b96cc --- /dev/null +++ b/lib/interfaces/BITBOXInterfaces.ts @@ -0,0 +1,22 @@ +export interface IConfig { + restURL?: string + wsURL?: string + bitdbURL?: string +} + +export interface SocketConfig { + restURL?: string + wsURL?: string + bitsocketURL?: string + callback?: Function +} + +export interface QueryInterface { + amount?: number + label?: string + message?: string +} + +export interface BitDBResponse { + message: string +} diff --git a/lib/interfaces/vendors.d.ts b/lib/interfaces/vendors.d.ts new file mode 100644 index 00000000..6e3185a9 --- /dev/null +++ b/lib/interfaces/vendors.d.ts @@ -0,0 +1,330 @@ +/// +declare module "bitcoincashjs-lib" { + export interface HDNode { + keyPair: any + getAddress(): any + isNeutered(): any + getIdentifier(): any + verify(buffer: any, signature: any): any + deriveHardened(path: any): any + sign(buffer: any): any + toBase58(): any + neutered(): any + getPublicKeyBuffer(): any + derivePath(path: any): any + derive(path: any): any + } + + export interface ECPair { + toWIF(): string + sign(buffer: Buffer, signatureAlgorithm?: number): Boolean | ECSignature + verify(buffer: Buffer, signature: ECSignature): boolean + getPublicKeyBuffer(): Buffer + getAddress(): string + } + + export type ECSignature = any +} + +declare module "bitcoin-com-rest" { + export interface BlockDetailsResult { + hash: string + size: number + height: number + version: number + merkleroot: string + tx: string[] + time: number + mediantime?: number + nonce: number + bits: string + difficulty: number + chainwork: string + confirmations: number + previousblockhash: string + nextblockhash: string + reward: number + isMainChain: boolean + poolInfo: object + } + + export interface MempoolInfoResult { + size: number + bytes: number + usage: number + maxmempool: number + mempoolminfee: number + } + + export interface BlockchainInfoResult { + chain: string + blocks: number + headers: number + bestblockhash: string + difficulty: number + mediantime: number + verificationprogress: number + chainwork: string + pruned: boolean + softforks: object[] + bip9_softforks: object + } + + export interface BlockHeaderResult { + hash: string + confirmations: number + height: number + version: number + versionHex: string + merkleroot: string + time: number + mediantime: number + nonce: number + bits: string + difficulty: number + chainwork: string + previousblockhash: string + nextblockhash: string + } + + export interface ChainTipResult { + height: number + hash: string + branchlen: number + status: string + } + + export interface TxOutResult { + bestblock: string + confirmations: number + value: number + scriptPubKey: { + asm: string + hex: string + reqSigs: number + type: string + addresses: string[] + } + version: number + coinbase: boolean + } + + export interface MempoolEntryResult { + size: number + fee: number + modifiedfee: number + time: number + height: number + startingpriority: number + currentpriority: number + descendantcount: number + descendantsize: number + descendantfees: number + ancestorcount: number + ancestorsize: number + ancestorfees: number + depends: string[] + spentby: string[] + } + + export interface NodeInfoResult { + version: number + protocolversion: number + blocks: number + timeoffset: number + connections: number + proxy: string + difficulty: number + testnet: boolean + paytxfee: number + relayfee: number + errors: string + } + + export interface NodeMemoryInfoResult { + locked: { + used: number + free: number + total: number + locked: number + chunks_used: number + chunks_free: number + } + } + + export interface DecodeRawTransactionResult { + txid: string + hash: string + size: number + version: number + locktime: number + vin: [ + { + txid: string + vout: number + scriptSig: { + asm: string + hex: string + } + sequence: number + } + ] + vout: [ + { + value: number + n: number + scriptPubKey: { + asm: string + hex: string + reqSigs: number + type: string + addresses: string[] + } + } + ] + } + + export interface DecodeScriptResult { + asm: string + type: string + p2sh: string + } + + export interface VerboseRawTransactionResult { + hex: string + txid: string + size: number + version: number + locktime: number + vin: [{ coinbase: string; sequence: number }] + vout: [ + { + value: number + n: number + scriptPubKey: { + asm: string + hex: string + reqSigs: number + type: string + addresses: string[] + } + } + ] + blockhash: string + confirmations: number + time: number + blocktime: number + } + + export interface TxnDetailsResult { + txid: string + version: number + locktime: number + vin: object[] + vout: object[] + blockhash: string + blockheight: number + confirmations: number + time: number + blocktime: number + isCoinBase: boolean + valueOut: number + size: number + } + + export interface AddressDetailsResult { + balance: number + balanceSat: number + totalReceived: number + totalReceivedSat: number + totalSent: number + totalSentSat: number + unconfirmedBalance: number + unconfirmedBalanceSat: number + unconfirmedTxApperances: number + txApperances: number + transactions: string[] + legacyAddress: string + cashAddress: string + } + + export interface utxo { + txid: string + vout: number + amount: number + satoshis: number + height: number + confirmations: number + } + + export interface AddressUtxoResult { + legacyAddress: string + cashAddress: string + scriptPubKey: string + utxos: utxo[] + } + + export interface AddressUnconfirmedResult { + legacyAddress: string + cashAddress: string + scriptPubKey: string + utxos: [ + { + txid: string + vout: number + scriptPubKey: string + amount: number + satoshis: number + confirmations: number + ts: number + legacyAddress: string + cashAddress: string + } + ] + } + + export interface AddressValidateResult { + isvalid: boolean + address: string + scriptPubKey: string + ismine: boolean + iswatchonly: boolean + isscript: boolean + pubkey: string + iscompressed: boolean + account: string + } + + export interface CashAccountLookupResult { + identifier: string + information: { + emoji: string + name: string + number: number + collision: { + hash: string + } + payment: string[] + } + } + + export interface CashAccountCheckResult { + identifier: string + block: number + results: string[] + } + + export interface CashAccountReverseLookupResult { + results: SingleCashAccountReverseLookupResult[] + } + + export interface SingleCashAccountReverseLookupResult { + accountEmoji: any + nameText: string + accountNumber: number + accountHash: string + accountCollisionLength: number + payloadType: number + payloadAddress: string + } +} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 3c284d2b..00000000 --- a/package-lock.json +++ /dev/null @@ -1,6542 +0,0 @@ -{ - "name": "bitbox-cli", - "version": "1.1.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@sinonjs/formatio": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", - "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", - "dev": true, - "requires": { - "samsam": "1.3.0" - } - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "ammo": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ammo/-/ammo-1.0.1.tgz", - "integrity": "sha1-j4rdFM1Jve3jurOj4OvK8h0D3os=", - "requires": { - "boom": "2.x.x", - "hoek": "2.x.x" - } - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "anymatch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", - "optional": true, - "requires": { - "micromatch": "^2.1.5", - "normalize-path": "^2.0.0" - } - }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "optional": true, - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "optional": true - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "optional": true - }, - "assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", - "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", - "requires": { - "util": "0.10.3" - } - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, - "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", - "optional": true - }, - "axios": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.17.1.tgz", - "integrity": "sha1-LY4+XQvb1zJ/kbyBT1xXZg+Bgk0=", - "requires": { - "follow-redirects": "^1.2.5", - "is-buffer": "^1.1.5" - } - }, - "babel-cli": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz", - "integrity": "sha1-UCq1SHTX24itALiHoGODzgPQAvE=", - "requires": { - "babel-core": "^6.26.0", - "babel-polyfill": "^6.26.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "chokidar": "^1.6.1", - "commander": "^2.11.0", - "convert-source-map": "^1.5.0", - "fs-readdir-recursive": "^1.0.0", - "glob": "^7.1.2", - "lodash": "^4.17.4", - "output-file-sync": "^1.1.2", - "path-is-absolute": "^1.0.1", - "slash": "^1.0.0", - "source-map": "^0.5.6", - "v8flags": "^2.1.1" - } - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - } - } - }, - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - } - } - }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - } - }, - "babel-helper-builder-binary-assignment-operator-visitor": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", - "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", - "requires": { - "babel-helper-explode-assignable-expression": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-builder-react-jsx": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz", - "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "esutils": "^2.0.2" - } - }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-define-map": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-helper-explode-assignable-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", - "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", - "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-regex": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", - "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-helper-remap-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", - "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", - "requires": { - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-syntax-async-functions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", - "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=" - }, - "babel-plugin-syntax-exponentiation-operator": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", - "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=" - }, - "babel-plugin-syntax-flow": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", - "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=" - }, - "babel-plugin-syntax-jsx": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" - }, - "babel-plugin-syntax-trailing-function-commas": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", - "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=" - }, - "babel-plugin-transform-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", - "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", - "requires": { - "babel-helper-remap-async-to-generator": "^6.24.1", - "babel-plugin-syntax-async-functions": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-plugin-transform-es2015-classes": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", - "requires": { - "babel-helper-define-map": "^6.24.1", - "babel-helper-function-name": "^6.24.1", - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-helper-replace-supers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-duplicate-keys": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", - "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-modules-amd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", - "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", - "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", - "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", - "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-systemjs": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", - "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-modules-umd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", - "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", - "requires": { - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", - "requires": { - "babel-helper-replace-supers": "^6.24.1", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", - "requires": { - "babel-helper-call-delegate": "^6.24.1", - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-sticky-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", - "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", - "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", - "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "regexpu-core": "^2.0.0" - } - }, - "babel-plugin-transform-exponentiation-operator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", - "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", - "requires": { - "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", - "babel-plugin-syntax-exponentiation-operator": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-flow-strip-types": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", - "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", - "requires": { - "babel-plugin-syntax-flow": "^6.18.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-react-display-name": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz", - "integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-react-jsx": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", - "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=", - "requires": { - "babel-helper-builder-react-jsx": "^6.24.1", - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-react-jsx-self": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz", - "integrity": "sha1-322AqdomEqEh5t3XVYvL7PBuY24=", - "requires": { - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-react-jsx-source": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz", - "integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=", - "requires": { - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-regenerator": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", - "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", - "requires": { - "regenerator-transform": "^0.10.0" - } - }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-polyfill": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", - "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", - "requires": { - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "regenerator-runtime": "^0.10.5" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" - } - } - }, - "babel-preset-env": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", - "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", - "requires": { - "babel-plugin-check-es2015-constants": "^6.22.0", - "babel-plugin-syntax-trailing-function-commas": "^6.22.0", - "babel-plugin-transform-async-to-generator": "^6.22.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.23.0", - "babel-plugin-transform-es2015-classes": "^6.23.0", - "babel-plugin-transform-es2015-computed-properties": "^6.22.0", - "babel-plugin-transform-es2015-destructuring": "^6.23.0", - "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", - "babel-plugin-transform-es2015-for-of": "^6.23.0", - "babel-plugin-transform-es2015-function-name": "^6.22.0", - "babel-plugin-transform-es2015-literals": "^6.22.0", - "babel-plugin-transform-es2015-modules-amd": "^6.22.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", - "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", - "babel-plugin-transform-es2015-modules-umd": "^6.23.0", - "babel-plugin-transform-es2015-object-super": "^6.22.0", - "babel-plugin-transform-es2015-parameters": "^6.23.0", - "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", - "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", - "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", - "babel-plugin-transform-exponentiation-operator": "^6.22.0", - "babel-plugin-transform-regenerator": "^6.22.0", - "browserslist": "^3.2.6", - "invariant": "^2.2.2", - "semver": "^5.3.0" - } - }, - "babel-preset-es2015": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", - "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", - "requires": { - "babel-plugin-check-es2015-constants": "^6.22.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.24.1", - "babel-plugin-transform-es2015-classes": "^6.24.1", - "babel-plugin-transform-es2015-computed-properties": "^6.24.1", - "babel-plugin-transform-es2015-destructuring": "^6.22.0", - "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1", - "babel-plugin-transform-es2015-for-of": "^6.22.0", - "babel-plugin-transform-es2015-function-name": "^6.24.1", - "babel-plugin-transform-es2015-literals": "^6.22.0", - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1", - "babel-plugin-transform-es2015-modules-umd": "^6.24.1", - "babel-plugin-transform-es2015-object-super": "^6.24.1", - "babel-plugin-transform-es2015-parameters": "^6.24.1", - "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "^6.24.1", - "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0", - "babel-plugin-transform-es2015-unicode-regex": "^6.24.1", - "babel-plugin-transform-regenerator": "^6.24.1" - } - }, - "babel-preset-flow": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz", - "integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=", - "requires": { - "babel-plugin-transform-flow-strip-types": "^6.22.0" - } - }, - "babel-preset-react": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz", - "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=", - "requires": { - "babel-plugin-syntax-jsx": "^6.3.13", - "babel-plugin-transform-react-display-name": "^6.23.0", - "babel-plugin-transform-react-jsx": "^6.24.1", - "babel-plugin-transform-react-jsx-self": "^6.22.0", - "babel-plugin-transform-react-jsx-source": "^6.22.0", - "babel-preset-flow": "^6.23.0" - } - }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - } - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base-x": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.4.tgz", - "integrity": "sha512-UYOadoSIkEI/VrRGSG6qp93rp2WdokiAiNYDfGW5qURAY8GiAQkvMbwNNSDYiVJopqv4gCna7xqf4rrNGp+5AA==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" - }, - "bchaddrjs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/bchaddrjs/-/bchaddrjs-0.2.1.tgz", - "integrity": "sha512-esOfL+EnG+qPgqAPl4NxWngDIJIEs35dcV6wU0NP6bxBtc363fYm7xhNtC1BRVagDLSbMNwyI27rkWXwN5i6yg==", - "requires": { - "bs58check": "^2.1.1", - "cashaddrjs": "^0.2.7" - } - }, - "bech32": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.3.tgz", - "integrity": "sha512-yuVFUvrNcoJi0sv5phmqc6P+Fl1HjRDRNOOkHY2X/3LBy2bIGNSFx4fZ95HMaXHupuS7cZR15AsvtmCIF4UEyg==" - }, - "big-integer": { - "version": "1.6.31", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.31.tgz", - "integrity": "sha512-lDbZNHHwxDKnjP7LWg2leO+tjs4SyVs2Z83dsR1Idbe2urRnxZAUdeQ8YBhHaGaWK/4WM3mz+RlbZsgqck17CA==" - }, - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" - }, - "bigi": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/bigi/-/bigi-1.4.2.tgz", - "integrity": "sha1-nGZalfiLiwj8Bc/XMfVhhZ1yWCU=" - }, - "binary-extensions": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", - "optional": true - }, - "bindings": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz", - "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==" - }, - "bip21": { - "version": "github:Bitcoin-com/bip21#28f8d03a3a16ed11eb5b963248ed1be8c46c6d6f", - "from": "github:Bitcoin-com/bip21", - "requires": { - "qs": "^6.3.0" - } - }, - "bip38": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bip38/-/bip38-2.0.2.tgz", - "integrity": "sha512-22KDak0RDyghFbR0Si7wyq9IgY423YzGYzWLpGeofH3DaolOQqjD3mNN08eFoubKlbyclOQKFwtONMv2SD9V3A==", - "requires": { - "bigi": "^1.2.0", - "browserify-aes": "^1.0.1", - "bs58check": "<3.0.0", - "buffer-xor": "^1.0.2", - "create-hash": "^1.1.1", - "ecurve": "^1.0.0", - "scryptsy": "^2.0.0" - } - }, - "bip39": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/bip39/-/bip39-2.5.0.tgz", - "integrity": "sha512-xwIx/8JKoT2+IPJpFEfXoWdYwP7UVAoUxxLNfGCfVowaJE7yg1Y5B1BVPqlUNsBq5/nGwmFkwRJ8xDW4sX8OdA==", - "requires": { - "create-hash": "^1.1.0", - "pbkdf2": "^3.0.9", - "randombytes": "^2.0.1", - "safe-buffer": "^5.0.1", - "unorm": "^1.3.3" - } - }, - "bip66": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", - "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "bip68": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/bip68/-/bip68-1.0.4.tgz", - "integrity": "sha512-O1htyufFTYy3EO0JkHg2CLykdXEtV2ssqw47Gq9A0WByp662xpJnMEB9m43LZjsSDjIAOozWRExlFQk2hlV1XQ==" - }, - "bitcoin-ops": { - "version": "github:Bitcoin-com/bitcoincash-ops#d62a0a12ce227a63222282b5f4e9a7a23a5a6b38", - "from": "github:Bitcoin-com/bitcoincash-ops" - }, - "bitcoincashjs-lib": { - "version": "github:Bitcoin-com/bitcoincashjs-lib#0a7fc7cf23551503f57689db4c930b8136db954c", - "from": "github:Bitcoin-com/bitcoincashjs-lib", - "requires": { - "bech32": "^1.1.2", - "bigi": "^1.4.0", - "bip66": "^1.1.0", - "bitcoin-ops": "^1.3.0", - "bs58check": "^2.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.3", - "ecurve": "^1.0.0", - "merkle-lib": "^2.0.10", - "pushdata-bitcoin": "^1.0.1", - "randombytes": "^2.0.1", - "safe-buffer": "^5.0.1", - "typeforce": "^1.11.3", - "varuint-bitcoin": "^1.0.4", - "wif": "^2.0.1" - } - }, - "bitcoinjs-message": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/bitcoinjs-message/-/bitcoinjs-message-2.0.0.tgz", - "integrity": "sha512-H5pJC7/eSqVjREiEOZ4jifX+7zXYP3Y28GIOIqg9hrgE7Vj8Eva9+HnVqnxwA1rJPOwZKuw0vo6k0UxgVc6q1A==", - "requires": { - "bs58check": "^2.0.2", - "buffer-equals": "^1.0.3", - "create-hash": "^1.1.2", - "secp256k1": "^3.0.1", - "varuint-bitcoin": "^1.0.1" - } - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" - }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "requires": { - "hoek": "2.x.x" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "optional": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserslist": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", - "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", - "requires": { - "caniuse-lite": "^1.0.30000844", - "electron-to-chromium": "^1.3.47" - } - }, - "bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", - "requires": { - "base-x": "^3.0.2" - } - }, - "bs58check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.1.tgz", - "integrity": "sha512-okRQiWc5FJuA2VOwQ1hB7Sf0MyEFg/EwRN12h4b8HrJoGkZ3xq1CGjkaAfYloLcZyqixQnO5mhPpN6IcHSplVg==", - "requires": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0" - } - }, - "buffer": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.1.0.tgz", - "integrity": "sha512-YkIRgwsZwJWTnyQrsBTWefizHh+8GYj3kbL1BTiAQ/9pwpino0G7B2gp5tx/FUBqUlvtxV85KNR3mwfAtv15Yw==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "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-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - }, - "can-promise": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/can-promise/-/can-promise-0.0.1.tgz", - "integrity": "sha512-gzVrHyyrvgt0YpDm7pn04MQt8gjh0ZAhN4ZDyCRtGl6YnuuK6b4aiUTD7G52r9l4YNmxfTtEscb92vxtAlL6XQ==", - "requires": { - "window-or-global": "^1.0.1" - } - }, - "caniuse-lite": { - "version": "1.0.30000855", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000855.tgz", - "integrity": "sha512-ajORrkXa5UYk62P5PK6ZmBraYOAOr9HWy+XxLwjDg8Ys/5KiSyarg8tIA32ZVqbFhtz67wyySXnU9imkh2ZT2w==" - }, - "cashaddrjs": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/cashaddrjs/-/cashaddrjs-0.2.8.tgz", - "integrity": "sha512-oezXpKZRjavdRB1QjBamfHFDzYescGFn9dWMbijP4fgXrqMdBygOqaPNW4phf7zpRD4+oW7aaFfFklF72/szaA==", - "requires": { - "big-integer": "^1.6.26" - } - }, - "chai": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", - "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", - "dev": true, - "requires": { - "assertion-error": "^1.0.1", - "check-error": "^1.0.1", - "deep-eql": "^3.0.0", - "get-func-name": "^2.0.0", - "pathval": "^1.0.0", - "type-detect": "^4.0.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true - }, - "chokidar": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", - "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", - "optional": true, - "requires": { - "anymatch": "^1.3.0", - "async-each": "^1.0.0", - "fsevents": "^1.0.0", - "glob-parent": "^2.0.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^2.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0" - } - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "clear": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clear/-/clear-0.0.1.tgz", - "integrity": "sha1-5RhuIp2ZRIF5wTAxG2+dML/2sLo=" - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "coininfo": { - "version": "github:Bitcoin-com/coininfo#eece2c6141d08c3e7783929f2a1e1e681aa1a82c", - "from": "github:Bitcoin-com/coininfo", - "requires": { - "safe-buffer": "^5.1.1" - } - }, - "color-convert": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", - "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", - "requires": { - "color-name": "1.1.1" - } - }, - "color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" - }, - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "convert-source-map": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=" - }, - "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "corsproxy": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/corsproxy/-/corsproxy-1.5.0.tgz", - "integrity": "sha1-KUge0hXuWxvWkkx5Fc+I/LE8EGE=", - "requires": { - "ejs": "^2.3.3", - "good": "^6.3.0", - "good-console": "^5.0.3", - "h2o2": "^4.0.1", - "hapi": "^9.0.2", - "hapi-cors-headers": "^1.0.0", - "http-proxy": "~1.11", - "inert": "^3.0.1", - "vision": "^3.0.0" - } - }, - "cp-file": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-5.0.0.tgz", - "integrity": "sha1-vHAP0wyjLSTUbH+wK5kuQ1/FqXg=", - "requires": { - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "nested-error-stacks": "^2.0.0", - "pify": "^3.0.0", - "safe-buffer": "^5.0.1" - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - } - } - }, - "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" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "requires": { - "repeating": "^2.0.0" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" - }, - "dijkstrajs": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.1.tgz", - "integrity": "sha1-082BIh4+pAdCz83lVtTpnpjdxxs=" - }, - "drbg.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", - "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", - "requires": { - "browserify-aes": "^1.0.6", - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4" - } - }, - "ecurve": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/ecurve/-/ecurve-1.0.6.tgz", - "integrity": "sha512-/BzEjNfiSuB7jIWKcS/z8FK9jNjmEWvUV2YZ4RLSmcDtP7Lq0m6FvDuSnJpBlDpGRpfRQeTLGLBI8H+kEv0r+w==", - "requires": { - "bigi": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "ejs": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz", - "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==" - }, - "electron-to-chromium": { - "version": "1.3.48", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.48.tgz", - "integrity": "sha1-07DYWTgUBE4JLs4hCPw6ya6kuQA=" - }, - "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "eventemitter3": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", - "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=" - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "optional": true, - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "optional": true, - "requires": { - "fill-range": "^2.1.0" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "optional": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "figlet": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.2.0.tgz", - "integrity": "sha1-bEZTc3j6tkkUa1phQ92gGbQwtBA=" - }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "optional": true - }, - "fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "optional": true, - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "requires": { - "locate-path": "^2.0.0" - } - }, - "flow-bin": { - "version": "0.64.0", - "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.64.0.tgz", - "integrity": "sha1-3dP7Oxg6sas1pdXeycr167ze0Wc=", - "dev": true - }, - "follow-redirects": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.0.tgz", - "integrity": "sha512-fdrt472/9qQ6Kgjvb935ig6vJCuofpBUD14f9Vb+SLlm7xIe4Qva5gey8EKtv8lp7ahE1wilg3xL1znpVGtZIA==", - "requires": { - "debug": "^3.1.0" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "optional": true - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "optional": true, - "requires": { - "for-in": "^1.0.1" - } - }, - "fs-readdir-recursive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", - "optional": true, - "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "debug": { - "version": "2.6.9", - "bundled": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.5.1", - "bundled": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.21", - "bundled": true, - "optional": true, - "requires": { - "safer-buffer": "^2.1.0" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "minipass": { - "version": "2.2.4", - "bundled": true, - "requires": { - "safe-buffer": "^5.1.1", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.1.0", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "needle": { - "version": "2.2.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.10.0", - "bundled": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.3", - "bundled": true, - "optional": true - }, - "npm-packlist": { - "version": "1.1.10", - "bundled": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.7", - "bundled": true, - "optional": true, - "requires": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "optional": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-buffer": { - "version": "5.1.1", - "bundled": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "optional": true - }, - "semver": { - "version": "5.5.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "4.4.1", - "bundled": true, - "optional": true, - "requires": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "optional": true, - "requires": { - "string-width": "^1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - }, - "yallist": { - "version": "3.0.2", - "bundled": true - } - } - }, - "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=" - }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" - }, - "git-clone": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/git-clone/-/git-clone-0.1.0.tgz", - "integrity": "sha1-DXYWN3gJOu9/HDAjjyqe8/B6Lrk=" - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "optional": true, - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - } - }, - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "requires": { - "is-glob": "^2.0.0" - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" - }, - "good": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/good/-/good-6.6.3.tgz", - "integrity": "sha1-B9zIEfwSuDmKnDMezdM37OWogDU=", - "requires": { - "hoek": "2.x.x", - "items": "1.x.x", - "joi": "6.x.x", - "traverse": "0.6.6", - "wreck": "6.x.x" - } - }, - "good-console": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/good-console/-/good-console-5.3.2.tgz", - "integrity": "sha1-f8c9RDfiWsToODJB5GaWy6N0ia0=", - "requires": { - "good-squeeze": "2.x.x", - "hoek": "2.x.x", - "json-stringify-safe": "5.0.x", - "moment": "2.11.x", - "through2": "0.6.x" - }, - "dependencies": { - "moment": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.11.2.tgz", - "integrity": "sha1-h5aOX5WsA4wuQqyVnHWBnNP1KQE=" - } - } - }, - "good-squeeze": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/good-squeeze/-/good-squeeze-2.1.0.tgz", - "integrity": "sha1-mc7pHSbVkWmKiZwo6TELzzxq4oo=", - "requires": { - "hoek": "2.x.x", - "json-stringify-safe": "5.0.x" - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" - }, - "h2o2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/h2o2/-/h2o2-4.0.2.tgz", - "integrity": "sha1-h8uWDcD1tJWWT6koJT5s8TuiJIY=", - "requires": { - "boom": "2.x.x", - "hoek": "2.x.x", - "joi": "6.x.x", - "wreck": "6.x.x" - } - }, - "hapi": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/hapi/-/hapi-9.5.1.tgz", - "integrity": "sha1-jYyhPnwiCweEZemgp2QPJqWvuFU=", - "requires": { - "accept": "1.x.x", - "ammo": "1.x.x", - "boom": "^2.5.x", - "call": "2.x.x", - "catbox": "6.x.x", - "catbox-memory": "1.x.x", - "cryptiles": "2.x.x", - "heavy": "3.x.x", - "hoek": "^2.14.x", - "iron": "2.x.x", - "items": "1.x.x", - "joi": "^6.8.1", - "kilt": "^1.1.x", - "mimos": "2.x.x", - "peekaboo": "1.x.x", - "qs": "4.x.x", - "shot": "^1.7.x", - "statehood": "2.x.x", - "subtext": "2.x.x", - "topo": "^1.1.x" - }, - "dependencies": { - "accept": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/accept/-/accept-1.1.0.tgz", - "integrity": "sha1-x7VWfJmt5Kx8k38qm8HFZhYKMLU=", - "requires": { - "boom": "2.x.x", - "hoek": "2.x.x" - } - }, - "ammo": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ammo/-/ammo-1.0.1.tgz", - "integrity": "sha1-j4rdFM1Jve3jurOj4OvK8h0D3os=", - "requires": { - "boom": "2.x.x", - "hoek": "2.x.x" - } - }, - "boom": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.9.0.tgz", - "integrity": "sha1-pUt/0v7kd9NRv543FoDL6mfxJxU=", - "requires": { - "hoek": "2.x.x" - } - }, - "call": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/call/-/call-2.0.2.tgz", - "integrity": "sha1-nJgxq9B2lIb97oOkEUm4KbMtBsA=", - "requires": { - "boom": "2.x.x", - "hoek": "2.x.x" - } - }, - "catbox": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/catbox/-/catbox-6.0.0.tgz", - "integrity": "sha1-6i8pT6Bemvx+IhDTI/XeU6OAQ+c=", - "requires": { - "boom": "2.x.x", - "hoek": "2.x.x", - "joi": "6.x.x" - } - }, - "catbox-memory": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/catbox-memory/-/catbox-memory-1.1.2.tgz", - "integrity": "sha1-M8kYOjKzGUXuikhNDjw8u4Lq7Bo=", - "requires": { - "hoek": "2.x.x" - } - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "requires": { - "boom": "2.x.x" - } - }, - "heavy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/heavy/-/heavy-3.0.1.tgz", - "integrity": "sha1-8oZ+bjUVv4OrGoux5z5dKOhas80=", - "requires": { - "boom": "2.x.x", - "hoek": "2.x.x", - "joi": "6.x.x" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" - }, - "iron": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/iron/-/iron-2.1.3.tgz", - "integrity": "sha1-cbjzV9gGquA6kKdFuaqv/sfi3eQ=", - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x" - } - }, - "items": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/items/-/items-1.1.0.tgz", - "integrity": "sha1-rZ1VhAsimGDLPRYLMidMLUvZ4mI=" - }, - "joi": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-6.8.1.tgz", - "integrity": "sha1-g94tYCj8DNXRYi8/V0fKCCtHjv8=", - "requires": { - "hoek": "2.x.x", - "isemail": "1.x.x", - "moment": "2.x.x", - "topo": "1.x.x" - }, - "dependencies": { - "isemail": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", - "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=" - }, - "moment": { - "version": "2.10.6", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.10.6.tgz", - "integrity": "sha1-bLIZZ8ecunsMpeZmRPFzZis++nc=" - } - } - }, - "kilt": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/kilt/-/kilt-1.1.1.tgz", - "integrity": "sha1-d7SmFjyn+lshN6iMFzNCFuwj1ds=", - "requires": { - "hoek": "2.x.x" - } - }, - "mimos": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/mimos/-/mimos-2.0.2.tgz", - "integrity": "sha1-wyQXF+dblZkr54esfdbbGptTmx4=", - "requires": { - "hoek": "2.x.x", - "mime-db": "1.x.x" - }, - "dependencies": { - "mime-db": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.19.0.tgz", - "integrity": "sha1-SWoYGYp86CRFNOJbsQK3T7Qg/VY=" - } - } - }, - "peekaboo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/peekaboo/-/peekaboo-1.0.0.tgz", - "integrity": "sha1-wNspJq1lTSygH3ymUKtFkadk/EI=" - }, - "qs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz", - "integrity": "sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc=" - }, - "shot": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/shot/-/shot-1.7.0.tgz", - "integrity": "sha1-8jKdfvM6/PA9RM5Bq66BSK4XBTI=", - "requires": { - "hoek": "2.x.x" - } - }, - "statehood": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/statehood/-/statehood-2.1.1.tgz", - "integrity": "sha1-AfFwtmxeklqvZ5qdMiulkYb8AAk=", - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "iron": "2.x.x", - "items": "1.x.x", - "joi": "6.x.x" - } - }, - "subtext": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/subtext/-/subtext-2.0.0.tgz", - "integrity": "sha1-I5lQ6SCBQ/FUirJeHJV5vbaNiU4=", - "requires": { - "boom": "2.x.x", - "content": "1.x.x", - "hoek": "2.x.x", - "pez": "1.x.x", - "qs": "4.x.x", - "wreck": "6.x.x" - }, - "dependencies": { - "content": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/content/-/content-1.0.2.tgz", - "integrity": "sha1-y37fMq/vF8SKz9vSH/mMIzFa6CQ=", - "requires": { - "boom": "2.x.x", - "hoek": "2.x.x" - } - }, - "pez": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pez/-/pez-1.0.0.tgz", - "integrity": "sha1-hEMYpc5wku7d/6KV4YB5rHefoBg=", - "requires": { - "b64": "2.x.x", - "boom": "2.x.x", - "content": "1.x.x", - "hoek": "2.x.x", - "nigel": "1.x.x" - }, - "dependencies": { - "b64": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/b64/-/b64-2.0.1.tgz", - "integrity": "sha1-0IwQcZcZ/x/htTKuSSaUCc4UnOk=", - "requires": { - "hoek": "2.x.x" - } - }, - "nigel": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/nigel/-/nigel-1.0.1.tgz", - "integrity": "sha1-RjmJr4gSePuqHTzJOCPb0XtDYKE=", - "requires": { - "hoek": "2.x.x", - "vise": "1.x.x" - }, - "dependencies": { - "vise": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/vise/-/vise-1.0.0.tgz", - "integrity": "sha1-KDRb5N5aNB4V/SgW/Z6j5zA+jfM=", - "requires": { - "hoek": "2.x.x" - } - } - } - } - } - }, - "wreck": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wreck/-/wreck-6.2.0.tgz", - "integrity": "sha1-8Jkx7UcbZL6Yjj57u4gjTa4i0iI=", - "requires": { - "boom": "2.x.x", - "hoek": "2.x.x" - } - } - } - }, - "topo": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", - "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=", - "requires": { - "hoek": "2.x.x" - } - } - } - }, - "hapi-cors-headers": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/hapi-cors-headers/-/hapi-cors-headers-1.0.3.tgz", - "integrity": "sha512-U/y+kpVLUJ0y86fEk8yleou9C1T5wFopcWQjuxKdMXzCcymTjfSqGz59waqvngUs1SbeXav/y8Ga9C0G0L1MGg==" - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "hash.js": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.4.tgz", - "integrity": "sha512-A6RlQvvZEtFS5fLU43IDu0QUmBy+fDO9VMdTXvufKwIkt/rFfvICAViCax5fbDO4zdNzaC3/27ZhKUok5bAJyw==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - } - } - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, - "hosted-git-info": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", - "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==" - }, - "http-proxy": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.11.3.tgz", - "integrity": "sha1-GRXciIdR4qa/PCq/yxgI+obHI1M=", - "requires": { - "eventemitter3": "1.x.x", - "requires-port": "0.x.x" - } - }, - "ieee754": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", - "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==" - }, - "inert": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/inert/-/inert-3.2.1.tgz", - "integrity": "sha1-xJZcXhh87z2yxChy5S51cAh2Qn0=", - "requires": { - "ammo": "1.x.x", - "boom": "2.x.x", - "hoek": "2.x.x", - "items": "1.x.x", - "joi": "^6.7.x", - "lru-cache": "2.7.x" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "optional": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "requires": { - "builtin-modules": "^1.0.0" - } - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "optional": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "optional": true, - "requires": { - "is-primitive": "^2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "optional": true - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "optional": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "optional": true - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "optional": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isemail": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", - "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "optional": true, - "requires": { - "isarray": "1.0.0" - } - }, - "items": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/items/-/items-1.1.1.tgz", - "integrity": "sha1-Q1td0hvKKLPP0lu1xrJ4txUBD9k=" - }, - "joi": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", - "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=", - "requires": { - "hoek": "2.x.x", - "isemail": "1.x.x", - "moment": "2.x.x", - "topo": "1.x.x" - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - }, - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" - }, - "just-extend": { - "version": "1.1.27", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "requires": { - "invert-kv": "^1.0.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - } - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, - "lodash.toarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", - "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" - }, - "lolex": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.0.tgz", - "integrity": "sha512-uJkH2e0BVfU5KOJUevbTOtpDduooSarH5PopO+LfM/vZf8Z9sJzODqKev804JYM2i++ktJfUmC1le4LwFQ1VMg==", - "dev": true - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "requires": { - "js-tokens": "^3.0.0" - } - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=" - }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "requires": { - "pify": "^3.0.0" - } - }, - "math-random": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", - "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", - "optional": true - }, - "md5.js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", - "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "mem": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "merkle-lib": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/merkle-lib/-/merkle-lib-2.0.10.tgz", - "integrity": "sha1-grjbrnXieneFOItz+ddyXQ9vMyY=" - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "optional": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", - "requires": { - "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.2", - "growl": "1.10.5", - "he": "1.1.1", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "supports-color": "5.4.0" - }, - "dependencies": { - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "moment": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", - "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "nan": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" - }, - "nested-error-stacks": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.0.1.tgz", - "integrity": "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==" - }, - "nise": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.1.tgz", - "integrity": "sha512-9JX3YwoIt3kS237scmSSOpEv7vCukVzLfwK0I0XhocDSHUANid8ZHnLEULbbSkfeMn98B2y5kphIWzZUylESRQ==", - "dev": true, - "requires": { - "@sinonjs/formatio": "^2.0.0", - "just-extend": "^1.1.27", - "lolex": "^2.3.2", - "path-to-regexp": "^1.7.0", - "text-encoding": "^0.6.4" - } - }, - "node-cmd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/node-cmd/-/node-cmd-3.0.0.tgz", - "integrity": "sha1-OP/3CkqqT2WdID61eGJzcBjiT28=" - }, - "node-emoji": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.8.1.tgz", - "integrity": "sha512-+ktMAh1Jwas+TnGodfCfjUbJKoANqPaJFN0z0iqh41eqD8dvguNzcitVSBSVK1pidz0AqGbLKcoVuVLRVZ/aVg==", - "requires": { - "lodash.toarray": "^4.4.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.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "nyc": { - "version": "11.9.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.9.0.tgz", - "integrity": "sha512-w8OdJAhXL5izerzZMdqzYKMj/pgHJyY3qEPYBjLLxrhcVoHEY9pU5ENIiZyCgG9OR7x3VcUMoD40o6PtVpfR4g==", - "dev": true, - "requires": { - "archy": "^1.0.0", - "arrify": "^1.0.1", - "caching-transform": "^1.0.0", - "convert-source-map": "^1.5.1", - "debug-log": "^1.0.1", - "default-require-extensions": "^1.0.0", - "find-cache-dir": "^0.1.1", - "find-up": "^2.1.0", - "foreground-child": "^1.5.3", - "glob": "^7.0.6", - "istanbul-lib-coverage": "^1.1.2", - "istanbul-lib-hook": "^1.1.0", - "istanbul-lib-instrument": "^1.10.0", - "istanbul-lib-report": "^1.1.3", - "istanbul-lib-source-maps": "^1.2.3", - "istanbul-reports": "^1.4.0", - "md5-hex": "^1.2.0", - "merge-source-map": "^1.1.0", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.0", - "resolve-from": "^2.0.0", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.1", - "spawn-wrap": "^1.4.2", - "test-exclude": "^4.2.0", - "yargs": "11.1.0", - "yargs-parser": "^8.0.0" - }, - "dependencies": { - "align-text": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - } - }, - "amdefine": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "bundled": true, - "dev": true - }, - "append-transform": { - "version": "0.4.0", - "bundled": true, - "dev": true, - "requires": { - "default-require-extensions": "^1.0.0" - } - }, - "archy": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "arr-diff": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "bundled": true, - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "bundled": true, - "dev": true - }, - "arrify": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "async": { - "version": "1.5.2", - "bundled": true, - "dev": true - }, - "atob": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "babel-code-frame": { - "version": "6.26.0", - "bundled": true, - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, - "babel-generator": { - "version": "6.26.1", - "bundled": true, - "dev": true, - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - } - }, - "babel-messages": { - "version": "6.23.0", - "bundled": true, - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-runtime": { - "version": "6.26.0", - "bundled": true, - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "bundled": true, - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "bundled": true, - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - } - }, - "babel-types": { - "version": "6.26.0", - "bundled": true, - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "bundled": true, - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "base": { - "version": "0.11.2", - "bundled": true, - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "builtin-modules": { - "version": "1.1.1", - "bundled": true, - "dev": true - }, - "cache-base": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "caching-transform": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "md5-hex": "^1.2.0", - "mkdirp": "^0.5.1", - "write-file-atomic": "^1.1.4" - } - }, - "camelcase": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true - }, - "center-align": { - "version": "0.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, - "chalk": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "class-utils": { - "version": "0.3.6", - "bundled": true, - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "cliui": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.2", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "collection-visit": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "commondir": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "component-emitter": { - "version": "1.2.1", - "bundled": true, - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "convert-source-map": { - "version": "1.5.1", - "bundled": true, - "dev": true - }, - "copy-descriptor": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "core-js": { - "version": "2.5.6", - "bundled": true, - "dev": true - }, - "cross-spawn": { - "version": "4.0.2", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "debug": { - "version": "2.6.9", - "bundled": true, - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "debug-log": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "decamelize": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "bundled": true, - "dev": true - }, - "default-require-extensions": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "strip-bom": "^2.0.0" - } - }, - "define-property": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "detect-indent": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "error-ex": { - "version": "1.3.1", - "bundled": true, - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true, - "dev": true - }, - "esutils": { - "version": "2.0.2", - "bundled": true, - "dev": true - }, - "execa": { - "version": "0.7.0", - "bundled": true, - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "extend-shallow": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "fill-range": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "find-cache-dir": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "requires": { - "commondir": "^1.0.1", - "mkdirp": "^0.5.1", - "pkg-dir": "^1.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "for-in": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "foreground-child": { - "version": "1.5.6", - "bundled": true, - "dev": true, - "requires": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" - } - }, - "fragment-cache": { - "version": "0.2.1", - "bundled": true, - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "get-caller-file": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "get-value": { - "version": "2.0.6", - "bundled": true, - "dev": true - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globals": { - "version": "9.18.0", - "bundled": true, - "dev": true - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "handlebars": { - "version": "4.0.11", - "bundled": true, - "dev": true, - "requires": { - "async": "^1.4.0", - "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" - }, - "dependencies": { - "source-map": { - "version": "0.4.4", - "bundled": true, - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, - "has-ansi": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "has-value": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "has-values": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hosted-git-info": { - "version": "2.6.0", - "bundled": true, - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true, - "dev": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "invariant": { - "version": "2.2.4", - "bundled": true, - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-arrayish": { - "version": "0.2.1", - "bundled": true, - "dev": true - }, - "is-buffer": { - "version": "1.1.6", - "bundled": true, - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "bundled": true, - "dev": true - } - } - }, - "is-extendable": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "is-finite": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "is-number": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-odd": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "bundled": true, - "dev": true - } - } - }, - "is-plain-object": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "isobject": "^3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "is-stream": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "is-utf8": { - "version": "0.2.1", - "bundled": true, - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "istanbul-lib-coverage": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "istanbul-lib-hook": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "append-transform": "^0.4.0" - } - }, - "istanbul-lib-instrument": { - "version": "1.10.1", - "bundled": true, - "dev": true, - "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.0", - "semver": "^5.3.0" - } - }, - "istanbul-lib-report": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "requires": { - "istanbul-lib-coverage": "^1.1.2", - "mkdirp": "^0.5.1", - "path-parse": "^1.0.5", - "supports-color": "^3.1.2" - }, - "dependencies": { - "supports-color": { - "version": "3.2.3", - "bundled": true, - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "1.2.3", - "bundled": true, - "dev": true, - "requires": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.1.2", - "mkdirp": "^0.5.1", - "rimraf": "^2.6.1", - "source-map": "^0.5.3" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "istanbul-reports": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "handlebars": "^4.0.3" - } - }, - "js-tokens": { - "version": "3.0.2", - "bundled": true, - "dev": true - }, - "jsesc": { - "version": "1.3.0", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, - "lazy-cache": { - "version": "1.0.4", - "bundled": true, - "dev": true, - "optional": true - }, - "lcid": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "invert-kv": "^1.0.0" - } - }, - "load-json-file": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "bundled": true, - "dev": true - } - } - }, - "lodash": { - "version": "4.17.10", - "bundled": true, - "dev": true - }, - "longest": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "loose-envify": { - "version": "1.3.1", - "bundled": true, - "dev": true, - "requires": { - "js-tokens": "^3.0.0" - } - }, - "lru-cache": { - "version": "4.1.3", - "bundled": true, - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "map-cache": { - "version": "0.2.2", - "bundled": true, - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "md5-hex": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "md5-o-matic": "^0.1.1" - } - }, - "md5-o-matic": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "mem": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "merge-source-map": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "bundled": true, - "dev": true - } - } - }, - "micromatch": { - "version": "3.1.10", - "bundled": true, - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "mimic-fn": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "mixin-deep": { - "version": "1.3.1", - "bundled": true, - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "nanomatch": { - "version": "1.2.9", - "bundled": true, - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "normalize-package-data": { - "version": "2.4.0", - "bundled": true, - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "npm-run-path": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "bundled": true, - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "object-visit": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "isobject": "^3.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "object.pick": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "isobject": "^3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optimist": { - "version": "0.6.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "os-locale": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, - "p-finally": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "p-limit": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "parse-json": { - "version": "2.2.0", - "bundled": true, - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "pascalcase": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "path-exists": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "path-key": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "path-parse": { - "version": "1.0.5", - "bundled": true, - "dev": true - }, - "path-type": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "bundled": true, - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "bundled": true, - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "find-up": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - } - } - }, - "posix-character-classes": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "read-pkg": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - } - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "bundled": true, - "dev": true - }, - "regex-not": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "repeat-element": { - "version": "1.1.2", - "bundled": true, - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "bundled": true, - "dev": true - }, - "repeating": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, - "require-directory": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "resolve-from": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "bundled": true, - "dev": true - }, - "ret": { - "version": "0.1.15", - "bundled": true, - "dev": true - }, - "right-align": { - "version": "0.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "align-text": "^0.1.1" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "dev": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-regex": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "semver": { - "version": "5.5.0", - "bundled": true, - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "set-value": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true - }, - "slide": { - "version": "1.1.6", - "bundled": true, - "dev": true - }, - "snapdragon": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.2.0" - } - }, - "source-map": { - "version": "0.5.7", - "bundled": true, - "dev": true - }, - "source-map-resolve": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "atob": "^2.0.0", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-url": { - "version": "0.4.0", - "bundled": true, - "dev": true - }, - "spawn-wrap": { - "version": "1.4.2", - "bundled": true, - "dev": true, - "requires": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" - } - }, - "spdx-correct": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "bundled": true, - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "split-string": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "static-extend": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "string-width": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-bom": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "test-exclude": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "requires": { - "arrify": "^1.0.1", - "micromatch": "^3.1.8", - "object-assign": "^4.1.0", - "read-pkg-up": "^1.0.1", - "require-main-filename": "^1.0.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "bundled": true, - "dev": true - }, - "braces": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "bundled": true, - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "bundled": true, - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } - } - }, - "to-fast-properties": { - "version": "1.0.3", - "bundled": true, - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "to-regex": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - } - } - }, - "trim-right": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "uglify-js": { - "version": "2.8.29", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "yargs": { - "version": "3.10.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "union-value": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } - } - }, - "unset-value": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "bundled": true, - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "bundled": true, - "dev": true - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "urix": { - "version": "0.1.0", - "bundled": true, - "dev": true - }, - "use": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "validate-npm-package-license": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "which": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "window-size": { - "version": "0.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "wordwrap": { - "version": "0.0.3", - "bundled": true, - "dev": true - }, - "wrap-ansi": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "write-file-atomic": { - "version": "1.3.4", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" - } - }, - "y18n": { - "version": "3.2.1", - "bundled": true, - "dev": true - }, - "yallist": { - "version": "2.1.2", - "bundled": true, - "dev": true - }, - "yargs": { - "version": "11.1.0", - "bundled": true, - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "camelcase": { - "version": "4.1.0", - "bundled": true, - "dev": true - }, - "cliui": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "yargs-parser": { - "version": "9.0.2", - "bundled": true, - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "8.1.0", - "bundled": true, - "dev": true, - "requires": { - "camelcase": "^4.1.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "bundled": true, - "dev": true - } - } - } - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "optional": true, - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "output-file-sync": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz", - "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=", - "requires": { - "graceful-fs": "^4.1.4", - "mkdirp": "^0.5.1", - "object-assign": "^4.1.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "optional": true, - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, - "path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", - "dev": true, - "requires": { - "isarray": "0.0.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - } - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "requires": { - "pify": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - } - } - }, - "pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", - "dev": true - }, - "pbkdf2": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz", - "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==", - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "pngjs": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.3.3.tgz", - "integrity": "sha512-1n3Z4p3IOxArEs1VRXnZ/RXdfEniAUS9jb68g58FIXMNkPJeZd+Qh4Uq7/e0LVxAQGos1eIUrqrt4FpjdnEd+Q==" - }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "optional": true - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "optional": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "pushdata-bitcoin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz", - "integrity": "sha1-FZMdPNlnreUiBvUjqnMxrvfUOvc=", - "requires": { - "bitcoin-ops": "^1.3.0" - } - }, - "qrcode": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.2.0.tgz", - "integrity": "sha512-wZK0Z0eYmOUDP2tOGzmLdeBn5Npa+4wms9GdvzH7HrywvGUq/Stz0BKUhW4DfmBf1PSrm9dNfdnVDq683Zxvag==", - "requires": { - "can-promise": "^0.0.1", - "dijkstrajs": "^1.0.1", - "isarray": "^2.0.1", - "pngjs": "^3.3.0", - "yargs": "^8.0.2" - }, - "dependencies": { - "isarray": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz", - "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==" - } - } - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "randomatic": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz", - "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==", - "optional": true, - "requires": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "optional": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "optional": true - } - } - }, - "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "optional": true - } - } - }, - "readdirp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", - "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", - "optional": true, - "requires": { - "graceful-fs": "^4.1.2", - "minimatch": "^3.0.2", - "readable-stream": "^2.0.2", - "set-immediate-shim": "^1.0.1" - } - }, - "regenerate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "regenerator-transform": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", - "requires": { - "babel-runtime": "^6.18.0", - "babel-types": "^6.19.0", - "private": "^0.1.6" - } - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "optional": true, - "requires": { - "is-equal-shallow": "^0.1.3" - } - }, - "regexpu-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", - "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", - "requires": { - "regenerate": "^1.2.1", - "regjsgen": "^0.2.0", - "regjsparser": "^0.1.4" - } - }, - "regjsgen": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" - }, - "regjsparser": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" - } - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" - }, - "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "optional": true - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "requires": { - "is-finite": "^1.0.0" - } - }, - "repl.history": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/repl.history/-/repl.history-0.1.4.tgz", - "integrity": "sha1-gDZxcfN4HW5CmccXWMJTCX9dWDI=" - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" - }, - "requires-port": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-0.0.1.tgz", - "integrity": "sha1-S0QUQR2d98hVmV3YmajHiilRwW0=" - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "samsam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", - "dev": true - }, - "satoshi-bitcoin": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/satoshi-bitcoin/-/satoshi-bitcoin-1.0.4.tgz", - "integrity": "sha1-0AK2dwddXLvywhGo3zJUvN9QseQ=", - "requires": { - "big.js": "^3.1.3" - } - }, - "scryptsy": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-2.0.0.tgz", - "integrity": "sha1-Jiw28CMc+nZU4jY/o5TNLexm83g=" - }, - "secp256k1": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.5.0.tgz", - "integrity": "sha512-e5QIJl8W7Y4tT6LHffVcZAxJjvpgE5Owawv6/XCYPQljE9aP2NFFddQ8OYMKhdLshNu88FfL3qCN3/xYkXGRsA==", - "requires": { - "bindings": "^1.2.1", - "bip66": "^1.1.3", - "bn.js": "^4.11.3", - "create-hash": "^1.1.2", - "drbg.js": "^1.0.1", - "elliptic": "^6.2.3", - "nan": "^2.2.1", - "safe-buffer": "^5.1.0" - } - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "optional": true - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "sinon": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.5.0.tgz", - "integrity": "sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w==", - "dev": true, - "requires": { - "@sinonjs/formatio": "^2.0.0", - "diff": "^3.1.0", - "lodash.get": "^4.4.2", - "lolex": "^2.2.0", - "nise": "^1.2.0", - "supports-color": "^5.1.0", - "type-detect": "^4.0.5" - }, - "dependencies": { - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "requires": { - "source-map": "^0.5.6" - } - }, - "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==" - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "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=" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - }, - "text-encoding": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", - "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", - "dev": true - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" - }, - "topo": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", - "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=", - "requires": { - "hoek": "2.x.x" - } - }, - "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" - } - }, - "traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "typeforce": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.12.0.tgz", - "integrity": "sha512-fvnkvueAOFLhtAqDgIA/wMP21SMwS/NQESFKZuwVrj5m/Ew6eK2S0z0iB++cwtROPWDOhaT6OUfla8UwMw4Adg==" - }, - "unorm": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.4.1.tgz", - "integrity": "sha1-NkIA1fE2RsqLzURJAnEzVhR5IwA=" - }, - "user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=" - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "requires": { - "inherits": "2.0.1" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "optional": true - }, - "v8flags": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", - "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", - "requires": { - "user-home": "^1.1.1" - } - }, - "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "varuint-bitcoin": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.0.tgz", - "integrity": "sha512-jCEPG+COU/1Rp84neKTyDJQr478/hAfVp5xxYn09QEH0yBjbmPeMfuuQIrp+BUD83hybtYZKhr5elV3bvdV1bA==", - "requires": { - "safe-buffer": "^5.1.1" - } - }, - "vision": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/vision/-/vision-3.0.0.tgz", - "integrity": "sha1-GEWEb2wjpvJTXa8woeHnHQukjGI=", - "requires": { - "boom": "2.x.x", - "hoek": "^2.9.x", - "items": "^1.1.x", - "joi": "6.x.x" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "wif": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", - "integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=", - "requires": { - "bs58check": "<3.0.0" - } - }, - "window-or-global": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/window-or-global/-/window-or-global-1.0.1.tgz", - "integrity": "sha1-2+RboqKRqrxW1iz2bEW3+jIpRt4=" - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "wreck": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/wreck/-/wreck-6.3.0.tgz", - "integrity": "sha1-oTaXafB7u2LWo3gzanhx/Hc8dAs=", - "requires": { - "boom": "2.x.x", - "hoek": "2.x.x" - } - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" - }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "yargs": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", - "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", - "requires": { - "camelcase": "^4.1.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "read-pkg-up": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^7.0.0" - } - }, - "yargs-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", - "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", - "requires": { - "camelcase": "^4.1.0" - } - } - } -} diff --git a/package.json b/package.json index 3bb619dd..4a1c9eab 100644 --- a/package.json +++ b/package.json @@ -1,67 +1,88 @@ { - "name": "bitbox-cli", - "version": "1.1.0", - "description": "BITBOX javascript sdk for Bitcoin Cash", - "author": "Bitcoin.com", - "main": "index.js", + "name": "bitbox-sdk", + "version": "8.11.0", + "description": "BITBOX SDK for Bitcoin Cash", + "author": "Gabriel Cardona ", + "contributors": [ + "Chris Troutner " + ], "scripts": { - "test": "nyc mocha --timeout 15000 --require babel-core/register", - "build": "babel src/ -d lib/", - "flow": "flow" + "test": "npm run test:unit", + "test:no-build": "nyc mocha test/unit --timeout 60000 --exit", + "test:unit": "tsc && nyc mocha test/unit --timeout 60000 --exit", + "test:integration": "TEST=integration nyc --reporter=text mocha --timeout 30000 test/integration --exit", + "test:integration:local": "TEST=integration SERVER=local nyc --reporter=text mocha --timeout 30000 test/integration --exit", + "test:integration:stage": "TEST=integration SERVER=stage nyc --reporter=text mocha --timeout 30000 test/integration --exit", + "test:integration:custom": "TEST=integration SERVER=custom mocha --timeout 30000 test/integration --exit", + "coverage": "nyc report --reporter=text-lcov | coveralls", + "build": "tsc" }, "license": "MIT", "engines": { - "node": ">=10.3.0" + "node": ">=10.15.3" }, - "bin": { - "bitbox": "./index.js" + "main": "index.js", + "files": [ + "index.ts", + "lib/" + ], + "homepage": "https://developer.bitcoin.com/bitbox", + "repository": { + "type": "git", + "url": "git+https://github.com/Bitcoin-com/bitbox-sdk.git" }, "dependencies": { + "@bitcoin-dot-com/bitcoincashjs2-lib": "^4.1.0", + "@types/bigi": "^1.4.2", + "@types/bip39": "^2.4.2", + "@types/randombytes": "^2.0.0", + "@types/socket.io": "^2.1.2", + "@types/socket.io-client": "^1.4.32", + "@types/wif": "^2.0.1", "assert": "^1.4.1", - "axios": "^0.17.1", - "babel-cli": "^6.26.0", - "babel-preset-env": "^1.6.1", - "babel-preset-es2015": "^6.24.1", - "babel-preset-flow": "^6.23.0", - "babel-preset-react": "^6.24.1", - "babel-register": "^6.26.0", - "bchaddrjs": "^0.2.1", + "axios": "0.19.0", + "bc-bip68": "^1.0.5", "bigi": "^1.4.2", + "bip-schnorr": "^0.3.0", "bip21": "Bitcoin-com/bip21", + "bip32-utils": "Bitcoin-com/bip32-utils#0.13.1", "bip38": "^2.0.2", "bip39": "^2.5.0", - "bip68": "^1.0.4", - "bitcoin-ops": "Bitcoin-com/bitcoincash-ops", - "bitcoincashjs-lib": "Bitcoin-com/bitcoincashjs-lib", + "bip66": "^1.1.5", + "bitcoincash-ops": "Bitcoin-com/bitcoincash-ops#2.0.0", "bitcoinjs-message": "^2.0.0", "bs58": "^4.0.1", - "buffer": "^5.1.0", - "chalk": "^2.3.0", - "clear": "0.0.1", + "cashaddrjs": "^0.2.9", "coininfo": "Bitcoin-com/coininfo", - "commander": "^2.13.0", - "corsproxy": "^1.5.0", - "cp-file": "^5.0.0", - "ecurve": "^1.0.6", - "figlet": "^1.2.0", - "git-clone": "^0.1.0", - "ini": "^1.3.5", - "mkdirp": "^0.5.1", - "mocha": "^5.0.1", - "node-cmd": "^3.0.0", - "node-emoji": "^1.8.1", - "qrcode": "^1.2.0", + "eventsource": "^1.0.7", "randombytes": "^2.0.6", - "repl.history": "^0.1.4", "safe-buffer": "^5.1.2", "satoshi-bitcoin": "^1.0.4", - "touch": "^3.1.0", + "socket.io": "^2.2.0", + "socket.io-client": "^2.2.0", "wif": "^2.0.6" }, "devDependencies": { + "@istanbuljs/nyc-config-typescript": "^0.1.3", + "@types/chai": "^4.1.7", + "@types/mocha": "^5.2.6", + "@types/node": "^10.11.7", + "@types/sinon": "^7.0.11", "chai": "^4.1.2", - "flow-bin": "^0.64.0", - "nyc": "^11.6.0", - "sinon": "^4.5.0" + "coveralls": "^3.0.2", + "eslint": "^5.16.0", + "eslint-config-prettier": "^3.0.1", + "eslint-plugin-node": "7.0.1", + "eslint-plugin-prettier": "^2.6.2", + "mocha": "^5.0.1", + "nock": "^10.0.6", + "node-mocks-http": "^1.7.0", + "nyc": "^14.1.1", + "prettier": "^1.14.2", + "semantic-release": "^15.13.31", + "sinon": "^4.5.0", + "source-map-support": "^0.5.12", + "ts-node": "^8.1.0", + "typescript": "^3.4.5" } } diff --git a/src/Address.js b/src/Address.js deleted file mode 100644 index 299f0b7d..00000000 --- a/src/Address.js +++ /dev/null @@ -1,133 +0,0 @@ -import axios from 'axios'; -import bchaddr from 'bchaddrjs'; -import Bitcoin from 'bitcoincashjs-lib'; - -class Address { - constructor(restURL) { - this.restURL = restURL; - } - - // Translate address from any address format into a specific format. - toLegacyAddress(address) { - return bchaddr.toLegacyAddress(address); - } - - toCashAddress(address, prefix = true) { - if(prefix) { - return bchaddr.toCashAddress(address); - } else { - return bchaddr.toCashAddress(address).split(':')[1]; - } - } - - // Test for address format. - isLegacyAddress(address) { - return bchaddr.isLegacyAddress(address); - } - - isCashAddress(address) { - return bchaddr.isCashAddress(address); - } - - // Test for address network. - isMainnetAddress(address) { - if(address[0] === 'x') { - return true - } else if(address[0] === 't') { - return false - } else { - return bchaddr.isMainnetAddress(address); - } - } - - isTestnetAddress(address) { - if(address[0] === 'x') { - return false - } else if(address[0] === 't') { - return true - } else { - return bchaddr.isTestnetAddress(address); - } - } - - // Test for address type. - isP2PKHAddress(address) { - return bchaddr.isP2PKHAddress(address); - } - - isP2SHAddress(address) { - return bchaddr.isP2SHAddress(address); - } - - // Detect address format. - detectAddressFormat(address) { - return bchaddr.detectAddressFormat(address); - } - - // Detect address network. - detectAddressNetwork(address) { - if(address[0] === 'x') { - return 'mainnet' - } else if(address[0] === 't') { - return 'testnet' - } else { - return bchaddr.detectAddressNetwork(address); - } - } - - // Detect address type. - detectAddressType(address) { - return bchaddr.detectAddressType(address); - } - - fromXPub(xpub, path = "0/0") { - let HDNode = Bitcoin.HDNode.fromBase58(xpub, Bitcoin.networks[this.detectAddressNetwork(xpub)]); - let address = HDNode.derivePath(path); - return this.toCashAddress(address.getAddress()); - } - - fromOutputScript(scriptPubKey) { - return bchaddr.toCashAddress(Bitcoin.address.fromOutputScript(scriptPubKey)); - } - - details(address) { - if(typeof address !== 'string') { - address = JSON.stringify(address); - } - return axios.get(`${this.restURL}address/details/${address}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - utxo(address) { - if(typeof address !== 'string') { - address = JSON.stringify(address); - } - return axios.get(`${this.restURL}address/utxo/${address}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - unconfirmed(address) { - if(typeof address !== 'string') { - address = JSON.stringify(address); - } - return axios.get(`${this.restURL}address/unconfirmed/${address}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } -} - -export default Address diff --git a/src/BitcoinCash.js b/src/BitcoinCash.js deleted file mode 100644 index 2d97f6e8..00000000 --- a/src/BitcoinCash.js +++ /dev/null @@ -1,142 +0,0 @@ -import Bitcoin from 'bitcoincashjs-lib'; -import bchaddr from 'bchaddrjs'; -import sb from 'satoshi-bitcoin'; -import bitcoinMessage from 'bitcoinjs-message'; -import bs58 from 'bs58'; -import bip21 from 'bip21'; -import coininfo from'coininfo'; -import bip38 from 'bip38'; -import wif from 'wif'; - -let Buffer = require('safe-buffer').Buffer - -class BitcoinCash { - // Translate coins to satoshi value - toSatoshi(coins) { - return sb.toSatoshi(coins); - } - - // Translate satoshi to coin value - toBitcoinCash(satoshis) { - return sb.toBitcoin(satoshis); - } - - // Translate satoshi to bits denomination - toBits(satoshis) { - return parseFloat(satoshis) / 100000; - } - - // Translate bits to satoshi denomination - fromBits(bits) { - return Math.ceil(bits * 100000); - } - - // sign message - signMessageWithPrivKey(privateKeyWIF, message) { - let network = privateKeyWIF.charAt(0) === 'c' ? 'testnet' : 'bitcoincash'; - let bitcoincash; - if(network === 'bitcoincash') { - bitcoincash = coininfo.bitcoincash.main; - } else { - bitcoincash = coininfo.bitcoincash.test; - } - let bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS(); - let keyPair = Bitcoin.ECPair.fromWIF(privateKeyWIF, bitcoincashBitcoinJSLib) - let privateKey = keyPair.d.toBuffer(32) - return bitcoinMessage.sign(message, privateKey, keyPair.compressed).toString('base64'); - } - - // verify message - verifyMessage(address, signature, message) { - return bitcoinMessage.verify(message, bchaddr.toLegacyAddress(address), signature); - } - - // encode base58Check - encodeBase58Check(hex) { - return bs58.encode(Buffer.from(hex, 'hex')); - } - - // decode base58Check - decodeBase58Check(address) { - return bs58.decode(address).toString('hex'); - } - - // encode bip21 url - encodeBIP21(address, options) { - return bip21.encode(bchaddr.toCashAddress(address), options); - } - - // decode bip21 url - decodeBIP21(url) { - return bip21.decode(url); - } - - getByteCount(inputs, outputs) { - // from https://github.com/bitcoinjs/bitcoinjs-lib/issues/921#issuecomment-354394004 - let totalWeight = 0 - let hasWitness = false - // assumes compressed pubkeys in all cases. - let types = { - 'inputs': { - 'MULTISIG-P2SH': 49 * 4, - 'MULTISIG-P2WSH': 6 + (41 * 4), - 'MULTISIG-P2SH-P2WSH': 6 + (76 * 4), - 'P2PKH': 148 * 4, - 'P2WPKH': 108 + (41 * 4), - 'P2SH-P2WPKH': 108 + (64 * 4) - }, - 'outputs': { - 'P2SH': 32 * 4, - 'P2PKH': 34 * 4, - 'P2WPKH': 31 * 4, - 'P2WSH': 43 * 4 - } - } - - Object.keys(inputs).forEach(function(key) { - if (key.slice(0,8) === 'MULTISIG') { - // ex. "MULTISIG-P2SH:2-3" would mean 2 of 3 P2SH MULTISIG - let keyParts = key.split(':') - if (keyParts.length !== 2) throw new Error('invalid input: ' + key) - let newKey = keyParts[0] - let mAndN = keyParts[1].split('-').map(function (item) { return parseInt(item) }) - - totalWeight += types.inputs[newKey] * inputs[key] - let multiplyer = (newKey === 'MULTISIG-P2SH') ? 4 : 1 - totalWeight += ((73 * mAndN[0]) + (34 * mAndN[1])) * multiplyer - } else { - totalWeight += types.inputs[key] * inputs[key] - } - if (key.indexOf('W') >= 0) hasWitness = true - }) - - Object.keys(outputs).forEach(function(key) { - totalWeight += types.outputs[key] * outputs[key] - }) - - if (hasWitness) totalWeight += 2 - - totalWeight += 10 * 4 - - return Math.ceil(totalWeight / 4) - } - - encryptBIP38(privKeyWIF, passphrase) { - let decoded = wif.decode(privKeyWIF); - - return bip38.encrypt(decoded.privateKey, decoded.compressed, passphrase); - } - - decryptBIP38(encryptedKey, passphrase, network = 'mainnet') { - let decryptedKey = bip38.decrypt(encryptedKey, passphrase); - let prefix; - if(network === 'testnet') { - prefix = 0xEF; - } else { - prefix = 0x80; - } - return wif.encode(prefix, decryptedKey.privateKey, decryptedKey.compressed) ; - } -} - -export default BitcoinCash; diff --git a/src/Block.js b/src/Block.js deleted file mode 100644 index c637dc87..00000000 --- a/src/Block.js +++ /dev/null @@ -1,18 +0,0 @@ -import axios from 'axios'; -class Block { - constructor(restURL) { - this.restURL = restURL; - } - - details(id) { - return axios.get(`${this.restURL}block/details/${id}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } -} - -export default Block; diff --git a/src/Blockchain.js b/src/Blockchain.js deleted file mode 100644 index f45ab220..00000000 --- a/src/Blockchain.js +++ /dev/null @@ -1,519 +0,0 @@ -import axios from 'axios'; -class Blockchain { - constructor(restURL) { - this.restURL = restURL; - } - - getBestBlockHash() { - // Returns the hash of the best (tip) block in the longest blockchain. - // - // Result: - // "hex" (string) the block hash hex encoded - return axios.get(`${this.restURL}blockchain/getBestBlockHash`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getBlock(blockhash, verbose = true) { - // If verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'. - // If verbose is true, returns an Object with information about block . - // - // Arguments: - // 1. "blockhash" (string, required) The block hash - // 2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data - // - // Result (for verbose = true): - // { - // "hash" : "hash", (string) the block hash (same as provided) - // "confirmations" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain - // "size" : n, (numeric) The block size - // "height" : n, (numeric) The block height or index - // "version" : n, (numeric) The block version - // "versionHex" : "00000000", (string) The block version formatted in hexadecimal - // "merkleroot" : "xxxx", (string) The merkle root - // "tx" : [ (array of string) The transaction ids - // "transactionid" (string) The transaction id - // ,... - // ], - // "time" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT) - // "mediantime" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT) - // "nonce" : n, (numeric) The nonce - // "bits" : "1d00ffff", (string) The bits - // "difficulty" : x.xxx, (numeric) The difficulty - // "chainwork" : "xxxx", (string) Expected number of hashes required to produce the chain up to this block (in hex) - // "previousblockhash" : "hash", (string) The hash of the previous block - // "nextblockhash" : "hash" (string) The hash of the next block - // } - // - // Result (for verbose=false): - // "data" (string) A string that is serialized, hex-encoded data for block 'hash'. - - return axios.get(`${this.restURL}blockchain/getBlock/${blockhash}?verbose=${verbose}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getBlockchainInfo() { - // Returns an object containing various state info regarding blockchain processing. - return axios.get(`${this.restURL}blockchain/getBlockchainInfo`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getBlockCount() { - // Returns the number of blocks in the longest blockchain. - // - // Result: - // n (numeric) The current block count - return axios.get(`${this.restURL}blockchain/getBlockCount`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getBlockHash(height = 1) { - // Returns hash of block in best-block-chain at height provided. - // - // Arguments: - // 1. height (numeric, required) The height index - // - // Result: - // "hash" (string) The block hash - return axios.get(`${this.restURL}blockchain/getBlockHash/${height}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getBlockHeader(hash, verbose = true) { - - // If verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'. - // If verbose is true, returns an Object with information about blockheader . - // - // Arguments: - // 1. "hash" (string, required) The block hash - // 2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data - // - // Result (for verbose = true): - // { - // "hash" : "hash", (string) the block hash (same as provided) - // "confirmations" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain - // "height" : n, (numeric) The block height or index - // "version" : n, (numeric) The block version - // "versionHex" : "00000000", (string) The block version formatted in hexadecimal - // "merkleroot" : "xxxx", (string) The merkle root - // "time" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT) - // "mediantime" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT) - // "nonce" : n, (numeric) The nonce - // "bits" : "1d00ffff", (string) The bits - // "difficulty" : x.xxx, (numeric) The difficulty - // "chainwork" : "0000...1f3" (string) Expected number of hashes required to produce the current chain (in hex) - // "previousblockhash" : "hash", (string) The hash of the previous block - // "nextblockhash" : "hash", (string) The hash of the next block - // } - // - // Result (for verbose=false): - // "data" (string) A string that is serialized, hex-encoded data for block 'hash'. - return axios.get(`${this.restURL}blockchain/getBlockHeader/${hash}?verbose=${verbose}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getChainTips() { - // Return information about all known tips in the block tree, including the main chain as well as orphaned branches. - // - // Result: - // [ - // { - // "height": xxxx, (numeric) height of the chain tip - // "hash": "xxxx", (string) block hash of the tip - // "branchlen": 0 (numeric) zero for main chain - // "status": "active" (string) "active" for the main chain - // }, - // { - // "height": xxxx, - // "hash": "xxxx", - // "branchlen": 1 (numeric) length of branch connecting the tip to the main chain - // "status": "xxxx" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid) - // } - // ] - // Possible values for status: - // 1. "invalid" This branch contains at least one invalid block - // 2. "headers-only" Not all blocks for this branch are available, but the headers are valid - // 3. "valid-headers" All blocks are available for this branch, but they were never fully validated - // 4. "valid-fork" This branch is not part of the active chain, but is fully validated - // 5. "active" This is the tip of the active main chain, which is certainly valid - - return axios.get(`${this.restURL}blockchain/getChainTips`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getDifficulty() { - - // Returns the proof-of-work difficulty as a multiple of the minimum difficulty. - // - // Result: - // n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty. - - return axios.get(`${this.restURL}blockchain/getDifficulty`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getMempoolAncestors(txid, verbose = false) { - // If txid is in the mempool, returns all in-mempool ancestors. - // - // Arguments: - // 1. "txid" (string, required) The transaction id (must be in mempool) - // 2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids - // - // Result (for verbose=false): - // [ (json array of strings) - // "transactionid" (string) The transaction id of an in-mempool ancestor transaction - // ,... - // ] - // - // Result (for verbose=true): - // { (json object) - // "transactionid" : { (json object) - // "size" : n, (numeric) transaction size. - // "fee" : n, (numeric) transaction fee in BCH - // "modifiedfee" : n, (numeric) transaction fee with fee deltas used for mining priority - // "time" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT - // "height" : n, (numeric) block height when transaction entered pool - // "startingpriority" : n, (numeric) DEPRECATED. Priority when transaction entered pool - // "currentpriority" : n, (numeric) DEPRECATED. Transaction priority now - // "descendantcount" : n, (numeric) number of in-mempool descendant transactions (including this one) - // "descendantsize" : n, (numeric) virtual transaction size of in-mempool descendants (including this one) - // "descendantfees" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one) - // "ancestorcount" : n, (numeric) number of in-mempool ancestor transactions (including this one) - // "ancestorsize" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one) - // "ancestorfees" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one) - // "depends" : [ (array) unconfirmed transactions used as inputs for this transaction - // "transactionid", (string) parent transaction id - // ... ] - // }, ... - // } - return axios.get(`${this.restURL}blockchain/getMempoolAncestors/${txid}?verbose=${verbose}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getMempoolDescendants(txid, verbose = false) { - // If txid is in the mempool, returns all in-mempool descendants. - // - // Arguments: - // 1. "txid" (string, required) The transaction id (must be in mempool) - // 2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids - // - // Result (for verbose=false): - // [ (json array of strings) - // "transactionid" (string) The transaction id of an in-mempool descendant transaction - // ,... - // ] - // - // Result (for verbose=true): - // { (json object) - // "transactionid" : { (json object) - // "size" : n, (numeric) transaction size. - // "fee" : n, (numeric) transaction fee in BCH - // "modifiedfee" : n, (numeric) transaction fee with fee deltas used for mining priority - // "time" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT - // "height" : n, (numeric) block height when transaction entered pool - // "startingpriority" : n, (numeric) DEPRECATED. Priority when transaction entered pool - // "currentpriority" : n, (numeric) DEPRECATED. Transaction priority now - // "descendantcount" : n, (numeric) number of in-mempool descendant transactions (including this one) - // "descendantsize" : n, (numeric) virtual transaction size of in-mempool descendants (including this one) - // "descendantfees" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one) - // "ancestorcount" : n, (numeric) number of in-mempool ancestor transactions (including this one) - // "ancestorsize" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one) - // "ancestorfees" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one) - // "depends" : [ (array) unconfirmed transactions used as inputs for this transaction - // "transactionid", (string) parent transaction id - // ... ] - // }, ... - // } - - return axios.get(`${this.restURL}blockchain/getMempoolDescendants/${txid}?verbose=${verbose}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getMempoolEntry(txid) { - // Returns mempool data for given transaction - // - // Arguments: - // 1. "txid" (string, required) The transaction id (must be in mempool) - // - // Result: - // { (json object) - // "size" : n, (numeric) transaction size. - // "fee" : n, (numeric) transaction fee in BCH - // "modifiedfee" : n, (numeric) transaction fee with fee deltas used for mining priority - // "time" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT - // "height" : n, (numeric) block height when transaction entered pool - // "startingpriority" : n, (numeric) DEPRECATED. Priority when transaction entered pool - // "currentpriority" : n, (numeric) DEPRECATED. Transaction priority now - // "descendantcount" : n, (numeric) number of in-mempool descendant transactions (including this one) - // "descendantsize" : n, (numeric) virtual transaction size of in-mempool descendants (including this one) - // "descendantfees" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one) - // "ancestorcount" : n, (numeric) number of in-mempool ancestor transactions (including this one) - // "ancestorsize" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one) - // "ancestorfees" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one) - // "depends" : [ (array) unconfirmed transactions used as inputs for this transaction - // "transactionid", (string) parent transaction id - // ... ] - // } - - return axios.get(`${this.restURL}blockchain/getMempoolEntry/${txid}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getMempoolInfo() { - // Returns details on the active state of the TX memory pool. - // - // Result: - // { - // "size": xxxxx, (numeric) Current tx count - // "bytes": xxxxx, (numeric) Transaction size. - // "usage": xxxxx, (numeric) Total memory usage for the mempool - // "maxmempool": xxxxx, (numeric) Maximum memory usage for the mempool - // "mempoolminfee": xxxxx (numeric) Minimum fee for tx to be accepted - // } - - return axios.get(`${this.restURL}blockchain/getMempoolInfo`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getRawMempool(verbose = false) { - // Returns all transaction ids in memory pool as a json array of string transaction ids. - // - // Arguments: - // 1. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids - // - // Result: (for verbose = false): - // [ (json array of string) - // "transactionid" (string) The transaction id - // ,... - // ] - // - // Result: (for verbose = true): - // { (json object) - // "transactionid" : { (json object) - // "size" : n, (numeric) transaction size. - // "fee" : n, (numeric) transaction fee in BCH - // "modifiedfee" : n, (numeric) transaction fee with fee deltas used for mining priority - // "time" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT - // "height" : n, (numeric) block height when transaction entered pool - // "startingpriority" : n, (numeric) DEPRECATED. Priority when transaction entered pool - // "currentpriority" : n, (numeric) DEPRECATED. Transaction priority now - // "descendantcount" : n, (numeric) number of in-mempool descendant transactions (including this one) - // "descendantsize" : n, (numeric) virtual transaction size of in-mempool descendants (including this one) - // "descendantfees" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one) - // "ancestorcount" : n, (numeric) number of in-mempool ancestor transactions (including this one) - // "ancestorsize" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one) - // "ancestorfees" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one) - // "depends" : [ (array) unconfirmed transactions used as inputs for this transaction - // "transactionid", (string) parent transaction id - // ... ] - // }, ... - // } - return axios.get(`${this.restURL}blockchain/getRawMempool?vebose=${verbose}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getTxOut(txid, n, include_mempool = true) { - // Returns details about an unspent transaction output. - // - // Arguments: - // 1. "txid" (string, required) The transaction id - // 2. n (numeric, required) vout number - // 3. include_mempool (boolean, optional) Whether to include the mempool - // - // Result: - // { - // "bestblock" : "hash", (string) the block hash - // "confirmations" : n, (numeric) The number of confirmations - // "value" : x.xxx, (numeric) The transaction value in BCH - // "scriptPubKey" : { (json object) - // "asm" : "code", (string) - // "hex" : "hex", (string) - // "reqSigs" : n, (numeric) Number of required signatures - // "type" : "pubkeyhash", (string) The type, eg pubkeyhash - // "addresses" : [ (array of string) array of bitcoin addresses - // "address" (string) bitcoin address - // ,... - // ] - // }, - // "coinbase" : true|false (boolean) Coinbase or not - // } - // - - return axios.get(`${this.restURL}blockchain/getTxOut/${txid}/n?include_mempool=${include_mempool}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getTxOutProof(txids, blockhash) { - let path = `${this.restURL}blockchain/getTxOutProof/${txids}`; - if(blockhash) { - path = `${path}?blockhash=${blockhash}` - } - // Returns a hex-encoded proof that "txid" was included in a block. - // - // NOTE: By default this function only works sometimes. This is when there is an - // unspent output in the utxo for this transaction. To make it always work, - // you need to maintain a transaction index, using the -txindex command line option or - // specify the block in which the transaction is included manually (by blockhash). - // - // Arguments: - // 1. "txids" (string) A json array of txids to filter - // [ - // "txid" (string) A transaction hash - // ,... - // ] - // 2. "blockhash" (string, optional) If specified, looks for txid in the block with this hash - // - // Result: - // "data" (string) A string that is a serialized, hex-encoded data for the proof. - return axios.get(path) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - preciousBlock(blockhash) { - // Treats a block as if it were received before others with the same work. - // - // A later preciousblock call can override the effect of an earlier one. - // - // The effects of preciousblock are not retained across restarts. - // - // Arguments: - // 1. "blockhash" (string, required) the hash of the block to mark as precious - - return axios.get(`${this.restURL}blockchain/preciousBlock/${blockhash}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - pruneBlockchain(height) { - // Arguments: - // 1. "height" (numeric, required) The block height to prune up to. May be set to a discrete height, or a unix timestamp - // to prune blocks whose block time is at least 2 hours older than the provided timestamp. - // - // Result: - // n (numeric) Height of the last block pruned. - return axios.post(`${this.restURL}blockchain/pruneBlockchain/${height}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - verifyChain(checklevel = 3, nblocks = 6) { - // Verifies blockchain database. - // - // Arguments: - // 1. checklevel (numeric, optional, 0-4, default=3) How thorough the block verification is. - // 2. nblocks (numeric, optional, default=6, 0=all) The number of blocks to check. - // - // Result: - // true|false (boolean) Verified or not - return axios.get(`${this.restURL}blockchain/verifyChain?checklevel=${checklevel}&nblocks=${nblocks}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - verifyTxOutProof(proof) { - // Verifies that a proof points to a transaction in a block, returning the transaction it commits to - // and throwing an RPC error if the block is not in our best chain - // - // Arguments: - // 1. "proof" (string, required) The hex-encoded proof generated by gettxoutproof - // - // Result: - // ["txid"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof is invalid - - return axios.get(`${this.restURL}blockchain/verifyTxOutProof/proof`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } -} - -export default Blockchain; diff --git a/src/Control.js b/src/Control.js deleted file mode 100644 index 9956f96f..00000000 --- a/src/Control.js +++ /dev/null @@ -1,77 +0,0 @@ -import axios from 'axios'; -class Control { - constructor(restURL) { - this.restURL = restURL; - } - - getInfo() { - // DEPRECATED. Returns an object containing various state info. - // - // Result: - // { - // "version": xxxxx, (numeric) the server version - // "protocolversion": xxxxx, (numeric) the protocol version - // "walletversion": xxxxx, (numeric) the wallet version - // "balance": xxxxxxx, (numeric) the total bitcoin balance of the wallet - // "blocks": xxxxxx, (numeric) the current number of blocks processed in the server - // "timeoffset": xxxxx, (numeric) the time offset - // "connections": xxxxx, (numeric) the number of connections - // "proxy": "host:port", (string, optional) the proxy used by the server - // "difficulty": xxxxxx, (numeric) the current difficulty - // "testnet": true|false, (boolean) if the server is using testnet or not - // "keypoololdest": xxxxxx, (numeric) the timestamp (seconds since Unix epoch) of the oldest pre-generated key in the key pool - // "keypoolsize": xxxx, (numeric) how many new keys are pre-generated - // "unlocked_until": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked - // "paytxfee": x.xxxx, (numeric) the transaction fee set in BCH/kB - // "relayfee": x.xxxx, (numeric) minimum relay fee for non-free transactions in BCH/kB - // "errors": "..." (string) any error messages - // } - - return axios.get(`${this.restURL}control/getInfo`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getMemoryInfo() { - - // Returns an object containing information about memory usage. - // - // Result: - // { - // "locked": { (json object) Information about locked memory manager - // "used": xxxxx, (numeric) Number of bytes used - // "free": xxxxx, (numeric) Number of bytes available in current arenas - // "total": xxxxxxx, (numeric) Total number of bytes managed - // "locked": xxxxxx, (numeric) Amount of bytes that succeeded locking. If this number is smaller than total, locking pages failed at some point and key data could be swapped to disk. - // "chunks_used": xxxxx, (numeric) Number allocated chunks - // "chunks_free": xxxxx, (numeric) Number unused chunks - // } - // } - // - - return axios.get(`${this.restURL}control/getMemoryInfo`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - // - // stop() { - // // Stop Bitcoin Cash server. - // return axios.post(`${this.restURL}control/stop`) - // .then((response) => { - // return response.data; - // }) - // .catch((error) => { - // return JSON.stringify(error.response.data.error.message); - // }); - // } -} - -export default Control; diff --git a/src/Crypto.js b/src/Crypto.js deleted file mode 100644 index 86d7fd0a..00000000 --- a/src/Crypto.js +++ /dev/null @@ -1,30 +0,0 @@ -import randomBytes from 'randombytes'; -import BitcoinCash from './BitcoinCash'; -import Bitcoin from 'bitcoincashjs-lib'; -let bc = new BitcoinCash(); - -class Crypto { - // Utility class to wrap NodeJS's crypto module - // https://nodejs.org/api/crypto.html - static sha256(buffer) { - return Bitcoin.crypto.sha256(buffer); - } - - static ripemd160(buffer) { - return Bitcoin.crypto.ripemd160(buffer); - } - - static hash256(buffer) { - return Bitcoin.crypto.hash256(buffer); - } - - static hash160(buffer) { - return Bitcoin.crypto.hash160(buffer); - } - - static randomBytes(size = 16) { - return randomBytes(size); - } -} - -export default Crypto; diff --git a/src/ECPair.js b/src/ECPair.js deleted file mode 100644 index 94fd3aa3..00000000 --- a/src/ECPair.js +++ /dev/null @@ -1,53 +0,0 @@ -import Bitcoin from 'bitcoincashjs-lib'; -import bchaddr from 'bchaddrjs'; -import coininfo from'coininfo'; - -class ECPair { - static fromWIF(privateKeyWIF) { - let network; - if(privateKeyWIF[0] === 'L' || privateKeyWIF[0] === 'K') { - network = 'bitcoincash'; - } else if(privateKeyWIF[0] === 'c') { - network = 'testnet'; - } - let bitcoincash; - if(network === 'bitcoincash') { - bitcoincash = coininfo.bitcoincash.main; - } else { - bitcoincash = coininfo.bitcoincash.test; - } - let bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS(); - - return Bitcoin.ECPair.fromWIF(privateKeyWIF, bitcoincashBitcoinJSLib); - } - - static toWIF(ecpair) { - return ecpair.toWIF(); - } - - static sign(ecpair, buffer) { - return ecpair.sign(buffer); - } - - static verify(ecpair, buffer, signature) { - return ecpair.verify(buffer, signature); - } - - static fromPublicKey(pubkeyBuffer) { - return Bitcoin.ECPair.fromPublicKeyBuffer(pubkeyBuffer); - } - - static toPublicKey(ecpair) { - return ecpair.getPublicKeyBuffer(); - } - - static toLegacyAddress(ecpair) { - return ecpair.getAddress(); - } - - static toCashAddress(ecpair) { - return bchaddr.toCashAddress(ecpair.getAddress()); - } -} - -export default ECPair; diff --git a/src/Generating.js b/src/Generating.js deleted file mode 100644 index c7ce4cfe..00000000 --- a/src/Generating.js +++ /dev/null @@ -1,29 +0,0 @@ -import axios from 'axios'; -class Generating { - constructor(restURL) { - this.restURL = restURL; - } - - generateToAddress(blocks, address, maxtries = 1000000) { - - // Mine blocks immediately to a specified address (before the RPC call returns) - // - // Arguments: - // 1. nblocks (numeric, required) How many blocks are generated immediately. - // 2. address (string, required) The address to send the newly generated bitcoin to. - // 3. maxtries (numeric, optional) How many iterations to try (default = 1000000). - // - // Result: - // [ blockhashes ] (array) hashes of blocks generated - // - return axios.post(`${this.restURL}generating/generateToAddress/${blocks}/${address}?maxtries=${maxtries}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } -} - -export default Generating; diff --git a/src/HDNode.js b/src/HDNode.js deleted file mode 100644 index a9dc4157..00000000 --- a/src/HDNode.js +++ /dev/null @@ -1,110 +0,0 @@ -import Bitcoin from 'bitcoincashjs-lib'; -import bchaddr from 'bchaddrjs'; -import coininfo from'coininfo'; -// let bip32utils = require('bip32-utils') - -class HDNode { - fromSeed(rootSeedBuffer, network = 'bitcoincash') { - let bitcoincash; - if(network === 'bitcoincash') { - bitcoincash = coininfo.bitcoincash.main; - } else { - bitcoincash = coininfo.bitcoincash.test; - } - let bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS(); - return Bitcoin.HDNode.fromSeedBuffer(rootSeedBuffer, bitcoincashBitcoinJSLib); - } - - toLegacyAddress(hdNode) { - return hdNode.getAddress(); - } - - toCashAddress(hdNode) { - return bchaddr.toCashAddress(hdNode.getAddress()); - } - - toWIF(hdNode) { - return hdNode.keyPair.toWIF(); - } - - toXPub(hdNode) { - return hdNode.neutered().toBase58(); - } - - toXPriv(hdNode) { - return hdNode.toBase58(); - } - - toKeyPair(hdNode) { - return hdNode.keyPair; - } - - toPublicKey(hdNode) { - return hdNode.getPublicKeyBuffer(); - } - - fromXPriv(xpriv) { - let bitcoincash; - if(xpriv[0] === 'x') { - bitcoincash = coininfo.bitcoincash.main; - } else if(xpriv[0] === 't') { - bitcoincash = coininfo.bitcoincash.test; - } - let bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS(); - return Bitcoin.HDNode.fromBase58(xpriv, bitcoincashBitcoinJSLib); - } - - fromXPub(xpub) { - let bitcoincash; - if(xpub[0] === 'x') { - bitcoincash = coininfo.bitcoincash.main; - } else if(xpub[0] === 't') { - bitcoincash = coininfo.bitcoincash.test; - } - let bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS(); - return Bitcoin.HDNode.fromBase58(xpub, bitcoincashBitcoinJSLib); - } - - derivePath(hdnode, path) { - return hdnode.derivePath(path); - } - - derive(hdnode, path) { - return hdnode.derive(path); - } - - deriveHardened(hdnode, path) { - return hdnode.deriveHardened(path); - } - - sign(hdnode, buffer) { - return hdnode.sign(buffer); - } - - verify(hdnode, buffer, signature) { - return hdnode.verify(buffer, signature); - } - - isPublic(hdnode) { - return hdnode.isNeutered(); - } - - isPrivate(hdnode) { - return !hdnode.isNeutered(); - } - - toIdentifier(hdnode) { - return hdnode.getIdentifier(); - } - - fromBase58(base58, network) { - return Bitcoin.HDNode.fromBase58(base58, network); - } - - // - // createChain(hdNode) { - // return new bip32utils.Chain(hdNode); - // } -} - -export default HDNode; diff --git a/src/Mining.js b/src/Mining.js deleted file mode 100644 index ae0ca03d..00000000 --- a/src/Mining.js +++ /dev/null @@ -1,109 +0,0 @@ -import axios from 'axios'; -class Mining { - constructor(restURL) { - this.restURL = restURL; - } - - getBlockTemplate(template_request) { - - // If the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'. - // It returns data needed to construct a block to work on. - // For full specification, see BIPs 22, 23, 9, and 145: - // https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki - // https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki - // https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes - // https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki - // - // Arguments: - // 1. template_request (json object, optional) A json object in the following spec - // { - // "mode":"template" (string, optional) This must be set to "template", "proposal" (see BIP 23), or omitted - // "capabilities":[ (array, optional) A list of strings - // "support" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid' - // ,... - // ], - // "rules":[ (array, optional) A list of strings - // "support" (string) client side supported softfork deployment - // ,... - // ] - // } - - return axios.get(`${this.restURL}mining/getBlockTemplate/${template_request}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.message); - }); - } - - getMiningInfo() { - // Returns a json object containing mining-related information. - // Result: - // { - // "blocks": nnn, (numeric) The current block - // "currentblocksize": nnn, (numeric) The last block size - // "currentblocktx": nnn, (numeric) The last block transaction - // "difficulty": xxx.xxxxx (numeric) The current difficulty - // "errors": "..." (string) Current errors - // "networkhashps": nnn, (numeric) The network hashes per second - // "pooledtx": n (numeric) The size of the mempool - // "chain": "xxxx", (string) current network name as defined in BIP70 (main, test, regtest) - // } - - return axios.get(`${this.restURL}mining/getMiningInfo`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getNetworkHashps(nblocks = 120, height = 1) { - // Returns the estimated network hashes per second based on the last n blocks. - // Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change. - // Pass in [height] to estimate the network speed at the time when a certain block was found. - // - // Arguments: - // 1. nblocks (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change. - // 2. height (numeric, optional, default=-1) To estimate at the time of the given height. - // - // Result: - // x (numeric) Hashes per second estimated - return axios.get(`${this.restURL}mining/getNetworkHashps?nblocks=${nblocks}&height=${height}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - submitBlock(hex, parameters) { - // Attempts to submit new block to network. - // The 'jsonparametersobject' parameter is currently ignored. - // See https://en.bitcoin.it/wiki/BIP_0022 for full specification. - // - // Arguments - // 1. "hex" (string, required) the hex-encoded block data to submit - // 2. "parameters" (string, optional) object of optional parameters - // { - // "workid" : "id" (string, optional) if the server provided a workid, it MUST be included with submissions - // } - // - let path = `${this.restURL}mining/submitBlock/${hex}`; - if(parameters) { - path = `${path}?parameters=${parameters}`; - } - return axios.post(path) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } -} - -export default Mining; diff --git a/src/Mnemonic.js b/src/Mnemonic.js deleted file mode 100644 index 957d7988..00000000 --- a/src/Mnemonic.js +++ /dev/null @@ -1,286 +0,0 @@ -import Crypto from './Crypto'; - -import BIP39 from 'bip39'; -import randomBytes from 'randombytes'; -import Bitcoin from 'bitcoincashjs-lib'; -import bchaddr from 'bchaddrjs'; -let Buffer = require('safe-buffer').Buffer - -class Mnemonic { - generate(bits = 128, wordlist) { - return BIP39.generateMnemonic(bits, randomBytes, wordlist); - } - - fromEntropy(bytes, wordlist) { - return BIP39.entropyToMnemonic(bytes, wordlist); - } - - toEntropy(mnemonic, wordlist) { - return Buffer.from(BIP39.mnemonicToEntropy(mnemonic, wordlist), 'hex'); - } - - validate(mnemonic, wordlist) { - // Preprocess the words - let words = mnemonic.split(' '); - // Detect blank phrase - if (words.length == 0) { - return "Blank mnemonic"; - } - // Check each word - for (let i = 0; i < words.length; i++) { - let word = words[i]; - if (wordlist.indexOf(word) == -1) { - // Finding closest match to word - let nearestWord = this.findNearestWord(word, wordlist); - return `${word} is not in wordlist, did you mean ${nearestWord}?`; - } - } - // Check the words are valid - let properPhrase = words.join(); - let isValid = BIP39.validateMnemonic(mnemonic, wordlist); - if (!isValid) { - return "Invalid mnemonic"; - } else { - return 'Valid mnemonic'; - } - } - - toSeed(mnemonic, password = '') { - return BIP39.mnemonicToSeed(mnemonic, password); - } - - wordLists() { - return BIP39.wordlists; - } - - toKeypairs(mnemonic, numberOfKeypairs = 1) { - let rootSeedBuffer = this.toSeed(mnemonic, ''); - let hdNode = Bitcoin.HDNode.fromSeedBuffer(rootSeedBuffer); - let HDPath = `44'/145'/0'/0/` - - let accounts = []; - - for (let i = 0; i < numberOfKeypairs; i++) { - let childHDNode = hdNode.derivePath(`${HDPath}${i}`); - accounts.push( - { - privateKeyWIF: childHDNode.keyPair.toWIF(), - address: bchaddr.toCashAddress(childHDNode.getAddress()) - } - ) - }; - return accounts; - } - - findNearestWord(word, wordlist) { - let minDistance = 99; - let closestWord = wordlist[0]; - for (let i = 0; i < wordlist.length; i++) { - let comparedTo = wordlist[i]; - if (comparedTo.indexOf(word) == 0) { - return comparedTo; - } - let distance = Levenshtein.get(word, comparedTo); - if (distance < minDistance) { - closestWord = comparedTo; - minDistance = distance; - } - } - return closestWord; - } -} - -export default Mnemonic; - -// The following code is from: https://raw.githubusercontent.com/iancoleman/bip39/7ff86d4c983f1e8c80b87b31acfd69fcf98c1b82/src/js/levenshtein.js - -/** - * Extend an Object with another Object's properties. - * - * The source objects are specified as additional arguments. - * - * @param dst Object the object to extend. - * - * @return Object the final object. - */ - -var _extend = function(dst) { - var sources = Array.prototype.slice.call(arguments, 1); - for (var i=0; i tmp) { - nextCol = tmp; - } - // deletion - tmp = prevRow[j + 1] + 1; - if (nextCol > tmp) { - nextCol = tmp; - } - - // copy current col value into previous (in preparation for next iteration) - prevRow[j] = curCol; - } - - // copy last col value into previous (in preparation for next iteration) - prevRow[j] = nextCol; - } - - return nextCol; - }, - - /** - * Asynchronously calculate levenshtein distance of the two strings. - * - * @param str1 String the first string. - * @param str2 String the second string. - * @param cb Function callback function with signature: function(Error err, int distance) - * @param [options] Object additional options. - * @param [options.progress] Function progress callback with signature: function(percentComplete) - */ - getAsync: function(str1, str2, cb, options) { - options = _extend({}, { - progress: null - }, options); - - // base cases - if (str1 === str2) return cb(null, 0); - if (str1.length === 0) return cb(null, str2.length); - if (str2.length === 0) return cb(null, str1.length); - - // two rows - var prevRow = new Array(str2.length + 1), - curCol, nextCol, - i, j, tmp, - startTime, currentTime; - - // initialise previous row - for (i=0; i tmp) { - nextCol = tmp; - } - // deletion - tmp = prevRow[j + 1] + 1; - if (nextCol > tmp) { - nextCol = tmp; - } - - // copy current into previous (in preparation for next iteration) - prevRow[j] = curCol; - - // get current time - currentTime = new Date().valueOf(); - } - - // send a progress update? - if (null !== options.progress) { - try { - options.progress.call(null, (i * 100.0/ str1.length)); - } catch (err) { - return cb('Progress callback: ' + err.toString()); - } - } - - // next iteration - _defer(__calculate); - }; - - __calculate(); - } - - }; diff --git a/src/Network.js b/src/Network.js deleted file mode 100644 index 3997e69a..00000000 --- a/src/Network.js +++ /dev/null @@ -1,299 +0,0 @@ -import axios from 'axios'; -class Network { - constructor(restURL) { - this.restURL = restURL; - } - - addNode(node, command){ - // Attempts add or remove a node from the addnode list. - // Or try a connection to a node once. - // - // Arguments: - // 1. "node" (string, required) The node (see getpeerinfo for nodes) - // 2. "command" (string, required) 'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once - // - - return axios.post(`${this.restURL}network/addNode/${node}/${command}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - clearBanned() { - //The clearbanned RPC clears list of banned nodes. - - // Parameters: none - - // Result—null on success - // JSON null when the list was cleared - - return axios.post(`${this.restURL}clearBanned`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - disconnectNode(configuration) { - // Immediately disconnects from the specified peer node. - // - // Strictly one out of 'configuration.address' and 'configuration.nodeid' can be provided to identify the node. - // - // To disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only. - // - // Arguments: - // 1. "configuration" (object, optional) - // Properties - // 1. "address" (string, optional) The IP address/port of the node - // 2. "nodeid" (number, optional) The node ID (see getpeerinfo for node IDs) - return axios.post(`${this.restURL}disconnectNode/${configuration}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getAddedNodeInfo(node) { - // Returns information about the given added node, or all added nodes - // (note that onetry addnodes are not listed here) - // - // Arguments: - // 1. "node" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned. - // - // Result: - // [ - // { - // "addednode" : "192.168.0.201", (string) The node ip address or name (as provided to addnode) - // "connected" : true|false, (boolean) If connected - // "addresses" : [ (list of objects) Only when connected = true - // { - // "address" : "192.168.0.201:8333", (string) The bitcoin server IP and port we're connected to - // "connected" : "outbound" (string) connection, inbound or outbound - // } - // ] - // } - // ,... - // ] - let path = `${this.restURL}network/getAddedNodeInfo`; - if(node) { - path = `${path}?node=${node}`; - } - - return axios.get(path) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getConnectionCount() { - // Returns the number of connections to other nodes. - // - // Result: - // n (numeric) The connection count - - return axios.get(`${this.restURL}network/getConnectionCount`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getNetTotals() { - // Returns information about network traffic, including bytes in, bytes out, and current time. - // - // Result: - // { - // "totalbytesrecv": n, (numeric) Total bytes received - // "totalbytessent": n, (numeric) Total bytes sent - // "timemillis": t, (numeric) Current UNIX time in milliseconds - // "uploadtarget": - // { - // "timeframe": n, (numeric) Length of the measuring timeframe in seconds - // "target": n, (numeric) Target in bytes - // "target_reached": true|false, (boolean) True if target is reached - // "serve_historical_blocks": true|false, (boolean) True if serving historical blocks - // "bytes_left_in_cycle": t, (numeric) Bytes left in current time cycle - // "time_left_in_cycle": t (numeric) Seconds left in current time cycle - // } - // } - - return axios.get(`${this.restURL}network/getNetTotals`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getNetworkInfo() { - // Returns an object containing various state info regarding P2P networking. - // - // Result: - // { - // "version": xxxxx, (numeric) the server version - // "subversion": "/Satoshi:x.x.x/", (string) the server subversion string - // "protocolversion": xxxxx, (numeric) the protocol version - // "localservices": "xxxxxxxxxxxxxxxx", (string) the services we offer to the network - // "localrelay": true|false, (bool) true if transaction relay is requested from peers - // "timeoffset": xxxxx, (numeric) the time offset - // "connections": xxxxx, (numeric) the number of connections - // "networkactive": true|false, (bool) whether p2p networking is enabled - // "networks": [ (array) information per network - // { - // "name": "xxx", (string) network (ipv4, ipv6 or onion) - // "limited": true|false, (boolean) is the network limited using -onlynet? - // "reachable": true|false, (boolean) is the network reachable? - // "proxy": "host:port" (string) the proxy that is used for this network, or empty if none - // "proxy_randomize_credentials": true|false, (string) Whether randomized credentials are used - // } - // ,... - // ], - // "relayfee": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in BCH/kB - // "incrementalfee": x.xxxxxxxx, (numeric) minimum fee increment for mempool limiting or BIP 125 replacement in BCH/kB - // "localaddresses": [ (array) list of local addresses - // { - // "address": "xxxx", (string) network address - // "port": xxx, (numeric) network port - // "score": xxx (numeric) relative score - // } - // ,... - // ] - // "warnings": "..." (string) any network warnings - // } - - return axios.get(`${this.restURL}network/getNetworkInfo`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getPeerInfo() { - // Returns data about each connected network node as a json array of objects. - // - // Result: - // [ - // { - // "id": n, (numeric) Peer index - // "addr":"host:port", (string) The ip address and port of the peer - // "addrlocal":"ip:port", (string) local address - // "services":"xxxxxxxxxxxxxxxx", (string) The services offered - // "relaytxes":true|false, (boolean) Whether peer has asked us to relay transactions to it - // "lastsend": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send - // "lastrecv": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive - // "bytessent": n, (numeric) The total bytes sent - // "bytesrecv": n, (numeric) The total bytes received - // "conntime": ttt, (numeric) The connection time in seconds since epoch (Jan 1 1970 GMT) - // "timeoffset": ttt, (numeric) The time offset in seconds - // "pingtime": n, (numeric) ping time (if available) - // "minping": n, (numeric) minimum observed ping time (if any at all) - // "pingwait": n, (numeric) ping wait (if non-zero) - // "version": v, (numeric) The peer version, such as 7001 - // "subver": "/Satoshi:0.8.5/", (string) The string version - // "inbound": true|false, (boolean) Inbound (true) or Outbound (false) - // "addnode": true|false, (boolean) Whether connection was due to addnode and is using an addnode slot - // "startingheight": n, (numeric) The starting height (block) of the peer - // "banscore": n, (numeric) The ban score - // "synced_headers": n, (numeric) The last header we have in common with this peer - // "synced_blocks": n, (numeric) The last block we have in common with this peer - // "inflight": [ - // n, (numeric) The heights of blocks we're currently asking from this peer - // ... - // ], - // "whitelisted": true|false, (boolean) Whether the peer is whitelisted - // "bytessent_per_msg": { - // "addr": n, (numeric) The total bytes sent aggregated by message type - // ... - // }, - // "bytesrecv_per_msg": { - // "addr": n, (numeric) The total bytes received aggregated by message type - // ... - // } - // } - // ,... - // ] - - return axios.get(`${this.restURL}network/getPeerInfo`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - // - // listBanned() { - // // List all banned IPs/Subnets. - // return axios.get(`${this.restURL}network/listBanned`) - // .then((response) => { - // return response.data; - // }) - // .catch((error) => { - // return JSON.stringify(error.response.data.error.message); - // }); - // } - - ping() { - // Requests that a ping be sent to all other nodes, to measure ping time. - // Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds. - // Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping. - - return axios.get(`${this.restURL}network/ping`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - // - // setBan(subnet, command, bantime, absolute) { - // // Attempts add or remove a IP/Subnet from the banned list. - // // - // // Arguments: - // // 1. "subnet" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip) - // // 2. "command" (string, required) 'add' to add a IP/Subnet to the list, 'remove' to remove a IP/Subnet from the list - // // 3. "bantime" (numeric, optional) time in seconds how long (or until when if [absolute] is set) the ip is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument) - // // 4. "absolute" (boolean, optional) If set, the bantime must be a absolute timestamp in seconds since epoch (Jan 1 1970 GMT) - // - // return axios.post(`${this.baseurl}network/setban/${subnet}/${command}`) - // .then((response) => { - // return response.data; - // }) - // .catch((error) => { - // return JSON.stringify(error.response.data.error.message); - // }); - // } - // - // setNetworkActive(state) { - // // Disable/enable all p2p network activity. - // // - // // Arguments: - // // 1. "state" (boolean, required) true to enable networking, false to disable - // - // return axios.post(`${this.baseurl}network/setNetworkActive/${state}`) - // .then((response) => { - // return response.data; - // }) - // .catch((error) => { - // return JSON.stringify(error.response.data.error.message); - // }); - // } -} - -export default Network; diff --git a/src/RawTransactions.js b/src/RawTransactions.js deleted file mode 100644 index 0e3da7ce..00000000 --- a/src/RawTransactions.js +++ /dev/null @@ -1,89 +0,0 @@ -import axios from 'axios'; -class RawTransactions { - constructor(restURL) { - this.restURL = restURL; - } - - decodeRawTransaction(hex) { - // decodes a serialized transaction hex string into a JSON object describing the transaction. - - // Parameter #1—serialized transaction in hex - - // Result—the decoded transaction - - return axios.get(`${this.restURL}rawtransactions/decodeRawTransaction/${hex}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - decodeScript(hex) { - // decodes a hex-encoded P2SH redeem script. - - // Parameter #1—a hex-encoded redeem script - - // Result—the decoded script - // console.log('decode script called *****', redeemScript) - - return axios.get(`${this.restURL}rawtransactions/decodeScript/${hex}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - getRawTransaction(txid, verbose = false) { - // NOTE: By default this function only works for mempool transactions. If the -txindex option is - // enabled, it also works for blockchain transactions. - // DEPRECATED: for now, it also works for transactions with unspent outputs. - // - // Return the raw transaction data. - // - // If verbose is 'true', returns an Object with information about 'txid'. - // If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'. - // - // Arguments: - // 1. "txid" (string, required) The transaction id - // 2. verbose (bool, optional, default=false) If false, return a string, otherwise return a json object - // - // Result (if verbose is not set or set to false): - // "data" (string) The serialized, hex-encoded data for 'txid' - - return axios.get(`${this.restURL}rawtransactions/getRawTransaction/${txid}?verbose=${verbose}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } - - sendRawTransaction(hex, allowhighfees = false) { - // Submits raw transaction (serialized, hex-encoded) to local node and network. - // - // Also see createrawtransaction and signrawtransaction calls. - // - // Arguments: - // 1. "hexstring" (string, required) The hex string of the raw transaction) - // 2. allowhighfees (boolean, optional, default=false) Allow high fees - // - // Result: - // "hex" (string) The transaction hash in hex - // - - return axios.post(`${this.restURL}rawtransactions/sendRawTransaction/${hex}?allowhighfees=${allowhighfees}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } -} - -export default RawTransactions; diff --git a/src/Script.js b/src/Script.js deleted file mode 100644 index a8cdd94f..00000000 --- a/src/Script.js +++ /dev/null @@ -1,66 +0,0 @@ -import Bitcoin from 'bitcoincashjs-lib'; -import opcodes from 'bitcoin-ops'; - -class Script { - constructor() { - this.opcodes = opcodes; - this.nullData = Bitcoin.script.nullData; - this.multisig = { - input: { - encode: (signatures) => { - let sigs = []; - signatures.forEach((sig) => { - sigs.push(sig); - }) - return Bitcoin.script.multisig.input.encode(sigs) - }, - decode: Bitcoin.script.multisig.input.decode, - check: Bitcoin.script.multisig.input.check, - }, - output: { - encode: (m, pubKeys) => { - let pks = []; - pubKeys.forEach((pubKey) => { - pks.push(pubKey); - }) - return Bitcoin.script.multisig.output.encode(m, pks); - }, - decode: Bitcoin.script.multisig.output.decode, - check: Bitcoin.script.multisig.output.check, - } - }; - this.pubKey = Bitcoin.script.pubKey; - this.pubKeyHash = Bitcoin.script.pubKeyHash; - this.scriptHash = Bitcoin.script.scriptHash; - } - - classifyInput(script) { - return Bitcoin.script.classifyInput(script); - } - - classifyOutput(script) { - return Bitcoin.script.classifyOutput(script); - } - - decode(scriptBuffer) { - return Bitcoin.script.decompile(scriptBuffer); - } - - encode(scriptChunks) { - let arr = []; - scriptChunks.forEach((chunk) => { - arr.push(chunk); - }); - return Bitcoin.script.compile(arr); - } - - toASM(buffer) { - return Bitcoin.script.toASM(buffer); - } - - fromASM(asm) { - return Bitcoin.script.fromASM(asm); - } -} - -export default Script; diff --git a/src/Transaction.js b/src/Transaction.js deleted file mode 100644 index 5ff4fa3d..00000000 --- a/src/Transaction.js +++ /dev/null @@ -1,40 +0,0 @@ -import Bitcoin from 'bitcoincashjs-lib'; -import axios from 'axios'; - -class Transaction { - constructor(restURL) { - this.restURL = restURL; - } - - transaction() { - return new Bitcoin.Transaction(); - } - - fromHex(hex) { - return Bitcoin.Transaction.fromHex(hex); - } - - transactionBuilder(network = 'bitcoin') { - return new Bitcoin.TransactionBuilder(Bitcoin.networks[network]); - } - - fromTransaction(tx) { - return Bitcoin.TransactionBuilder.fromTransaction(tx); - } - - details(txid) { - if(typeof txid !== 'string') { - txid = JSON.stringify(txid); - } - - return axios.get(`${this.restURL}transaction/details/${txid}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } -} - -export default Transaction; diff --git a/src/TransactionBuilder.js b/src/TransactionBuilder.js deleted file mode 100644 index a3709f7b..00000000 --- a/src/TransactionBuilder.js +++ /dev/null @@ -1,58 +0,0 @@ -import Bitcoin from 'bitcoincashjs-lib'; -import bchaddr from 'bchaddrjs'; -import coininfo from'coininfo'; -import bip68 from 'bip68'; - -class TransactionBuilder { - constructor(network = 'bitcoincash') { - let bitcoincash; - if(network === 'bitcoincash') { - bitcoincash = coininfo.bitcoincash.main; - } else { - bitcoincash = coininfo.bitcoincash.test; - } - let bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS(); - this.transaction = new Bitcoin.TransactionBuilder(bitcoincashBitcoinJSLib); - this.DEFAULT_SEQUENCE = 0xffffffff; - this.hashTypes = { - SIGHASH_ALL: 0x01, - SIGHASH_NONE: 0x02, - SIGHASH_SINGLE: 0x03, - SIGHASH_ANYONECANPAY: 0x80, - SIGHASH_BITCOINCASH_BIP143: 0x40, - ADVANCED_TRANSACTION_MARKER: 0x00, - ADVANCED_TRANSACTION_FLAG: 0x01 - }; - this.bip68 = bip68; - } - - addInput(txHash, vout, sequence = this.DEFAULT_SEQUENCE, prevOutScript) { - this.transaction.addInput( - txHash, - vout, - sequence, - prevOutScript - ); - } - - addOutput(scriptPubKey, amount) { - try { - this.transaction.addOutput(bchaddr.toLegacyAddress(scriptPubKey), amount); - } - catch(error) { - this.transaction.addOutput(scriptPubKey, amount); - } - } - - sign(vin, keyPair, redeemScript, hashType = this.hashTypes.SIGHASH_ALL, value) { - let witnessScript; - - this.transaction.sign(vin, keyPair, redeemScript, hashType, value, witnessScript); - } - - build() { - return this.transaction.build(); - } -} - -export default TransactionBuilder; diff --git a/src/Util.js b/src/Util.js deleted file mode 100644 index 85d29c52..00000000 --- a/src/Util.js +++ /dev/null @@ -1,38 +0,0 @@ -import axios from 'axios'; -class Util { - constructor(restURL) { - this.restURL = restURL; - } - - validateAddress(address) { - // Return information about the given bitcoin address. - // - // Arguments: - // 1. "address" (string, required) The bitcoin address to validate - // - // Result: - // { - // "isvalid" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned. - // "address" : "address", (string) The bitcoin address validated - // "scriptPubKey" : "hex", (string) The hex encoded scriptPubKey generated by the address - // "ismine" : true|false, (boolean) If the address is yours or not - // "iswatchonly" : true|false, (boolean) If the address is watchonly - // "isscript" : true|false, (boolean) If the key is a script - // "pubkey" : "publickeyhex", (string) The hex value of the raw public key - // "iscompressed" : true|false, (boolean) If the address is compressed - // "account" : "account" (string) DEPRECATED. The account associated with the address, "" is the default account - // "timestamp" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT) - // "hdkeypath" : "keypath" (string, optional) The HD keypath if the key is HD and available - // "hdmasterkeyid" : "" (string, optional) The Hash160 of the HD master pubkey - // } - return axios.get(`${this.restURL}util/validateAddress/${address}`) - .then((response) => { - return response.data; - }) - .catch((error) => { - return JSON.stringify(error.response.data.error.message); - }); - } -} - -export default Util; diff --git a/src/bitbox-cli.js b/src/bitbox-cli.js deleted file mode 100644 index 4448448b..00000000 --- a/src/bitbox-cli.js +++ /dev/null @@ -1,52 +0,0 @@ -// 3rd party deps -import axios from 'axios'; -import Bitcoin from 'bitcoincashjs-lib'; - -// local deps -import BitcoinCash from './BitcoinCash'; -import Crypto from './Crypto'; -import Util from './Util'; -import Block from './Block'; -import Blockchain from './Blockchain'; -import Control from './Control'; -import Generating from './Generating'; -import Mining from './Mining'; -import Network from './Network'; -import RawTransactions from './RawTransactions'; -import Mnemonic from './Mnemonic'; -import Address from './Address'; -import HDNode from './HDNode'; -import Transaction from './Transaction'; -import TransactionBuilder from './TransactionBuilder'; -import ECPair from './ECPair'; -import Script from './Script'; - -class BITBOXCli { - constructor(config) { - if(config && config.restURL && config.restURL !== '') { - this.restURL = config.restURL; - } else { - this.restURL = 'https://rest.bitbox.earth/v1/'; - } - - this.Address = new Address(this.restURL); - this.BitcoinCash = new BitcoinCash(); - this.Block = new Block(this.restURL); - this.Blockchain = new Blockchain(this.restURL); - this.Control = new Control(this.restURL); - this.Crypto = Crypto; - this.ECPair = ECPair; - this.Generating = new Generating(this.restURL); - this.HDNode = new HDNode(); - this.Mining = new Mining(this.restURL); - this.Mnemonic = new Mnemonic(); - this.Network = new Network(this.restURL); - this.RawTransactions = new RawTransactions(this.restURL); - this.Script = new Script(); - this.Transaction = new Transaction(this.restURL); - this.TransactionBuilder = TransactionBuilder; - this.Util = new Util(this.restURL); - } -} - -export default BITBOXCli; diff --git a/test/Address.js b/test/Address.js deleted file mode 100644 index f34d940c..00000000 --- a/test/Address.js +++ /dev/null @@ -1,598 +0,0 @@ -let fixtures = require('./fixtures/Address.json') -let chai = require('chai'); -let assert = require('assert'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let axios = require('axios'); -let sinon = require('sinon'); - -function flatten (arrays) { - return [].concat.apply([], arrays) -} - -let XPUBS = flatten([ - fixtures.mainnetXPub, - fixtures.testnetXPub -]) - -let LEGACY_ADDRESSES = flatten([ - fixtures.legacyMainnetP2PKH, - fixtures.legacyMainnetP2SH, - fixtures.legacyTestnetP2PKH -]); - -let mainnet_xpubs = []; -fixtures.mainnetXPub.forEach((f, i) => { - mainnet_xpubs.push(f.xpub); -}) -let MAINNET_ADDRESSES = flatten([ - mainnet_xpubs, - fixtures.legacyMainnetP2PKH, - fixtures.legacyMainnetP2SH, - fixtures.cashaddrMainnetP2PKH -]); - -let testnet_xpubs = []; -fixtures.testnetXPub.forEach((f, i) => { - testnet_xpubs.push(f.xpub); -}) -let TESTNET_ADDRESSES = flatten([ - testnet_xpubs, - fixtures.legacyTestnetP2PKH, - fixtures.cashaddrTestnetP2PKH -]); - -let CASHADDR_ADDRESSES = flatten([ - fixtures.cashaddrMainnetP2PKH, - fixtures.cashaddrMainnetP2SH, - fixtures.cashaddrTestnetP2PKH -]); - -let CASHADDR_ADDRESSES_NO_PREFIX = CASHADDR_ADDRESSES.map((address) => { - let parts = address.split(':'); - return parts[1]; -}) - -let P2PKH_ADDRESSES = flatten([ - fixtures.legacyMainnetP2PKH, - fixtures.legacyTestnetP2PKH, - fixtures.cashaddrMainnetP2PKH, - fixtures.cashaddrTestnetP2PKH -]) - -let P2SH_ADDRESSES = flatten([ - fixtures.legacyMainnetP2SH, - fixtures.cashaddrMainnetP2SH -]) - -describe('#addressConversion', () => { - describe('#toLegacyAddress', () => { - it('should translate legacy address format to itself correctly', () => { - assert.deepEqual( - LEGACY_ADDRESSES.map(BITBOX.Address.toLegacyAddress), - LEGACY_ADDRESSES - ); - }) - - it('should convert cashaddr address to legacy base58Check', () => { - assert.deepEqual( - CASHADDR_ADDRESSES.map(BITBOX.Address.toLegacyAddress), - LEGACY_ADDRESSES - ); - }); - - describe('errors', () => { - it('should fail when called with an invalid address', () => { - assert.throws(() => { - BITBOX.Address.toLegacyAddress() - }, BITBOX.BitcoinCash.InvalidAddressError) - assert.throws(() => { - BITBOX.Address.toLegacyAddress('some invalid address') - }, BITBOX.BitcoinCash.InvalidAddressError) - }) - }); - }); - - describe('#toCashAddress', () => { - it('should convert legacy base58Check address to cashaddr', () => { - assert.deepEqual( - LEGACY_ADDRESSES.map(address => BITBOX.Address.toCashAddress(address, true)), - CASHADDR_ADDRESSES - ); - }); - - it('should translate cashaddr address format to itself correctly', () => { - assert.deepEqual( - CASHADDR_ADDRESSES.map(address => BITBOX.Address.toCashAddress(address, true)), - CASHADDR_ADDRESSES - ); - }) - - it('should translate no-prefix cashaddr address format to itself correctly', () => { - assert.deepEqual( - CASHADDR_ADDRESSES_NO_PREFIX.map(address => BITBOX.Address.toCashAddress(address, true)), - CASHADDR_ADDRESSES - ) - }) - - it('should translate no-prefix cashaddr address format to itself correctly', () => { - CASHADDR_ADDRESSES.forEach((address) => { - let noPrefix = BITBOX.Address.toCashAddress(address, false); - assert.equal(address.split(':')[1], noPrefix); - }); - }) - - describe('errors', () => { - it('should fail when called with an invalid address', () => { - assert.throws(() => { - BITBOX.BitcoinCash.Addresst.oCashAddress() - }, BITBOX.BitcoinCash.InvalidAddressError) - assert.throws(() => { - BITBOX.BitcoinCash.Addresst.toCashAddress('some invalid address') - }, BITBOX.BitcoinCash.InvalidAddressError) - }) - }); - }); -}); - -describe('address format detection', () => { - - describe('#isLegacyAddress', () => { - describe('is legacy', () => { - LEGACY_ADDRESSES.forEach((address) => { - it(`should detect ${address} is a legacy base58Check address`, () => { - let isBase58Check = BITBOX.Address.isLegacyAddress(address); - assert.equal(isBase58Check, true); - }); - }); - }); - describe('is not legacy', () => { - CASHADDR_ADDRESSES.forEach((address) => { - it(`should detect ${address} is not a legacy address`, () => { - let isBase58Check = BITBOX.Address.isLegacyAddress(address); - assert.equal(isBase58Check, false); - }); - }); - }); - - describe('errors', () => { - it('should fail when called with an invalid address', () => { - assert.throws(() => { - BITBOX.Address.isLegacyAddress() - }, BITBOX.BitcoinCash.InvalidAddressError) - assert.throws(() => { - BITBOX.Address.isLegacyAddress('some invalid address') - }, BITBOX.BitcoinCash.InvalidAddressError) - }) - }); - }); - - describe('#isCashAddress', () => { - describe('is cashaddr', () => { - CASHADDR_ADDRESSES.forEach((address) => { - it(`should detect ${address} is a cashaddr address`, () => { - let isCashaddr = BITBOX.Address.isCashAddress(address); - assert.equal(isCashaddr, true); - }); - }); - }); - - describe('is not cashaddr', () => { - LEGACY_ADDRESSES.forEach((address) => { - it(`should detect ${address} is not a cashaddr address`, () => { - let isCashaddr = BITBOX.Address.isCashAddress(address); - assert.equal(isCashaddr, false); - }); - }); - }); - - describe('errors', () => { - it('should fail when called with an invalid address', () => { - assert.throws(() => { - BITBOX.Address.isCashAddress() - }, BITBOX.BitcoinCash.InvalidAddressError) - assert.throws(() => { - BITBOX.Address.isCashAddress('some invalid address') - }, BITBOX.BitcoinCash.InvalidAddressError) - }) - }); - }); -}); - -describe('network detection', () => { - - describe('#isMainnetAddress', () => { - describe('is mainnet', () => { - MAINNET_ADDRESSES.forEach((address) => { - it(`should detect ${address} is a mainnet address`, () => { - let isMainnet = BITBOX.Address.isMainnetAddress(address); - assert.equal(isMainnet, true); - }); - }); - }); - - describe('is not mainnet', () => { - TESTNET_ADDRESSES.forEach((address) => { - it(`should detect ${address} is not a mainnet address`, () => { - let isMainnet = BITBOX.Address.isMainnetAddress(address); - assert.equal(isMainnet, false); - }); - }); - }); - - describe('errors', () => { - it('should fail when called with an invalid address', () => { - assert.throws(() => { - BITBOX.Address.isMainnetAddress() - }, BITBOX.BitcoinCash.InvalidAddressError) - assert.throws(() => { - BITBOX.Address.isMainnetAddress('some invalid address') - }, BITBOX.BitcoinCash.InvalidAddressError) - }) - }); - }); - - describe('#isTestnetAddress', () => { - describe('is testnet', () => { - TESTNET_ADDRESSES.forEach((address) => { - it(`should detect ${address} is a testnet address`, () => { - let isTestnet = BITBOX.Address.isTestnetAddress(address); - assert.equal(isTestnet, true); - }); - }); - }); - - describe('is not testnet', () => { - MAINNET_ADDRESSES.forEach((address) => { - it(`should detect ${address} is not a testnet address`, () => { - let isTestnet = BITBOX.Address.isTestnetAddress(address); - assert.equal(isTestnet, false); - }); - }); - }); - - describe('errors', () => { - it('should fail when called with an invalid address', () => { - assert.throws(() => { - BITBOX.Address.isTestnetAddress() - }, BITBOX.BitcoinCash.InvalidAddressError) - assert.throws(() => { - BITBOX.Address.isTestnetAddress('some invalid address') - }, BITBOX.BitcoinCash.InvalidAddressError) - }) - }); - }); -}); - -describe('address type detection', () => { - describe('#isP2PKHAddress', () => { - describe('is P2PKH', () => { - P2PKH_ADDRESSES.forEach((address) => { - it(`should detect ${address} is a P2PKH address`, () => { - let isP2PKH = BITBOX.Address.isP2PKHAddress(address); - assert.equal(isP2PKH, true); - }); - }); - }); - - describe('is not P2PKH', () => { - P2SH_ADDRESSES.forEach((address) => { - it(`should detect ${address} is not a P2PKH address`, () => { - let isP2PKH = BITBOX.Address.isP2PKHAddress(address); - assert.equal(isP2PKH, false); - }); - }); - }); - - describe('errors', () => { - it('should fail when called with an invalid address', () => { - assert.throws(() => { - BITBOX.Address.isP2PKHAddress() - }, BITBOX.BitcoinCash.InvalidAddressError) - assert.throws(() => { - BITBOX.Address.isP2PKHAddress('some invalid address') - }, BITBOX.BitcoinCash.InvalidAddressError) - }) - }); - }); - - describe('#isP2SHAddress', () => { - describe('is P2SH', () => { - P2SH_ADDRESSES.forEach((address) => { - it(`should detect ${address} is a P2SH address`, () => { - let isP2SH = BITBOX.Address.isP2SHAddress(address); - assert.equal(isP2SH, true); - }); - }); - }); - - describe('is not P2SH', () => { - P2PKH_ADDRESSES.forEach((address) => { - it(`should detect ${address} is not a P2SH address`, () => { - let isP2SH = BITBOX.Address.isP2SHAddress(address); - assert.equal(isP2SH, false); - }); - }); - }); - - describe('errors', () => { - it('should fail when called with an invalid address', () => { - assert.throws(() => { - BITBOX.Address.isP2SHAddress() - }, BITBOX.BitcoinCash.InvalidAddressError) - assert.throws(() => { - BITBOX.Address.isP2SHAddress('some invalid address') - }, BITBOX.BitcoinCash.InvalidAddressError) - }) - }); - }); -}); - -describe('cashaddr prefix detection', () => { - it('should return the same result for detectAddressFormat', () => { - assert.deepEqual( - CASHADDR_ADDRESSES_NO_PREFIX.map(BITBOX.Address.detectAddressFormat), - CASHADDR_ADDRESSES.map(BITBOX.Address.detectAddressFormat) - ) - }) - it('should return the same result for detectAddressNetwork', () => { - assert.deepEqual( - CASHADDR_ADDRESSES_NO_PREFIX.map(BITBOX.Address.detectAddressNetwork), - CASHADDR_ADDRESSES.map(BITBOX.Address.detectAddressNetwork) - ) - }) - it('should return the same result for detectAddressType', () => { - assert.deepEqual( - CASHADDR_ADDRESSES_NO_PREFIX.map(BITBOX.Address.detectAddressType), - CASHADDR_ADDRESSES.map(BITBOX.Address.detectAddressType) - ) - }) - it('should return the same result for toLegacyAddress', () => { - assert.deepEqual( - CASHADDR_ADDRESSES_NO_PREFIX.map(BITBOX.Address.toLegacyAddress), - CASHADDR_ADDRESSES.map(BITBOX.Address.toLegacyAddress) - ) - }) - it('should return the same result for isLegacyAddress', () => { - assert.deepEqual( - CASHADDR_ADDRESSES_NO_PREFIX.map(BITBOX.Address.isLegacyAddress), - CASHADDR_ADDRESSES.map(BITBOX.Address.isLegacyAddress) - ) - }) - it('should return the same result for isCashAddress', () => { - assert.deepEqual( - CASHADDR_ADDRESSES_NO_PREFIX.map(BITBOX.Address.isCashAddress), - CASHADDR_ADDRESSES.map(BITBOX.Address.isCashAddress) - ) - }) - it('should return the same result for isMainnetAddress', () => { - assert.deepEqual( - CASHADDR_ADDRESSES_NO_PREFIX.map(BITBOX.Address.isMainnetAddress), - CASHADDR_ADDRESSES.map(BITBOX.Address.isMainnetAddress) - ) - }) - it('should return the same result for isTestnetAddress', () => { - assert.deepEqual( - CASHADDR_ADDRESSES_NO_PREFIX.map(BITBOX.Address.isTestnetAddress), - CASHADDR_ADDRESSES.map(BITBOX.Address.isTestnetAddress) - ) - }) - it('should return the same result for isP2PKHAddress', () => { - assert.deepEqual( - CASHADDR_ADDRESSES_NO_PREFIX.map(BITBOX.Address.isP2PKHAddress), - CASHADDR_ADDRESSES.map(BITBOX.Address.isP2PKHAddress) - ) - }) - it('should return the same result for isP2SHAddress', () => { - assert.deepEqual( - CASHADDR_ADDRESSES_NO_PREFIX.map(BITBOX.Address.isP2SHAddress), - CASHADDR_ADDRESSES.map(BITBOX.Address.isP2SHAddress) - ) - }) -}) - -describe('#detectAddressFormat', () => { - LEGACY_ADDRESSES.forEach((address) => { - it(`should detect ${address} is a legacy base58Check address`, () => { - let isBase58Check = BITBOX.Address.detectAddressFormat(address); - assert.equal(isBase58Check, 'legacy'); - }); - }); - - CASHADDR_ADDRESSES.forEach((address) => { - it(`should detect ${address} is a legacy cashaddr address`, () => { - let isCashaddr = BITBOX.Address.detectAddressFormat(address); - assert.equal(isCashaddr, 'cashaddr'); - }); - }); - - describe('errors', () => { - it('should fail when called with an invalid address', () => { - assert.throws(() => { - BITBOX.Address.detectAddressFormat() - }, BITBOX.BitcoinCash.InvalidAddressError) - assert.throws(() => { - BITBOX.Address.detectAddressFormat('some invalid address') - }, BITBOX.BitcoinCash.InvalidAddressError) - }) - }); -}); - -describe('#detectAddressNetwork', () => { - MAINNET_ADDRESSES.forEach((address) => { - it(`should detect ${address} is a mainnet address`, () => { - let isMainnet = BITBOX.Address.detectAddressNetwork(address); - assert.equal(isMainnet, 'mainnet'); - }) - }); - - TESTNET_ADDRESSES.forEach((address) => { - it(`should detect ${address} is a testnet address`, () => { - let isTestnet = BITBOX.Address.detectAddressNetwork(address); - assert.equal(isTestnet, 'testnet'); - }); - }); - - describe('errors', () => { - it('should fail when called with an invalid address', () => { - assert.throws(() => { - BITBOX.Address.detectAddressNetwork() - }, BITBOX.BitcoinCash.InvalidAddressError) - assert.throws(() => { - BITBOX.Address.detectAddressNetwork('some invalid address') - }, BITBOX.BitcoinCash.InvalidAddressError) - }); - }); -}); - -describe('#detectAddressType', () => { - P2PKH_ADDRESSES.forEach((address) => { - it(`should detect ${address} is a P2PKH address`, () => { - let isP2PKH = BITBOX.Address.detectAddressType(address); - assert.equal(isP2PKH, 'p2pkh'); - }) - }); - - P2SH_ADDRESSES.forEach((address) => { - it(`should detect ${address} is a P2SH address`, () => { - let isP2SH = BITBOX.Address.detectAddressType(address); - assert.equal(isP2SH, 'p2sh'); - }) - }); - - describe('errors', () => { - it('should fail when called with an invalid address', () => { - assert.throws(() => { - BITBOX.Address.detectAddressType() - }, BITBOX.BitcoinCash.InvalidAddressError) - assert.throws(() => { - BITBOX.Address.detectAddressType('some invalid address') - }, BITBOX.BitcoinCash.InvalidAddressError) - }) - }); -}); - -describe('#fromXPub', () => { - XPUBS.forEach((xpub, i) => { - xpub.addresses.forEach((address, j) => { - it(`generate public external change address ${j} for ${xpub.xpub}`, () => { - assert.equal(BITBOX.Address.fromXPub(xpub.xpub, `0/${j}`), address); - }); - }); - }); -}); - -describe('#details', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get details', (done) => { - let data = { - "legacyAddress": "3CnzuFFbtgVyHNiDH8BknGo3PQ3dpdThgJ", - "cashAddress": "bitcoincash:ppuukp49np467kyzxl0fkla34rmgcddhvc33ce2d6l", - "balance": 300.0828874, - "balanceSat": 30008288740, - "totalReceived": 12945.45174649, - "totalReceivedSat": 1294545174649, - "totalSent": 12645.36885909, - "totalSentSat": 1264536885909, - "unconfirmedBalance": 0, - "unconfirmedBalanceSat": 0, - "unconfirmedTxApperances": 0, - "txApperances": 1042, - "transactions": [ - "b29425a876f62e114508e67e66b5eb1ab0d320d7c9a57fb0ece086a36e2b7309" - ] - }; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Address.details('bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf') - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); -}); - -describe('#utxo', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get utxo', (done) => { - let data = [ - { - "legacyAddress": "3CnzuFFbtgVyHNiDH8BknGo3PQ3dpdThgJ", - "cashAddress": "bitcoincash:ppuukp49np467kyzxl0fkla34rmgcddhvc33ce2d6l", - "txid": "6f56254424378d6914cebd097579c70664843e5876ca86f0bf412ba7f3928326", - "vout": 0, - "scriptPubKey": "a91479cb06a5986baf588237de9b7fb1a8f68c35b76687", - "amount": 12.5002911, - "satoshis": 1250029110, - "height": 528745, - "confirmations": 17 - }, - { - "legacyAddress": "3CnzuFFbtgVyHNiDH8BknGo3PQ3dpdThgJ", - "cashAddress": "bitcoincash:ppuukp49np467kyzxl0fkla34rmgcddhvc33ce2d6l", - "txid": "b29425a876f62e114508e67e66b5eb1ab0d320d7c9a57fb0ece086a36e2b7309", - "vout": 0, - "scriptPubKey": "a91479cb06a5986baf588237de9b7fb1a8f68c35b76687", - "amount": 12.50069247, - "satoshis": 1250069247, - "height": 528744, - "confirmations": 18 - } - ]; - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Address.utxo('bitcoincash:ppuukp49np467kyzxl0fkla34rmgcddhvc33ce2d6l') - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); -}); - -describe('#unconfirmed', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get unconfirmed transactions', (done) => { - let data = [ - { - "txid": "e0aadd861a06993e39af932bb0b9ad69e7b37ef5843a13c6724789e1c94f3513", - "vout": 1, - "scriptPubKey": "76a914a0f531f4ff810a415580c12e54a7072946bb927e88ac", - "amount": 0.00008273, - "satoshis": 8273, - "confirmations": 0, - "ts": 1526680569, - "legacyAddress": "1Fg4r9iDrEkCcDmHTy2T79EusNfhyQpu7W", - "cashAddress": "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c" - } - ]; - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Address.unconfirmed('bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c') - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); -}); diff --git a/test/BitcoinCash.js b/test/BitcoinCash.js deleted file mode 100644 index 6413f98a..00000000 --- a/test/BitcoinCash.js +++ /dev/null @@ -1,223 +0,0 @@ -let fixtures = require('./fixtures/BitcoinCash.json') -let chai = require('chai'); -let assert = require('assert'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); - -// TODO -// 1. generate testnet p2sh -// 2. generate cashaddr mainnet p2sh -// 3. generate cashaddr testnet p2sh -// 4. create BITBOX fromBase58 method -// * confirm xpub cannot generate WIF -// * confirm xpriv can generate WIF -// 5. create fromXPriv method w/ tests and docs - // 1. mainnet - // * confirm xpriv generates address - // * confirm xpriv generates WIF - // 2. testnet - // * confirm xpriv generates address - // * confirm xpriv generates WIF -// 6. More error test cases. - -describe('#BitcoinCash', () => { - describe('price conversion', () => { - describe('#toBitcoinCash', () => { - fixtures.conversion.toBCH.satoshis.forEach((satoshi) => { - it(`should convert ${satoshi[0]} Satoshis to ${satoshi[1]} $BCH`, () => { - assert.equal(BITBOX.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1]); - }); - }); - - fixtures.conversion.toBCH.strings.forEach((satoshi) => { - it(`should convert "${satoshi[0]}" Satoshis as a string to ${satoshi[1]} $BCH`, () => { - assert.equal(BITBOX.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1]); - }); - }); - - fixtures.conversion.toBCH.not.forEach((bch) => { - it(`converts ${bch[0]} to Bitcoin Cash, not to ${bch[1]} Satoshi`, () => { - assert.notEqual(BITBOX.BitcoinCash.toBitcoinCash(bch[0]), bch[1]); - }); - }); - - fixtures.conversion.toBCH.rounding.forEach((satoshi) => { - it(`rounding ${satoshi[0]} to ${satoshi[1]} $BCH`, () => { - assert.equal(BITBOX.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1]); - }); - }); - }); - - describe('#toSatoshi', () => { - fixtures.conversion.toSatoshi.bch.forEach((bch) => { - it(`should convert ${bch[0]} $BCH to ${bch[1]} Satoshis`, () => { - assert.equal(BITBOX.BitcoinCash.toSatoshi(bch[0]), bch[1]); - }); - }); - - fixtures.conversion.toSatoshi.strings.forEach((bch) => { - it(`should convert "${bch[0]}" $BCH as a string to ${bch[1]} Satoshis`, () => { - assert.equal(BITBOX.BitcoinCash.toSatoshi(bch[0]), bch[1]); - }); - }); - - fixtures.conversion.toSatoshi.not.forEach((satoshi) => { - it(`converts ${satoshi[0]} to Satoshi, not to ${satoshi[1]} Bitcoin Cash`, () => { - assert.notEqual(BITBOX.BitcoinCash.toSatoshi(satoshi[0]), satoshi[1]); - }); - }); - - fixtures.conversion.toSatoshi.rounding.forEach((bch) => { - it(`rounding ${bch[0]} to ${bch[1]} Satoshi`, () => { - assert.equal(BITBOX.BitcoinCash.toSatoshi(bch[0]), bch[1]); - }); - }); - }); - - describe('#toBits', () => { - fixtures.conversion.toBits.bch.forEach((bch) => { - it(`should convert ${bch[0]} BCH to ${bch[1]} bits`, () => { - assert.equal(BITBOX.BitcoinCash.toBits(BITBOX.BitcoinCash.toSatoshi(bch[0])), bch[1]); - }); - }); - - fixtures.conversion.toBits.strings.forEach((bch) => { - it(`should convert "${bch[0]}" BCH as a string to ${bch[1]} bits`, () => { - assert.equal(BITBOX.BitcoinCash.toBits(BITBOX.BitcoinCash.toSatoshi(bch[0])), bch[1]); - }); - }); - }); - - describe('#fromBits', () => { - fixtures.conversion.fromBits.bch.forEach((bch) => { - it(`should convert ${bch[1]} bits to ${bch[0]} BCH`, () => { - assert.equal(BITBOX.BitcoinCash.toBitcoinCash(BITBOX.BitcoinCash.fromBits(bch[1])), bch[0]); - }); - }); - - fixtures.conversion.fromBits.strings.forEach((bch) => { - it(`should convert "${bch[0]}" bits as a string to ${bch[1]} BCH`, () => { - assert.equal(BITBOX.BitcoinCash.toBitcoinCash(BITBOX.BitcoinCash.fromBits(bch[1])), bch[0]); - }); - }); - }); - }); - - describe('sign and verify messages', () => { - describe('#signMessageWithPrivKey', () => { - fixtures.signatures.sign.forEach((sign) => { - it(`should sign a message w/ ${sign.network} ${sign.privateKeyWIF}`, () => { - let privateKeyWIF = sign.privateKeyWIF; - let message = sign.message; - let signature = BITBOX.BitcoinCash.signMessageWithPrivKey(privateKeyWIF, message) - assert.equal(signature, sign.signature); - }); - }); - }); - - describe('#verifyMessage', () => { - fixtures.signatures.verify.forEach((sign) => { - it(`should verify a valid signed message from ${sign.network} cashaddr address ${sign.address}`, () => { - assert.equal(BITBOX.BitcoinCash.verifyMessage(sign.address, sign.signature, sign.message), true); - }); - }); - - fixtures.signatures.verify.forEach((sign) => { - let legacyAddress = BITBOX.Address.toLegacyAddress(sign.address); - it(`should verify a valid signed message from ${sign.network} legacy address ${legacyAddress}`, () => { - assert.equal(BITBOX.BitcoinCash.verifyMessage(legacyAddress, sign.signature, sign.message), true); - }); - }); - - fixtures.signatures.verify.forEach((sign) => { - let legacyAddress = BITBOX.Address.toLegacyAddress(sign.address); - it(`should not verify an invalid signed message from ${sign.network} cashaddr address ${sign.address}`, () => { - assert.equal(BITBOX.BitcoinCash.verifyMessage(sign.address, sign.signature, 'nope'), false); - }); - }); - }); - }); - - describe('encode and decode to base58Check', () => { - describe('#encodeBase58Check', () => { - fixtures.encodeBase58Check.forEach((base58Check, i) => { - it(`encode ${base58Check.hex} as base58Check ${base58Check.base58Check}`, () => { - assert.equal(BITBOX.BitcoinCash.encodeBase58Check(base58Check.hex), base58Check.base58Check); - }); - }); - }); - - describe('#decodeBase58Check', () => { - fixtures.encodeBase58Check.forEach((base58Check, i) => { - it(`decode ${base58Check.base58Check} as ${base58Check.hex}`, () => { - assert.equal(BITBOX.BitcoinCash.decodeBase58Check(base58Check.base58Check), base58Check.hex); - }); - }); - }); - }); - - describe('encode and decode BIP21 urls', () => { - describe('#encodeBIP21', () => { - fixtures.bip21.valid.forEach((bip21, i) => { - it(`encode ${bip21.address} as url`, () => { - let url = BITBOX.BitcoinCash.encodeBIP21(bip21.address, bip21.options) - assert.equal(url, bip21.url); - }); - }); - }); - - describe('#decodeBIP21', () => { - fixtures.bip21.valid.forEach((bip21, i) => { - it(`decodes ${bip21.url}`, () => { - let decoded = BITBOX.BitcoinCash.decodeBIP21(bip21.url); - assert.equal(decoded.options.amount, bip21.options.amount); - assert.equal(decoded.options.label, bip21.options.label); - assert.equal(BITBOX.Address.toCashAddress(decoded.address), BITBOX.Address.toCashAddress(bip21.address)); - }); - }); - }); - }); - - describe('#getByteCount', () => { - fixtures.getByteCount.forEach((fixture) => { - it(`get byte count`, () => { - let byteCount = BITBOX.BitcoinCash.getByteCount(fixture.inputs, fixture.outputs); - assert.equal(byteCount, fixture.byteCount); - }); - }); - }); - - describe('#bip38', () => { - describe('#encryptBIP38', () => { - fixtures.bip38.encrypt.mainnet.forEach((fixture) => { - it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on mainnet`, () => { - let encryptedKey = BITBOX.BitcoinCash.encryptBIP38(fixture.wif, fixture.password); - assert.equal(encryptedKey, fixture.encryptedKey); - }); - }); - - fixtures.bip38.encrypt.testnet.forEach((fixture) => { - it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on testnet`, () => { - let encryptedKey = BITBOX.BitcoinCash.encryptBIP38(fixture.wif, fixture.password); - assert.equal(encryptedKey, fixture.encryptedKey); - }); - }); - }); - - describe('#decryptBIP38', () => { - fixtures.bip38.decrypt.mainnet.forEach((fixture) => { - it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on mainnet`, () => { - let wif = BITBOX.BitcoinCash.decryptBIP38(fixture.encryptedKey, fixture.password, 'mainnet'); - assert.equal(wif, fixture.wif); - }); - }); - - fixtures.bip38.decrypt.testnet.forEach((fixture) => { - it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on testnet`, () => { - let wif = BITBOX.BitcoinCash.decryptBIP38(fixture.encryptedKey, fixture.password, 'testnet'); - assert.equal(wif, fixture.wif); - }); - }); - }); - }); -}); diff --git a/test/Block.js b/test/Block.js deleted file mode 100644 index 98c36662..00000000 --- a/test/Block.js +++ /dev/null @@ -1,48 +0,0 @@ -let chai = require('chai'); -let assert = require('assert'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let axios = require('axios'); -let sinon = require('sinon'); - -describe('#Block', () => { - describe('#details', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get block details', (done) => { - let data = { - hash: '000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0', - size: 216, - height: 507, - version: 1, - merkleroot: 'a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8', - tx: - [ 'a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8' ], - time: 1231973656, - nonce: 330467862, - bits: '1d00ffff', - difficulty: 1, - chainwork: '000000000000000000000000000000000000000000000000000001fc01fc01fc', - confirmations: 528402, - previousblockhash: '00000000a99525c043fd7e323414b60add43c254c44860094048f9c01e9a5fdd', - nextblockhash: '000000000d550f4161f2702165fdd782ec72ff9c541f864ebb8256b662b7e51a', - reward: 50, - isMainChain: true, - poolInfo: {} - }; - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Block.details('000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0') - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); -}); diff --git a/test/Blockchain.js b/test/Blockchain.js deleted file mode 100644 index b8541491..00000000 --- a/test/Blockchain.js +++ /dev/null @@ -1,456 +0,0 @@ -// let fixtures = require('./fixtures/BitcoinCash.json') -let chai = require('chai'); -let assert = require('assert'); -let axios = require('axios'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let sinon = require('sinon'); - -describe('#Blockchain', () => { - describe('#getBestBlockHash', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get best block hash', (done) => { - const resolved = new Promise((r) => r({ data: '0000000000000000005f1f550d3d8b142b684277016ebd00fa29c668606ae52d' })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.getBestBlockHash() - .then((result) => { - let hash = '0000000000000000005f1f550d3d8b142b684277016ebd00fa29c668606ae52d'; - assert.equal(hash, result); - }) - .then(done, done); - }); - }); - - describe('#getBlock', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = { - hash: '00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09', - confirmations: 526807, - size: 216, - height: 1000, - version: 1, - versionHex: '00000001', - merkleroot: 'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33', - tx: - [ 'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33' ], - time: 1232346882, - mediantime: 1232344831, - nonce: 2595206198, - bits: '1d00ffff', - difficulty: 1, - chainwork: '000000000000000000000000000000000000000000000000000003e903e903e9', - previousblockhash: '0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d', - nextblockhash: '00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6' - }; - - it('should get block by hash', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.getBlock("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09") - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getBlockchainInfo', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = { - chain: 'main', - blocks: 527810, - headers: 527810, - bestblockhash: '000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0', - difficulty: 576023394804.6666, - mediantime: 1524878499, - verificationprogress: 0.9999990106793685, - chainwork: '00000000000000000000000000000000000000000096da5b040913fa09249b4e', - pruned: false, - softforks: - [ { id: 'bip34', version: 2, reject: [Object] }, - { id: 'bip66', version: 3, reject: [Object] }, - { id: 'bip65', version: 4, reject: [Object] } ], - bip9_softforks: - { csv: - { status: 'active', - startTime: 1462060800, - timeout: 1493596800, - since: 419328 - } - } - }; - - it('should get blockchain info', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.getBlockchainInfo() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getBlockCount', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = 527810; - - it('should get block count', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.getBlockCount() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getBlockHash', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = '000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0'; - - it('should get block hash by height', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.getBlockHash(527810) - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getBlockHeader', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = { - hash: '000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0', - confirmations: 1, - height: 527810, - version: 536870912, - versionHex: '20000000', - merkleroot: '9298432bbebe4638456aa19cb7ef91639da87668a285d88d0ecd6080424d223b', - time: 1524881438, - mediantime: 1524878499, - nonce: 3326843941, - bits: '1801e8a5', - difficulty: 576023394804.6666, - chainwork: '00000000000000000000000000000000000000000096da5b040913fa09249b4e', - previousblockhash: '000000000000000000b33251708bc7a7b4540e61880d8c376e8e2db6a19a4789' - }; - - it('should get block header by hash', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.getBlockHeader('000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0', true) - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getDifficulty', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = '577528469277.1339'; - - it('should get difficulty', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.getDifficulty() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getMempoolAncestors', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = "Transaction not in mempool"; - - it('should get mempool ancestors', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.getMempoolAncestors('daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88', true) - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getMempoolDescendants', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = { - result: "Transaction not in mempool" - }; - - it('should get mempool descendants', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.getMempoolDescendants('daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88', true) - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getMempoolEntry', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = { - result: "Transaction not in mempool" - }; - - it('should get mempool entry', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.getMempoolEntry('daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88') - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getMempoolInfo', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = { - result: { - size: 317, - bytes: 208583, - usage: 554944, - maxmempool: 300000000, - mempoolminfee: 0 - } - }; - - it('should get mempool info', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.getMempoolInfo() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getRawMempool', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = { - result: { - transactions: [ - { - txid: 'ab36d68dd0a618592fe34e4a898e8beeeb4049133547dbb16f9338384084af96', - size: 191, - fee: 0.00047703, - modifiedfee: 0.00047703, - time: 1524883317, - height: 527811, - startingpriority: 5287822727.272727, - currentpriority: 5287822727.272727, - descendantcount: 1, - descendantsize: 191, - descendantfees: 47703, - ancestorcount: 1, - ancestorsize: 191, - ancestorfees: 47703, - depends: [] - }] - } - }; - - it('should get mempool info', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.getRawMempool() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getTxOut', () => { - // TODO finish this test - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = { - result: { } - }; - - it('should get TODO', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.getTxOut('daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88', 0, true) - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#preciousBlock', () => { - // TODO finish this test - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = { - result: { } - }; - - it('should get TODO', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.preciousBlock() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#pruneBlockchain', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = "Cannot prune blocks because node is not in prune mode."; - - it('should prune blockchain', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'post').returns(resolved); - - BITBOX.Blockchain.pruneBlockchain(507) - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#verifyChain', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = true; - - it('should verify blockchain', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.verifyChain(3, 6) - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#verifyTxOutProof', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - let data = "proof must be hexadecimal string (not '')"; - - it('should verify utxo proof', (done) => { - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Blockchain.verifyTxOutProof(3, 6) - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); -}); diff --git a/test/Control.js b/test/Control.js deleted file mode 100644 index 1b6aa3e7..00000000 --- a/test/Control.js +++ /dev/null @@ -1,72 +0,0 @@ -// let fixtures = require('./fixtures/BitcoinCash.json') -let chai = require('chai'); -let assert = require('assert'); -let axios = require('axios'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let sinon = require('sinon'); - -describe('#Control', () => { - describe('#getInfo', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get info', (done) => { - let data = { - version: 170000, - protocolversion: 70015, - blocks: 527813, - timeoffset: 0, - connections: 21, - proxy: '', - difficulty: 581086703759.5878, - testnet: false, - paytxfee: 0, - relayfee: 0.00001, - errors: '' - }; - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Control.getInfo() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getMemoryInfo', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get memory info', (done) => { - let data = { - locked: { - used: 0, - free: 65536, - total: 65536, - locked: 65536, - chunks_used: 0, - chunks_free: 1 - } - }; - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Control.getMemoryInfo() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); -}); diff --git a/test/Crypto.js b/test/Crypto.js deleted file mode 100644 index ef84bdf7..00000000 --- a/test/Crypto.js +++ /dev/null @@ -1,101 +0,0 @@ -let fixtures = require('./fixtures/Crypto.json') -let chai = require('chai'); -let assert = require('assert'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let Buffer = require('safe-buffer').Buffer - -describe('#Crypto', () => { - describe('#sha256', () => { - fixtures.sha256.forEach((fixture) => { - it(`should create SHA256Hash hex encoded ${fixture.hash} from ${fixture.hex}`, () => { - let data = Buffer.from(fixture.hex, 'hex') - let sha256Hash = BITBOX.Crypto.sha256(data).toString('hex'); - assert.equal(sha256Hash, fixture.hash); - }); - - it(`should create 64 character SHA256Hash hex encoded`, () => { - let data = Buffer.from(fixture.hex, 'hex') - let sha256Hash = BITBOX.Crypto.sha256(data).toString('hex'); - assert.equal(sha256Hash.length, 64); - }); - }); - }); - - describe('#ripemd160', () => { - fixtures.ripemd160.forEach((fixture) => { - it(`should create RIPEMD160Hash hex encoded ${fixture.hash} from ${fixture.hex}`, () => { - let data = Buffer.from(fixture.hex, 'hex') - let ripemd160 = BITBOX.Crypto.ripemd160(data).toString('hex'); - assert.equal(ripemd160, fixture.hash); - }); - - it(`should create 64 character RIPEMD160Hash hex encoded`, () => { - let data = Buffer.from(fixture.hex, 'hex') - let ripemd160 = BITBOX.Crypto.ripemd160(data).toString('hex'); - assert.equal(ripemd160.length, 40); - }); - }); - }); - - describe('#hash256', () => { - fixtures.hash256.forEach((fixture) => { - it(`should create double SHA256 Hash hex encoded ${fixture.hash} from ${fixture.hex}`, () => { - let data = Buffer.from(fixture.hex, 'hex') - let hash256 = BITBOX.Crypto.hash256(data).toString('hex'); - assert.equal(hash256, fixture.hash); - }); - - it(`should create 64 character SHA256 Hash hex encoded`, () => { - let data = Buffer.from(fixture.hex, 'hex') - let hash256 = BITBOX.Crypto.hash256(data).toString('hex'); - assert.equal(hash256.length, 64); - }); - }); - }); - - describe('#hash160', () => { - fixtures.hash160.forEach((fixture) => { - it(`should create RIPEMD160(SHA256()) hex encoded ${fixture.hash} from ${fixture.hex}`, () => { - let data = Buffer.from(fixture.hex, 'hex') - let hash160 = BITBOX.Crypto.hash160(data).toString('hex'); - assert.equal(hash160, fixture.hash); - }); - - it(`should create 64 character SHA256Hash hex encoded`, () => { - let data = Buffer.from(fixture.hex, 'hex') - let hash160 = BITBOX.Crypto.hash160(data).toString('hex'); - assert.equal(hash160.length, 40); - }); - }); - }); - - describe('#randomBytes', () => { - for(let i = 0; i < 6; i++) { - it('should return 16 bytes of entropy hex encoded', () => { - let entropy = BITBOX.Crypto.randomBytes(16); - assert.equal(Buffer.byteLength(entropy), 16); - }); - - it('should return 20 bytes of entropy hex encoded', () => { - let entropy = BITBOX.Crypto.randomBytes(20); - assert.equal(Buffer.byteLength(entropy), 20); - }); - - it('should return 24 bytes of entropy hex encoded', () => { - let entropy = BITBOX.Crypto.randomBytes(24); - assert.equal(Buffer.byteLength(entropy), 24); - }); - - it('should return 28 bytes of entropy hex encoded', () => { - let entropy = BITBOX.Crypto.randomBytes(28); - assert.equal(Buffer.byteLength(entropy), 28); - }); - - it('should return 32 bytes of entropy hex encoded', () => { - let entropy = BITBOX.Crypto.randomBytes(32); - assert.equal(Buffer.byteLength(entropy), 32); - }); - } - }); -}); diff --git a/test/ECPair.js b/test/ECPair.js deleted file mode 100644 index dc818bab..00000000 --- a/test/ECPair.js +++ /dev/null @@ -1,111 +0,0 @@ -let fixtures = require('./fixtures/ECPair.json') -let chai = require('chai'); -let assert = require('assert'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let script = BITBOX.Script; -let Buffer = require('safe-buffer').Buffer - -describe('#ECPair', () => { - describe('#fromWIF', () => { - fixtures.fromWIF.forEach((fixture) => { - it(`should create ECPair from WIF ${fixture.privateKeyWIF}`, () => { - let ecpair = BITBOX.ECPair.fromWIF(fixture.privateKeyWIF); - assert.equal(typeof ecpair, 'object'); - }) - - it(`should get ${fixture.legacy} legacy address`, () => { - let legacy = BITBOX.ECPair.fromWIF(fixture.privateKeyWIF); - assert.equal(BITBOX.HDNode.toLegacyAddress(legacy), fixture.legacy); - }) - - it(`should get ${fixture.cashAddr} cash address`, () => { - let cashAddr = BITBOX.ECPair.fromWIF(fixture.privateKeyWIF); - assert.equal(BITBOX.HDNode.toCashAddress(cashAddr), fixture.cashAddr); - }) - }); - }); - - describe('#toWIF', () => { - fixtures.toWIF.forEach((fixture) => { - it(`should get WIF ${fixture.privateKeyWIF} from ECPair`, () => { - let ecpair = BITBOX.ECPair.fromWIF(fixture.privateKeyWIF); - let wif = BITBOX.ECPair.toWIF(ecpair); - assert.equal(wif, fixture.privateKeyWIF); - }) - }); - }); - - describe('#fromPublicKey', () => { - fixtures.fromPublicKey.forEach((fixture) => { - it(`should create ECPair from public key buffer`, () => { - let ecpair = BITBOX.ECPair.fromPublicKey(Buffer.from(fixture.pubkeyHex, 'hex')); - assert.equal(typeof ecpair, 'object'); - }); - - it(`should get ${fixture.legacy} legacy address`, () => { - let ecpair = BITBOX.ECPair.fromPublicKey(Buffer.from(fixture.pubkeyHex, 'hex')); - assert.equal(BITBOX.HDNode.toLegacyAddress(ecpair), fixture.legacy); - }) - - it(`should get ${fixture.cashAddr} cash address`, () => { - let ecpair = BITBOX.ECPair.fromPublicKey(Buffer.from(fixture.pubkeyHex, 'hex')); - assert.equal(BITBOX.HDNode.toCashAddress(ecpair), fixture.cashAddr); - }) - }); - }); - - describe('#toPublicKey', () => { - fixtures.toPublicKey.forEach((fixture) => { - it(`should create a public key buffer from an ECPair`, () => { - let ecpair = BITBOX.ECPair.fromPublicKey(Buffer.from(fixture.pubkeyHex, 'hex')); - let pubkeyBuffer = BITBOX.ECPair.toPublicKey(ecpair); - assert.equal(typeof pubkeyBuffer, 'object'); - }); - }); - }); - - describe('#toLegacyAddress', () => { - fixtures.toLegacyAddress.forEach((fixture) => { - it(`should create legacy address ${fixture.legacy} from an ECPair`, () => { - let ecpair = BITBOX.ECPair.fromWIF(fixture.privateKeyWIF); - let legacyAddress = BITBOX.ECPair.toLegacyAddress(ecpair); - assert.equal(legacyAddress, fixture.legacy); - }); - }); - }); - - describe('#toCashAddress', () => { - fixtures.toCashAddress.forEach((fixture) => { - it(`should create cash address ${fixture.cashAddr} from an ECPair`, () => { - let ecpair = BITBOX.ECPair.fromWIF(fixture.privateKeyWIF); - let cashAddr = BITBOX.ECPair.toCashAddress(ecpair); - assert.equal(cashAddr, fixture.cashAddr); - }); - }); - }); - - describe('#sign', () => { - fixtures.sign.forEach((fixture) => { - it(`should sign 32 byte hash buffer`, () => { - let ecpair = BITBOX.ECPair.fromWIF(fixture.privateKeyWIF); - let buf = Buffer.from(BITBOX.Crypto.sha256(fixture.data), 'hex'); - let signatureBuf = BITBOX.ECPair.sign(ecpair, buf); - assert.equal(typeof signatureBuf, 'object'); - }); - }); - }); - - describe('#verify', () => { - fixtures.verify.forEach((fixture) => { - it(`should verify signed 32 byte hash buffer`, () => { - let ecpair1 = BITBOX.ECPair.fromWIF(fixture.privateKeyWIF1); - let ecpair2 = BITBOX.ECPair.fromWIF(fixture.privateKeyWIF2); - let buf = Buffer.from(BITBOX.Crypto.sha256(fixture.data), 'hex'); - let signature = BITBOX.ECPair.sign(ecpair1, buf); - let verify = BITBOX.ECPair.verify(ecpair1, buf, signature); - assert.equal(verify, true); - }); - }); - }); -}); diff --git a/test/Generating.js b/test/Generating.js deleted file mode 100644 index 0c55c230..00000000 --- a/test/Generating.js +++ /dev/null @@ -1,30 +0,0 @@ -// let fixtures = require('./fixtures/BitcoinCash.json') -let chai = require('chai'); -let assert = require('assert'); -let axios = require('axios'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let sinon = require('sinon'); - -describe('#Generating', () => { - describe('#generateToAddress', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should generate', (done) => { - let data = []; - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'post').returns(resolved); - - BITBOX.Generating.generateToAddress(1, 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf') - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); -}); diff --git a/test/HDNode.js b/test/HDNode.js deleted file mode 100644 index 6af45758..00000000 --- a/test/HDNode.js +++ /dev/null @@ -1,319 +0,0 @@ -let fixtures = require('./fixtures/HDNode.json') -let chai = require('chai'); -let assert = require('assert'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let Buffer = require('safe-buffer').Buffer - -describe('#HDNode', () => { - describe('#fromSeed', () => { - fixtures.fromSeed.forEach((mnemonic) => { - it(`should create an HDNode from root seed buffer`, () => { - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(mnemonic); - let hdNode = BITBOX.HDNode.fromSeed(rootSeedBuffer); - assert.notEqual(hdNode, null); - }); - }); - }); - - describe('#derive', () => { - fixtures.derive.forEach((derive) => { - it(`should derive non hardened child HDNode`, () => { - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(derive.mnemonic); - let hdNode = BITBOX.HDNode.fromSeed(rootSeedBuffer); - let childHDNode = BITBOX.HDNode.derive(hdNode, 0); - assert.equal(BITBOX.HDNode.toXPub(childHDNode), derive.xpub); - assert.equal(BITBOX.HDNode.toXPriv(childHDNode), derive.xpriv); - }); - }); - }); - - describe('#deriveHardened', () => { - fixtures.deriveHardened.forEach((derive) => { - it(`should derive hardened child HDNode`, () => { - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(derive.mnemonic); - let hdNode = BITBOX.HDNode.fromSeed(rootSeedBuffer); - let childHDNode = BITBOX.HDNode.deriveHardened(hdNode, 0); - assert.equal(BITBOX.HDNode.toXPub(childHDNode), derive.xpub); - assert.equal(BITBOX.HDNode.toXPriv(childHDNode), derive.xpriv); - }); - }); - - describe('derive BIP44 $BCH account', () => { - fixtures.deriveBIP44.forEach((derive) => { - it(`should derive BIP44 $BCH account`, () => { - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(derive.mnemonic); - let hdNode = BITBOX.HDNode.fromSeed(rootSeedBuffer); - let purpose = BITBOX.HDNode.deriveHardened(hdNode, 44); - let coin = BITBOX.HDNode.deriveHardened(purpose, 145); - let childHDNode = BITBOX.HDNode.deriveHardened(coin, 0); - assert.equal(BITBOX.HDNode.toXPub(childHDNode), derive.xpub); - assert.equal(BITBOX.HDNode.toXPriv(childHDNode), derive.xpriv); - }); - }); - }); - }); - - describe('#derivePath', () => { - describe('derive non hardened Path', () => { - fixtures.derivePath.forEach((derive) => { - it(`should derive non hardened child HDNode from path`, () => { - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(derive.mnemonic); - let hdNode = BITBOX.HDNode.fromSeed(rootSeedBuffer); - let childHDNode = BITBOX.HDNode.derivePath(hdNode, "0"); - assert.equal(BITBOX.HDNode.toXPub(childHDNode), derive.xpub); - assert.equal(BITBOX.HDNode.toXPriv(childHDNode), derive.xpriv); - }); - }); - }); - - describe('derive hardened Path', () => { - fixtures.deriveHardenedPath.forEach((derive) => { - it(`should derive hardened child HDNode from path`, () => { - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(derive.mnemonic); - let hdNode = BITBOX.HDNode.fromSeed(rootSeedBuffer); - let childHDNode = BITBOX.HDNode.derivePath(hdNode, "0'"); - assert.equal(BITBOX.HDNode.toXPub(childHDNode), derive.xpub); - assert.equal(BITBOX.HDNode.toXPriv(childHDNode), derive.xpriv); - }); - }); - }); - - describe('derive BIP44 $BCH account', () => { - fixtures.deriveBIP44.forEach((derive) => { - it(`should derive BIP44 $BCH account`, () => { - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(derive.mnemonic); - let hdNode = BITBOX.HDNode.fromSeed(rootSeedBuffer); - let childHDNode = BITBOX.HDNode.derivePath(hdNode, "44'/145'/0'"); - assert.equal(BITBOX.HDNode.toXPub(childHDNode), derive.xpub); - assert.equal(BITBOX.HDNode.toXPriv(childHDNode), derive.xpriv); - }); - }); - }); - }); - - describe('#toLegacyAddress', () => { - fixtures.toLegacyAddress.forEach((fixture) => { - it(`should get address ${fixture.address} from HDNode`, () => { - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(fixture.mnemonic); - let hdNode = BITBOX.HDNode.fromSeed(rootSeedBuffer); - let childHDNode = BITBOX.HDNode.derivePath(hdNode, "0"); - let addy = BITBOX.HDNode.toLegacyAddress(childHDNode); - assert.equal(addy, fixture.address); - }); - }); - }); - - describe('#toCashAddress', () => { - fixtures.toCashAddress.forEach((fixture) => { - it(`should get address ${fixture.address} from HDNode`, () => { - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(fixture.mnemonic); - let hdNode = BITBOX.HDNode.fromSeed(rootSeedBuffer); - let childHDNode = BITBOX.HDNode.derivePath(hdNode, "0"); - let addy = BITBOX.HDNode.toCashAddress(childHDNode); - assert.equal(addy, fixture.address); - }); - }); - }); - - describe('#toWIF', () => { - fixtures.toWIF.forEach((fixture) => { - it(`should get privateKeyWIF ${fixture.privateKeyWIF} from HDNode`, () => { - let hdNode = BITBOX.HDNode.fromXPriv(fixture.xpriv); - assert.equal(BITBOX.HDNode.toWIF(hdNode), fixture.privateKeyWIF); - }); - }); - }); - - describe('#toXPub', () => { - fixtures.toXPub.forEach((fixture) => { - it(`should create xpub ${fixture.xpub} from an HDNode`, () => { - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(fixture.mnemonic); - let hdNode = BITBOX.HDNode.fromSeed(rootSeedBuffer); - let xpub = BITBOX.HDNode.toXPub(hdNode); - assert.equal(xpub, fixture.xpub); - }); - }); - }); - - describe('#toXPriv', () => { - fixtures.toXPriv.forEach((fixture) => { - it(`should create xpriv ${fixture.xpriv} from an HDNode`, () => { - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(fixture.mnemonic); - let hdNode = BITBOX.HDNode.fromSeed(rootSeedBuffer); - let xpriv = BITBOX.HDNode.toXPriv(hdNode); - assert.equal(xpriv, fixture.xpriv); - }); - }); - }); - - describe('#toKeyPair', () => { - fixtures.toKeyPair.forEach((fixture) => { - it(`should get ECPair from an HDNode`, () => { - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(fixture.mnemonic); - let hdNode = BITBOX.HDNode.fromSeed(rootSeedBuffer); - let keyPair = BITBOX.HDNode.toKeyPair(hdNode); - assert.equal(typeof keyPair, 'object'); - }); - }); - }); - - describe('#toPublicKey', () => { - fixtures.toPublicKey.forEach((fixture) => { - it(`should create public key buffer from an HDNode`, () => { - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(fixture.mnemonic); - let hdNode = BITBOX.HDNode.fromSeed(rootSeedBuffer); - let publicKeyBuffer = BITBOX.HDNode.toPublicKey(hdNode); - assert.equal(typeof publicKeyBuffer, 'object'); - }); - }); - }); - - describe('#fromXPriv', () => { - fixtures.fromXPriv.forEach((fixture) => { - let hdNode = BITBOX.HDNode.fromXPriv(fixture.xpriv); - it(`should create HDNode from xpriv ${fixture.xpriv}`, () => { - assert.notEqual(hdNode, null); - }); - - it(`should export xpriv ${fixture.xpriv}`, () => { - assert.equal(BITBOX.HDNode.toXPriv(hdNode), fixture.xpriv); - }); - - it(`should export xpub ${fixture.xpub}`, () => { - assert.equal(BITBOX.HDNode.toXPub(hdNode), fixture.xpub); - }); - - it(`should export legacy address ${fixture.legacy}`, () => { - assert.equal(BITBOX.HDNode.toLegacyAddress(hdNode), fixture.legacy); - }); - - it(`should export cashaddress ${fixture.cashaddress}`, () => { - assert.equal(BITBOX.HDNode.toCashAddress(hdNode), fixture.cashaddress); - }); - - it(`should export privateKeyWIF ${fixture.privateKeyWIF}`, () => { - assert.equal(BITBOX.HDNode.toWIF(hdNode), fixture.privateKeyWIF); - }); - }); - }); - - describe('#fromXPub', () => { - fixtures.fromXPub.forEach((fixture) => { - let hdNode = BITBOX.HDNode.fromXPub(fixture.xpub); - it(`should create HDNode from xpub ${fixture.xpub}`, () => { - assert.notEqual(hdNode, null); - }); - - it(`should export xpub ${fixture.xpub}`, () => { - assert.equal(BITBOX.HDNode.toXPub(hdNode), fixture.xpub); - }); - - it(`should export legacy address ${fixture.legacy}`, () => { - assert.equal(BITBOX.HDNode.toLegacyAddress(hdNode), fixture.legacy); - }); - - it(`should export cashaddress ${fixture.cashaddress}`, () => { - assert.equal(BITBOX.HDNode.toCashAddress(hdNode), fixture.cashaddress); - }); - }); - }); - // - // describe('create accounts and addresses', () => { - // fixtures.accounts.forEach((fixture) => { - // let seedBuffer = BITBOX.Mnemonic.toSeed(fixture.mnemonic) - // let hdNode = BITBOX.HDNode.fromSeed(seedBuffer) - // let a = BITBOX.HDNode.derivePath(hdNode, "0'"); - // let external = BITBOX.HDNode.derivePath(a, "0"); - // let account = BITBOX.HDNode.createAccount([external]); - // - // it(`#createAccount`, () => { - // assert.notEqual(account, null); - // }); - // - // describe('#getChainAddress', () => { - // let external1 = BITBOX.Address.toCashAddress(account.getChainAddress(0)); - // it(`should create external change address ${external1}`, () => { - // assert.equal(external1, fixture.externals[0] ); - // }); - // }); - // - // describe('#nextChainAddress', () => { - // for(let i = 0; i < 4; i++) { - // let ex = BITBOX.Address.toCashAddress(account.nextChainAddress(0)); - // it(`should create external change address ${ex}`, () => { - // assert.equal(ex, fixture.externals[i + 1]); - // }); - // } - // }); - // }); - // }); - - describe('#sign', () => { - fixtures.sign.forEach((fixture) => { - it(`should sign 32 byte hash buffer`, () => { - let hdnode = BITBOX.HDNode.fromXPriv(fixture.privateKeyWIF); - let buf = Buffer.from(BITBOX.Crypto.sha256(fixture.data), 'hex'); - let signatureBuf = BITBOX.HDNode.sign(hdnode, buf); - assert.equal(typeof signatureBuf, 'object'); - }); - }); - }); - - describe('#verify', () => { - fixtures.verify.forEach((fixture) => { - it(`should verify signed 32 byte hash buffer`, () => { - let hdnode1 = BITBOX.HDNode.fromXPriv(fixture.privateKeyWIF1); - let hdnode2 = BITBOX.HDNode.fromXPriv(fixture.privateKeyWIF2); - let buf = Buffer.from(BITBOX.Crypto.sha256(fixture.data), 'hex'); - let signature = BITBOX.HDNode.sign(hdnode1, buf); - let verify = BITBOX.HDNode.verify(hdnode1, buf, signature); - assert.equal(verify, true); - }); - }); - }); - - describe('#isPublic', () => { - fixtures.isPublic.forEach((fixture) => { - it(`should verify hdnode is public`, () => { - let node = BITBOX.HDNode.fromXPub(fixture.xpub); - assert.equal(BITBOX.HDNode.isPublic(node), true); - }); - }); - - fixtures.isPublic.forEach((fixture) => { - it(`should verify hdnode is not public`, () => { - let node = BITBOX.HDNode.fromXPriv(fixture.xpriv); - assert.equal(BITBOX.HDNode.isPublic(node), false); - }); - }); - }); - - describe('#isPrivate', () => { - fixtures.isPrivate.forEach((fixture) => { - it(`should verify hdnode is not private`, () => { - let node = BITBOX.HDNode.fromXPub(fixture.xpub); - assert.equal(BITBOX.HDNode.isPrivate(node), false); - }); - }); - - fixtures.isPrivate.forEach((fixture) => { - it(`should verify hdnode is private`, () => { - let node = BITBOX.HDNode.fromXPriv(fixture.xpriv); - assert.equal(BITBOX.HDNode.isPrivate(node), true); - }); - }); - }); - - describe('#toIdentifier', () => { - fixtures.toIdentifier.forEach((fixture) => { - it(`should get identifier of hdnode`, () => { - let node = BITBOX.HDNode.fromXPriv(fixture.xpriv); - let publicKeyBuffer = BITBOX.HDNode.toPublicKey(node); - let hash160 = BITBOX.Crypto.hash160(publicKeyBuffer); - let identifier = BITBOX.HDNode.toIdentifier(node); - assert.equal(identifier.toString('hex'), hash160.toString('hex')); - }); - }); - }); -}); diff --git a/test/Mining.js b/test/Mining.js deleted file mode 100644 index 4f6b9302..00000000 --- a/test/Mining.js +++ /dev/null @@ -1,115 +0,0 @@ -// let fixtures = require('./fixtures/BitcoinCash.json') -let chai = require('chai'); -let assert = require('assert'); -let axios = require('axios'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let sinon = require('sinon'); - -describe('#Mining', () => { - describe('#getBlockTemplate', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get block template', (done) => { - let data = { - data: '01000000017f6305e3b0b05f5b57a82f4e6d4187e148bbe56a947208390e488bad36472368000000006a47304402203b0079ff5b896187feb02e2679c87ac2fb8d483b60e0721ed33601e2c0eecc700220590f8a0e1a51b53b368294861fd5fc99db3a6607d0f4e543f6217108e208c1834121024c93c841d7f576584ffbf513b7abd8283e6562669905f6554f788fce4cc67a34ffffffff0228100000000000001976a914af78709a76abc8a28e568c9210c8247dd10cff2c88ac22020000000000001976a914f339927678803f451b41400737e7dc83c6a8682188ac00000000', - txid: '7f462d71c649a0d8cfbaa2d20d8ff86677966b308f0ac9906ee015bf4453f97a', - hash: '7f462d71c649a0d8cfbaa2d20d8ff86677966b308f0ac9906ee015bf4453f97a', - depends: [], - fee: 226, - sigops: 2 - }; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Mining.getBlockTemplate('') - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getMiningInfo', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get mining info', (done) => { - let data = { - blocks: 527816, - currentblocksize: 89408, - currentblocktx: 156, - difficulty: 568757800682.7649, - blockprioritypercentage: 5, - errors: '', - networkhashps: 4347259225696976000, - pooledtx: 184, - chain: 'main' - }; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Mining.getMiningInfo() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getNetworkHashps', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get network hashps', (done) => { - let data = 3586365937646890000; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Mining.getNetworkHashps() - .then((result) => { - assert.equal( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#submitBlock', () => { - // TODO finish - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should TODO', (done) => { - let data = {}; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'post').returns(resolved); - - BITBOX.Mining.submitBlock() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); -}); diff --git a/test/Mnemonic.js b/test/Mnemonic.js deleted file mode 100644 index 8453c3da..00000000 --- a/test/Mnemonic.js +++ /dev/null @@ -1,260 +0,0 @@ -let fixtures = require('./fixtures/Mnemonic.json') -let chai = require('chai'); -let assert = require('assert'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let Buffer = require('safe-buffer').Buffer - -describe('#Mnemonic', () => { - describe('#generate', () => { - it('should generate a 12 word mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(128); - assert.equal(mnemonic.split(' ').length, 12); - }); - - it('should generate a 15 word mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(160); - assert.equal(mnemonic.split(' ').length, 15); - }); - - it('should generate a 18 word mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(192); - assert.equal(mnemonic.split(' ').length, 18); - }); - - it('should generate an 21 word mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(224); - assert.equal(mnemonic.split(' ').length, 21); - }); - - it('should generate an 24 word mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(256); - assert.equal(mnemonic.split(' ').length, 24); - }); - - it('should generate an 24 word italian mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(256, BITBOX.Mnemonic.wordLists().italian); - assert.equal(mnemonic.split(' ').length, 24); - }); - }); - - describe('#fromEntropy', () => { - it('should generate a 12 word mnemonic from 16 bytes of entropy', () => { - let rand = BITBOX.Crypto.randomBytes(16); - let mnemonic = BITBOX.Mnemonic.fromEntropy(rand.toString('hex')); - assert.equal(mnemonic.split(' ').length, 12); - }); - - it('should generate a 15 word mnemonic from 20 bytes of entropy', () => { - let rand = BITBOX.Crypto.randomBytes(20); - let mnemonic = BITBOX.Mnemonic.fromEntropy(rand.toString('hex')); - assert.equal(mnemonic.split(' ').length, 15); - }); - - it('should generate an 18 word mnemonic from 24 bytes of entropy', () => { - let rand = BITBOX.Crypto.randomBytes(24); - let mnemonic = BITBOX.Mnemonic.fromEntropy(rand.toString('hex')); - assert.equal(mnemonic.split(' ').length, 18); - }); - - it('should generate an 21 word mnemonic from 28 bytes of entropy', () => { - let rand = BITBOX.Crypto.randomBytes(28); - let mnemonic = BITBOX.Mnemonic.fromEntropy(rand.toString('hex')); - assert.equal(mnemonic.split(' ').length, 21); - }); - - it('should generate an 24 word mnemonic from 32 bytes of entropy', () => { - let rand = BITBOX.Crypto.randomBytes(32); - let mnemonic = BITBOX.Mnemonic.fromEntropy(rand.toString('hex')); - assert.equal(mnemonic.split(' ').length, 24); - }); - - it('should generate an 24 french word mnemonic 32 bytes of entropy', () => { - let rand = BITBOX.Crypto.randomBytes(32); - let mnemonic = BITBOX.Mnemonic.fromEntropy(rand.toString('hex'), BITBOX.Mnemonic.wordLists().french); - assert.equal(mnemonic.split(' ').length, 24); - }); - - fixtures.fromEntropy.forEach((entropy) => { - let mnemonic = BITBOX.Mnemonic.fromEntropy(entropy.entropy); - it(`should convert ${entropy.entropy} to ${entropy.mnemonic}`, () => { - assert.equal(mnemonic, entropy.mnemonic); - }); - }); - }); - - describe('#toEntropy', () => { - it('should turn a 12 word mnemonic to entropy', () => { - let mnemonic = BITBOX.Mnemonic.generate(128); - let entropy = BITBOX.Mnemonic.toEntropy(mnemonic); - assert.equal(entropy.length, 16); - }); - - it('should turn a 15 word mnemonic to entropy', () => { - let mnemonic = BITBOX.Mnemonic.generate(160); - let entropy = BITBOX.Mnemonic.toEntropy(mnemonic); - assert.equal(entropy.length, 20); - }); - - it('should turn a 18 word mnemonic to entropy', () => { - let mnemonic = BITBOX.Mnemonic.generate(192); - let entropy = BITBOX.Mnemonic.toEntropy(mnemonic); - assert.equal(entropy.length, 24); - }); - - it('should turn a 21 word mnemonic to entropy', () => { - let mnemonic = BITBOX.Mnemonic.generate(224); - let entropy = BITBOX.Mnemonic.toEntropy(mnemonic); - assert.equal(entropy.length, 28); - }); - - it('should turn a 24 word mnemonic to entropy', () => { - let mnemonic = BITBOX.Mnemonic.generate(256); - let entropy = BITBOX.Mnemonic.toEntropy(mnemonic); - assert.equal(entropy.length, 32); - }); - - it('should turn a 24 word spanish mnemonic to entropy', () => { - let mnemonic = BITBOX.Mnemonic.generate(256, BITBOX.Mnemonic.wordLists().spanish); - let entropy = BITBOX.Mnemonic.toEntropy(mnemonic, BITBOX.Mnemonic.wordLists().spanish); - assert.equal(entropy.length, 32); - }); - - fixtures.fromEntropy.forEach((fixture) => { - let entropy = BITBOX.Mnemonic.toEntropy(fixture.mnemonic); - it(`should convert ${fixture.mnemonic} to ${fixture.entropy}`, () => { - assert.equal(entropy.toString('hex'), fixture.entropy); - }); - }); - }); - - describe('#validate', () => { - it('fails for a mnemonic that is too short', () => { - assert.equal(BITBOX.Mnemonic.validate('mixed winner', BITBOX.Mnemonic.wordLists().english), 'Invalid mnemonic'); - }); - - it('fails for a mnemonic that is too long', () => { - assert.equal(BITBOX.Mnemonic.validate('mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake', BITBOX.Mnemonic.wordLists().english), 'Invalid mnemonic'); - }); - - it('fails if mnemonic words are not in the word list', () => { - assert.equal(BITBOX.Mnemonic.validate('failsauce one two three four five six seven eight nine ten eleven', BITBOX.Mnemonic.wordLists().english), 'failsauce is not in wordlist, did you mean balance?'); - }); - - it('validate a 128 bit mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(128); - assert.equal(BITBOX.Mnemonic.validate(mnemonic, BITBOX.Mnemonic.wordLists().english), 'Valid mnemonic'); - }); - - it('validate a 160 bit mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(160); - assert.equal(BITBOX.Mnemonic.validate(mnemonic, BITBOX.Mnemonic.wordLists().english), 'Valid mnemonic'); - }); - - it('validate a 192 bit mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(192); - assert.equal(BITBOX.Mnemonic.validate(mnemonic, BITBOX.Mnemonic.wordLists().english), 'Valid mnemonic'); - }); - - it('validate a 224 bit mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(224); - assert.equal(BITBOX.Mnemonic.validate(mnemonic, BITBOX.Mnemonic.wordLists().english), 'Valid mnemonic'); - }); - - it('validate a 256 bit mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(256); - assert.equal(BITBOX.Mnemonic.validate(mnemonic, BITBOX.Mnemonic.wordLists().english), 'Valid mnemonic'); - }); - - it('validate a 256 bit chinese simplified mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(256, BITBOX.Mnemonic.wordLists().chinese_simplified); - assert.equal(BITBOX.Mnemonic.validate(mnemonic, BITBOX.Mnemonic.wordLists().chinese_simplified), 'Valid mnemonic'); - }); - }); - - describe('#toSeed', () => { - it('should create 512 bit / 64 byte HMAC-SHA512 root seed from a 128 bit mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(128); - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(mnemonic, ''); - assert.equal(rootSeedBuffer.byteLength, 64); - }); - - it('should create 512 bit / 64 byte HMAC-SHA512 root seed from a 160 bit mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(160); - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(mnemonic, ''); - assert.equal(rootSeedBuffer.byteLength, 64); - }); - - it('should create 512 bit / 64 byte HMAC-SHA512 root seed from a 192 bit mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(192); - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(mnemonic, ''); - assert.equal(rootSeedBuffer.byteLength, 64); - }); - - it('should create 512 bit / 64 byte HMAC-SHA512 root seed from a 224 bit mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(224); - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(mnemonic, ''); - assert.equal(rootSeedBuffer.byteLength, 64); - }); - - it('should create 512 bit / 64 byte HMAC-SHA512 root seed from a 256 bit mnemonic', () => { - let mnemonic = BITBOX.Mnemonic.generate(256); - let rootSeedBuffer = BITBOX.Mnemonic.toSeed(mnemonic, ''); - assert.equal(rootSeedBuffer.byteLength, 64); - }); - }); - - describe('#wordLists', () => { - it('return a list of 2048 english words', () => { - assert.equal(BITBOX.Mnemonic.wordLists().english.length, 2048); - }); - - it('return a list of 2048 japanese words', () => { - assert.equal(BITBOX.Mnemonic.wordLists().japanese.length, 2048); - }); - - it('return a list of 2048 chinese simplified words', () => { - assert.equal(BITBOX.Mnemonic.wordLists().chinese_simplified.length, 2048); - }); - - it('return a list of 2048 chinese traditional words', () => { - assert.equal(BITBOX.Mnemonic.wordLists().chinese_traditional.length, 2048); - }); - - it('return a list of 2048 french words', () => { - assert.equal(BITBOX.Mnemonic.wordLists().french.length, 2048); - }); - - it('return a list of 2048 italian words', () => { - assert.equal(BITBOX.Mnemonic.wordLists().italian.length, 2048); - }); - - it('return a list of 2048 korean words', () => { - assert.equal(BITBOX.Mnemonic.wordLists().korean.length, 2048); - }); - - it('return a list of 2048 spanish words', () => { - assert.equal(BITBOX.Mnemonic.wordLists().spanish.length, 2048); - }); - }); - - describe('#toKeypairs', () => { - fixtures.toKeypairs.forEach((fixture, i) => { - let keypairs = BITBOX.Mnemonic.toKeypairs(fixture.mnemonic, 5); - keypairs.forEach((keypair, j) => { - it(`Generate keypair from mnemonic`, () => { - assert.equal(keypair.privateKeyWIF, fixtures.toKeypairs[i].output[j].privateKeyWIF); - }); - }); - }); - }); - - describe('#findNearestWord', () => { - fixtures.findNearestWord.forEach((fixture, i) => { - let word = BITBOX.Mnemonic.findNearestWord(fixture.word, BITBOX.Mnemonic.wordLists()[fixture.language]); - it(`find word ${fixture.foundWord} near ${fixture.word} in ${fixture.language}`, () => { - assert.equal(word, fixture.foundWord); - }); - }); - }); -}); diff --git a/test/Network.js b/test/Network.js deleted file mode 100644 index 5f403b2f..00000000 --- a/test/Network.js +++ /dev/null @@ -1,201 +0,0 @@ -// let fixtures = require('./fixtures/BitcoinCash.json') -let chai = require('chai'); -let assert = require('assert'); -let axios = require('axios'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let sinon = require('sinon'); - -describe('#Network', () => { - describe('#getConnectionCount', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get connection count', (done) => { - let data = 13; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Network.getConnectionCount() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getNetTotals', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get net totals', (done) => { - let data = { - totalbytesrecv: 9348169, - totalbytessent: 246903958, - timemillis: 1524922367067, - uploadtarget: - { timeframe: 86400, - target: 0, - target_reached: false, - serve_historical_blocks: true, - bytes_left_in_cycle: 0, - time_left_in_cycle: 0 - } - }; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Network.getNetTotals() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getNetworkInfo', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get network info', (done) => { - let data = { - version: 170000, - subversion: '/Bitcoin ABC:0.17.0(EB32.0)/', - protocolversion: 70015, - localservices: '0000000000000025', - localrelay: true, - timeoffset: 0, - networkactive: true, - connections: 11, - networks: - [ { name: 'ipv4', - limited: false, - reachable: true, - proxy: '', - proxy_randomize_credentials: false }, - { name: 'ipv6', - limited: false, - reachable: true, - proxy: '', - proxy_randomize_credentials: false }, - { name: 'onion', - limited: true, - reachable: false, - proxy: '', - proxy_randomize_credentials: false } ], - relayfee: 0.00001, - incrementalfee: 0.00001, - localaddresses: [ { address: '138.68.54.100', port: 8333, score: 584 } ], - warnings: '' - }; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Network.getNetworkInfo() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getPeerInfo', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get peer info', (done) => { - let data = [ - { id: 99, - addr: '54.39.17.74:47990', - addrlocal: '138.68.54.100:8333', - services: '0000000000000000', - relaytxes: true, - lastsend: 1524922628, - lastrecv: 1524922616, - bytessent: 310482, - bytesrecv: 10637, - conntime: 1524890802, - timeoffset: 0, - pingtime: 0.066598, - minping: 0.066502, - version: 70015, - subver: '/bitnodes.ping.com:0.1/', - inbound: true, - addnode: false, - startingheight: 527808, - banscore: 0, - synced_headers: 527872, - synced_blocks: -1, - inflight: [], - whitelisted: false, - bytessent_per_msg: - { addr: 14975, - feefilter: 32, - inv: 286552, - ping: 8512, - pong: 192, - sendcmpct: 33, - sendheaders: 24, - verack: 24, - version: 138 }, - bytesrecv_per_msg: - { addr: 1410, - inv: 366, - ping: 192, - pong: 8512, - verack: 24, - version: 133 } } - ]; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Network.getPeerInfo() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#ping', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should ping', (done) => { - let data = null; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Network.ping() - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); -}); diff --git a/test/RawTransactions.js b/test/RawTransactions.js deleted file mode 100644 index ce339b3b..00000000 --- a/test/RawTransactions.js +++ /dev/null @@ -1,109 +0,0 @@ -let chai = require('chai'); -let assert = require('assert'); -let axios = require('axios'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); - -let sinon = require('sinon'); - -describe('#RawTransactions', () => { - describe('#decodeRawTransaction', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should decode raw transaction', (done) => { - let data = { - "txid": "4ebd325a4b394cff8c57e8317ccf5a8d0e2bdf1b8526f8aad6c8e43d8240621a", - "hash": "4ebd325a4b394cff8c57e8317ccf5a8d0e2bdf1b8526f8aad6c8e43d8240621a", - "size": 10, - "version": 2, - "locktime": 0, - "vin": [], - "vout": [] - }; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.RawTransactions.decodeRawTransaction('02000000000000000000') - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#decodeScript', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should decode script', (done) => { - let data = { - asm: 'OP_RETURN 5361746f736869204e616b616d6f746f', - type: 'nulldata', - p2sh: 'bitcoincash:prswx5965nfumux9qng5kj8hw603vcne7q08t8c6jp' - }; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.RawTransactions.decodeScript('6a105361746f736869204e616b616d6f746f') - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#getRawTransaction', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get raw transaction', (done) => { - let data = '020000000160d663961c63c7f0a07f22ec07b8f55b3935bfdbed8b1d8454916e8932fbf109010000006b4830450221008479fab4cfdcb111833d250a43f98ac26d43272b7a29cb1b9a0491eae5c44b3502203448b17253632395c29a7d62058bbfe93efb20fc8636ba6837002d464195aec04121029123258f7cdcd45b864066bcaa9b71f24d5ed1fa1dd36eaf107d8432b5014658ffffffff016d180000000000001976a91479d3297d1823149f4ec61df31d19f2fad5390c0288ac00000000'; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.RawTransactions.getRawTransaction('808d617eccaad4f1397fe07a06ec5ed15a0821cf22a3e0931c0c92aef9e572b6') - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); - - describe('#sendRawTransaction', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should send raw transaction', (done) => { - let data = 'Error: transaction already in block chain'; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'post').returns(resolved); - - BITBOX.RawTransactions.sendRawTransaction('020000000160d663961c63c7f0a07f22ec07b8f55b3935bfdbed8b1d8454916e8932fbf109010000006b4830450221008479fab4cfdcb111833d250a43f98ac26d43272b7a29cb1b9a0491eae5c44b3502203448b17253632395c29a7d62058bbfe93efb20fc8636ba6837002d464195aec04121029123258f7cdcd45b864066bcaa9b71f24d5ed1fa1dd36eaf107d8432b5014658ffffffff016d180000000000001976a91479d3297d1823149f4ec61df31d19f2fad5390c0288ac00000000') - .then((result) => { - assert.equal( - data, - result - ); - }) - .then(done, done); - }); - }); -}); diff --git a/test/Script.js b/test/Script.js deleted file mode 100644 index b3e75ff4..00000000 --- a/test/Script.js +++ /dev/null @@ -1,362 +0,0 @@ -let fixtures = require('./fixtures/Script.json') -let chai = require('chai'); -let assert = require('assert'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let Buffer = require('safe-buffer').Buffer - -describe('#Script', () => { - describe('#decode', () => { - describe('P2PKH scriptSig', () => { - fixtures.decodeScriptSig.forEach((fixture) => { - it(`should decode scriptSig buffer`, () => { - let decodedScriptSig = BITBOX.Script.decode(Buffer.from(fixture.scriptSigHex, 'hex')); - assert.equal(typeof decodedScriptSig, 'object'); - }); - - it(`should decode scriptSig buffer to cash address ${fixture.cashAddress}`, () => { - let decodedScriptSig = BITBOX.Script.decode(Buffer.from(fixture.scriptSigHex, 'hex')); - let address = BITBOX.HDNode.toCashAddress(BITBOX.ECPair.fromPublicKey(decodedScriptSig[1])); - assert.equal(address, fixture.cashAddress); - }); - - it(`should decode scriptSig buffer to legacy address ${fixture.legacyAddress}`, () => { - let decodedScriptSig = BITBOX.Script.decode(Buffer.from(fixture.scriptSigHex, 'hex')); - let address = BITBOX.HDNode.toLegacyAddress(BITBOX.ECPair.fromPublicKey(decodedScriptSig[1])); - assert.equal(address, fixture.legacyAddress); - }); - }); - }); - - describe('P2PKH scriptPubKey', () => { - fixtures.decodeScriptPubKey.forEach((fixture) => { - it(`should decode scriptSig buffer`, () => { - let decodedScriptPubKey = BITBOX.Script.decode(Buffer.from(fixture.scriptPubKeyHex, 'hex')); - assert.equal(decodedScriptPubKey.length, 5); - }); - - it(`should match hashed pubKey ${fixture.pubKeyHex}`, () => { - let decodedScriptPubKey = BITBOX.Script.decode(Buffer.from(fixture.scriptPubKeyHex, 'hex')); - let data = Buffer.from(fixture.pubKeyHex, 'hex') - let hash160 = BITBOX.Crypto.hash160(data).toString('hex'); - assert.equal(decodedScriptPubKey[2].toString('hex'), hash160); - }); - }); - }); - }); - - describe('#encode', () => { - describe('P2PKH scriptSig', () => { - fixtures.encodeScriptSig.forEach((fixture) => { - it(`should encode scriptSig chunks to buffer`, () => { - let arr = [ - Buffer.from(fixture.scriptSigChunks[0], 'hex'), - Buffer.from(fixture.scriptSigChunks[1], 'hex') - ]; - let encodedScriptSig = BITBOX.Script.encode(arr); - assert.equal(typeof encodedScriptSig, 'object'); - }); - }); - }); - - describe('P2PKH scriptPubKey', () => { - fixtures.encodeScriptPubKey.forEach((fixture) => { - it(`should encode scriptPubKey buffer`, () => { - let decodedScriptPubKey = BITBOX.Script.decode(Buffer.from(fixture.scriptPubKeyHex, 'hex')); - let compiledScriptPubKey = BITBOX.Script.encode(decodedScriptPubKey); - assert.equal(compiledScriptPubKey.toString('hex'), fixture.scriptPubKeyHex); - }); - }); - }); - }); - - describe('#toASM', () => { - describe('P2PKH scriptSig', () => { - fixtures.scriptSigToASM.forEach((fixture) => { - it(`should encode scriptSig buffer to ${fixture.asm}`, () => { - let arr = [ - Buffer.from(fixture.scriptSigChunks[0], 'hex'), - Buffer.from(fixture.scriptSigChunks[1], 'hex') - ]; - let compiledScriptSig = BITBOX.Script.encode(arr); - let asm = BITBOX.Script.toASM(compiledScriptSig); - assert.equal(asm, fixture.asm); - }); - }); - }); - - describe('P2PKH scriptPubKey', () => { - fixtures.scriptPubKeyToASM.forEach((fixture) => { - it(`should compile scriptPubKey buffer to ${fixture.asm}`, () => { - let asm = BITBOX.Script.toASM(Buffer.from(fixture.scriptPubKeyHex, 'hex')); - assert.equal(asm, fixture.asm); - }); - }); - }); - }); - - describe('#fromASM', () => { - describe('P2PKH scriptSig', () => { - fixtures.scriptSigFromASM.forEach((fixture) => { - it(`should decode scriptSig asm to buffer`, () => { - let buf = BITBOX.Script.fromASM(fixture.asm); - assert.equal(typeof buf, 'object'); - }); - }); - }); - - describe('P2PKH scriptPubKey', () => { - fixtures.scriptPubKeyFromASM.forEach((fixture) => { - it(`should decode scriptPubKey asm to buffer`, () => { - let buf = BITBOX.Script.fromASM(fixture.asm); - assert.equal(typeof buf, 'object'); - }); - }); - }); - }); - - describe('#OPCodes', () => { - for (let opcode in fixtures.opcodes) { - it(`should have OP Code ${opcode}`, () => { - assert.equal(BITBOX.Script.opcodes[opcode], fixtures.opcodes[opcode]); - }); - } - }); - - describe('#classifyInput', () => { - fixtures.classifyInput.forEach((fixture) => { - it(`should classify input type ${fixture.type}`, () => { - let type = BITBOX.Script.classifyInput(BITBOX.Script.fromASM(fixture.script)); - assert.equal(type, fixture.type); - }); - }); - }); - - describe('#classifyOutput', () => { - fixtures.classifyOutput.forEach((fixture) => { - it(`should classify ouput type ${fixture.type}`, () => { - let type = BITBOX.Script.classifyOutput(BITBOX.Script.fromASM(fixture.script)); - assert.equal(type, fixture.type); - }); - }); - }); - - describe('#nullDataTemplate', () => { - fixtures.nullDataTemplate.forEach((fixture) => { - it(`should encode nulldata output`, () => { - let buf = BITBOX.Script.nullData.output.encode(Buffer.from(`${fixture.data}`, 'ascii')); - assert.equal(buf.toString('hex'), fixture.hex); - }); - - it(`should decode nulldata output`, () => { - let buf = BITBOX.Script.nullData.output.decode(Buffer.from(`${fixture.hex}`, 'hex')); - assert.equal(buf.toString('ascii'), fixture.data); - }); - - it(`should confirm correctly formatted nulldata output`, () => { - let buf = BITBOX.Script.nullData.output.encode(Buffer.from(`${fixture.data}`, 'ascii')); - let valid = BITBOX.Script.nullData.output.check(buf); - assert.equal(valid, true); - }); - }); - }); - - describe('#pubKeyTemplate', () => { - describe('#pubKeyInputTemplate', () => { - fixtures.pubKeyInputTemplate.forEach((fixture) => { - it(`should encode pubKey input`, () => { - let buf = BITBOX.Script.pubKey.input.encode(Buffer.from(fixture.signature, 'hex')); - assert.equal(buf.toString('hex'), fixture.hex); - }); - - it(`should decode pubKey input`, () => { - let buf = BITBOX.Script.pubKey.input.decode(Buffer.from(fixture.hex, 'hex')); - assert.equal(buf.toString('hex'), fixture.signature); - }); - - it(`should confirm correctly formatted pubKeyHash input`, () => { - let buf = BITBOX.Script.pubKey.input.encode(Buffer.from(fixture.signature, 'hex')); - let valid = BITBOX.Script.pubKey.input.check(buf); - assert.equal(valid, true); - }); - }); - }); - - describe('#pubKeyOutputTemplate', () => { - fixtures.pubKeyOutputTemplate.forEach((fixture) => { - it(`should encode pubKey output`, () => { - let buf = BITBOX.Script.pubKey.output.encode(Buffer.from(fixture.pubKey, 'hex')); - assert.equal(buf.toString('hex'), fixture.hex); - }); - - it(`should decode pubKey output`, () => { - let buf = BITBOX.Script.pubKey.output.decode(Buffer.from(`${fixture.hex}`, 'hex')); - assert.equal(buf.toString('hex'), fixture.pubKey); - }); - - it(`should confirm correctly formatted pubKey output`, () => { - let buf = BITBOX.Script.pubKey.output.encode(Buffer.from(fixture.pubKey, 'hex')); - let valid = BITBOX.Script.pubKey.output.check(buf); - assert.equal(valid, true); - }); - }); - }); - }); - - describe('#pubKeyHashTemplate', () => { - describe('#pubKeyHashInputTemplate', () => { - fixtures.pubKeyHashInputTemplate.forEach((fixture) => { - it(`should encode pubKeyHash input`, () => { - let buf = BITBOX.Script.pubKeyHash.input.encode(Buffer.from(fixture.signature, 'hex'), Buffer.from(fixture.pubKey, 'hex')); - assert.equal(buf.toString('hex'), fixture.hex); - }); - - it(`should decode pubKeyHash input signature`, () => { - let buf = BITBOX.Script.pubKeyHash.input.decode(Buffer.from(fixture.hex, 'hex')); - assert.equal(buf.signature.toString('hex'), fixture.signature); - }); - - it(`should decode pubKeyHash input pubkey`, () => { - let buf = BITBOX.Script.pubKeyHash.input.decode(Buffer.from(fixture.hex, 'hex')); - assert.equal(buf.pubKey.toString('hex'), fixture.pubKey); - }); - - it(`should confirm correctly formatted pubKeyHash input`, () => { - let buf = BITBOX.Script.pubKeyHash.input.encode(Buffer.from(fixture.signature, 'hex'), Buffer.from(fixture.pubKey, 'hex')); - let valid = BITBOX.Script.pubKeyHash.input.check(buf); - assert.equal(valid, true); - }); - }); - }); - - describe('#pubKeyHashOutputTemplate', () => { - fixtures.pubKeyHashOutputTemplate.forEach((fixture) => { - let node = BITBOX.HDNode.fromXPriv(fixture.xpriv); - let identifier = BITBOX.HDNode.toIdentifier(node); - it(`should encode pubKeyHash output`, () => { - let buf = BITBOX.Script.pubKeyHash.output.encode(identifier); - assert.equal(buf.toString('hex'), fixture.hex); - }); - - it(`should decode pubKeyHash output`, () => { - let buf = BITBOX.Script.pubKeyHash.output.decode(Buffer.from(`${fixture.hex}`, 'hex')); - assert.equal(buf.toString('hex'), identifier.toString('hex')); - }); - - it(`should confirm correctly formatted pubKeyHash output`, () => { - let buf = BITBOX.Script.pubKeyHash.output.encode(identifier); - let valid = BITBOX.Script.pubKeyHash.output.check(buf); - assert.equal(valid, true); - }); - }); - }); - }); - - describe('#multisigTemplate', () => { - describe('#multisigInputTemplate', () => { - fixtures.multisigInputTemplate.forEach((fixture) => { - it(`should encode multisig input`, () => { - let signatures = fixture.signatures.map((signature) => { - return signature ? Buffer.from(signature, 'hex') : BITBOX.Script.opcodes.OP_0 - }) - - let buf = BITBOX.Script.multisig.input.encode(signatures); - assert.equal(buf.toString('hex'), fixture.hex); - }); - - it(`should decode multisig input`, () => { - let buf = BITBOX.Script.multisig.input.decode(Buffer.from(fixture.hex, 'hex')); - assert.equal(buf[0].toString('hex'), fixture.signatures[0]); - }); - - it(`should confirm correctly formatted multisig input`, () => { - let signatures = fixture.signatures.map((signature) => { - return signature ? Buffer.from(signature, 'hex') : BITBOX.Script.opcodes.OP_0 - }) - - let buf = BITBOX.Script.multisig.input.encode(signatures); - let valid = BITBOX.Script.multisig.input.check(buf); - assert.equal(valid, true); - }); - }); - }); - - describe('#multisigOutputTemplate', () => { - fixtures.multisigOutputTemplate.forEach((fixture) => { - it(`should encode multisig output`, () => { - let pubKeys = fixture.pubKeys.map((p) => { return Buffer.from(p, 'hex') }) - let m = pubKeys.length - let buf = BITBOX.Script.multisig.output.encode(m, pubKeys); - - assert.equal(buf.toString('hex'), fixture.hex); - }); - - it(`should decode multisig output`, () => { - let output = BITBOX.Script.multisig.output.decode(Buffer.from(`${fixture.hex}`, 'hex')); - assert.equal(output.m, fixture.pubKeys.length); - }); - - it(`should confirm correctly formatted multisig output`, () => { - let pubKeys = fixture.pubKeys.map((p) => { return Buffer.from(p, 'hex') }) - let m = pubKeys.length - let buf = BITBOX.Script.multisig.output.encode(m, pubKeys); - let valid = BITBOX.Script.multisig.output.check(buf); - assert.equal(valid, true); - }); - }); - }); - }); - - describe('#scriptHashTemplate', () => { - describe('#scriptHashInputTemplate', () => { - fixtures.scriptHashInputTemplate.forEach((fixture) => { - it(`should encode scriptHash input`, () => { - let buf = BITBOX.Script.scriptHash.input.encode(BITBOX.Script.fromASM(fixture.redeemScriptSig), BITBOX.Script.fromASM(fixture.redeemScript)); - assert.equal(buf.toString('hex'), fixture.hex); - }); - - it(`should decode scriptHash input`, () => { - let redeemScriptSig = BITBOX.Script.fromASM(fixture.redeemScriptSig) - let redeemScript = BITBOX.Script.fromASM(fixture.redeemScript) - assert.deepEqual(BITBOX.Script.scriptHash.input.decode(Buffer.from(fixture.hex, 'hex')), { - redeemScriptSig: redeemScriptSig, - redeemScript: redeemScript - }) - }); - - it(`should confirm correctly formatted scriptHash input`, () => { - let buf = BITBOX.Script.scriptHash.input.encode(BITBOX.Script.fromASM(fixture.redeemScriptSig), BITBOX.Script.fromASM(fixture.redeemScript)); - let valid = BITBOX.Script.scriptHash.input.check(buf); - assert.equal(valid, true); - }); - }); - }); - - describe('#scriptHashOutputTemplate', () => { - fixtures.scriptHashOutputTemplate.forEach((fixture) => { - it(`should encode scriptHash output`, () => { - let redeemScript = BITBOX.Script.fromASM(fixture.output); - let scriptHash = BITBOX.Crypto.hash160(redeemScript); - let buf = BITBOX.Script.scriptHash.output.encode(scriptHash); - - assert.equal(buf.toString('hex'), fixture.hex); - }); - - it(`should decode scriptHash output`, () => { - let redeemScript = BITBOX.Script.fromASM(fixture.output); - let scriptHash = BITBOX.Crypto.hash160(redeemScript); - let buf = BITBOX.Script.scriptHash.output.decode(Buffer.from(`${fixture.hex}`, 'hex')); - assert.deepEqual(buf, scriptHash) - }); - - it(`should confirm correctly formatted scriptHash output`, () => { - let redeemScript = BITBOX.Script.fromASM(fixture.output); - let scriptHash = BITBOX.Crypto.hash160(redeemScript); - let buf = BITBOX.Script.scriptHash.output.encode(scriptHash); - let valid = BITBOX.Script.scriptHash.output.check(buf); - assert.equal(valid, true); - }); - }); - }); - }); -}); diff --git a/test/Transaction.js b/test/Transaction.js deleted file mode 100644 index 0774905e..00000000 --- a/test/Transaction.js +++ /dev/null @@ -1,50 +0,0 @@ -let chai = require('chai'); -let assert = require('assert'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let axios = require('axios'); -let sinon = require('sinon'); - -describe('#Transaction', () => { - describe('#details', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should get transaction details', (done) => { - let data = { - txid: 'a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8', - version: 1, - locktime: 0, - vin: - [ { coinbase: '04ffff001d029804', sequence: 4294967295, n: 0 } ], - vout: - [ { value: '50.00000000', - n: 0, - scriptPubKey: [Object], - spentTxId: null, - spentIndex: null, - spentHeight: null } ], - blockhash: '000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0', - blockheight: 507, - confirmations: 528399, - time: 1231973656, - blocktime: 1231973656, - isCoinBase: true, - valueOut: 50, - size: 135 - }; - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Transaction.details('a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8') - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); -}); diff --git a/test/TransactionBuilder.js b/test/TransactionBuilder.js deleted file mode 100644 index aee0d42e..00000000 --- a/test/TransactionBuilder.js +++ /dev/null @@ -1,1218 +0,0 @@ -let fixtures = require('./fixtures/TransactionBuilder.json') -let chai = require('chai'); -let assert = require('assert'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let Buffer = require('safe-buffer').Buffer - - -describe('#TransactionBuilder', () => { - describe('#hashTypes', () => { - let transactionBuilder = new BITBOX.TransactionBuilder('bitcoincash'); - fixtures.hashTypes.forEach((fixture) => { - it(`should match hash type`, () => { - assert.equal(fixture[Object.keys(fixture)[0]], transactionBuilder.hashTypes[Object.keys(fixture)[0]]); - }); - }); - }); - - describe('#P2PK', () => { - describe('#toOne', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2pk.toOne.mainnet.forEach((fixture) => { - it(`should create 1-to-1 P2PK transaction on mainnet`, () => { - let node = BITBOX.HDNode.fromXPriv(fixture.xpriv); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let originalAmount = fixture.amount; - let txid = fixture.txHash; - let pubKey = BITBOX.HDNode.toPublicKey(node); - let buf = BITBOX.Script.pubKey.output.encode(pubKey); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, buf); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 3 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(buf, sendAmount); - let keyPair = BITBOX.HDNode.toKeyPair(node); - let redeemScript; - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - describe('#Testnet', () => { - fixtures.scripts.p2pk.toOne.testnet.forEach((fixture) => { - it(`should create 1-to-1 P2PK transaction on testnet`, () => { - let node = BITBOX.HDNode.fromXPriv(fixture.xpriv); - let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - let originalAmount = fixture.amount; - let txid = fixture.txHash; - let pubKey = BITBOX.HDNode.toPublicKey(node); - let buf = BITBOX.Script.pubKey.output.encode(pubKey); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, buf); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 3 }, { P2PKH: 3 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(buf, sendAmount); - let keyPair = BITBOX.HDNode.toKeyPair(node); - let redeemScript; - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - }); - - describe('#toMany', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2pk.toMany.mainnet.forEach((fixture) => { - it(`should create 1-to-many P2PK transaction on mainnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let node3 = BITBOX.HDNode.fromXPriv(fixture.xprivs[2]); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let originalAmount = fixture.amount; - let txid = fixture.txHash; - let pubKey1 = BITBOX.HDNode.toPublicKey(node1); - let pubKey2 = BITBOX.HDNode.toPublicKey(node2); - let pubKey3 = BITBOX.HDNode.toPublicKey(node3); - let buf1 = BITBOX.Script.pubKey.output.encode(pubKey1); - let buf2 = BITBOX.Script.pubKey.output.encode(pubKey2); - let buf3 = BITBOX.Script.pubKey.output.encode(pubKey3); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, buf1); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 3 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(buf2, Math.floor(sendAmount / 2)); - transactionBuilder.addOutput(buf3, Math.floor(sendAmount / 2)); - let keyPair = BITBOX.HDNode.toKeyPair(node1); - let redeemScript; - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - describe('#Testnet', () => { - fixtures.scripts.p2pk.toMany.testnet.forEach((fixture) => { - it(`should create 1-to-many P2PK transaction on testnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let node3 = BITBOX.HDNode.fromXPriv(fixture.xprivs[2]); - let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - let originalAmount = fixture.amount; - let txid = fixture.txHash; - let pubKey1 = BITBOX.HDNode.toPublicKey(node1); - let pubKey2 = BITBOX.HDNode.toPublicKey(node2); - let pubKey3 = BITBOX.HDNode.toPublicKey(node3); - let buf1 = BITBOX.Script.pubKey.output.encode(pubKey1); - let buf2 = BITBOX.Script.pubKey.output.encode(pubKey2); - let buf3 = BITBOX.Script.pubKey.output.encode(pubKey3); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, buf1); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 3 }, { P2PKH: 3 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(buf2, Math.floor(sendAmount / 2)); - transactionBuilder.addOutput(buf3, Math.floor(sendAmount / 2)); - let keyPair = BITBOX.HDNode.toKeyPair(node1); - let redeemScript; - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - }); - - describe('#manyToMany', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2pk.manyToMany.mainnet.forEach((fixture) => { - it(`should create many-to-many P2PK transaction on mainnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let node3 = BITBOX.HDNode.fromXPriv(fixture.xprivs[2]); - let node4 = BITBOX.HDNode.fromXPriv(fixture.xprivs[3]); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let originalAmount = fixture.amount; - let txid = fixture.txHash; - let pubKey1 = BITBOX.HDNode.toPublicKey(node1); - let pubKey2 = BITBOX.HDNode.toPublicKey(node2); - let pubKey3 = BITBOX.HDNode.toPublicKey(node3); - let pubKey4 = BITBOX.HDNode.toPublicKey(node4); - let buf1 = BITBOX.Script.pubKey.output.encode(pubKey1); - let buf2 = BITBOX.Script.pubKey.output.encode(pubKey2); - let buf3 = BITBOX.Script.pubKey.output.encode(pubKey3); - let buf4 = BITBOX.Script.pubKey.output.encode(pubKey4); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, buf1); - transactionBuilder.addInput(txid, 1, transactionBuilder.DEFAULT_SEQUENCE, buf2); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 3 }, { P2PKH: 3 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(buf3, Math.floor(sendAmount / 2)); - transactionBuilder.addOutput(buf4, Math.floor(sendAmount / 2)); - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - let redeemScript; - transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - describe('#Testnet', () => { - fixtures.scripts.p2pk.manyToMany.testnet.forEach((fixture) => { - it(`should create many-to-many P2PK transaction on testnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let node3 = BITBOX.HDNode.fromXPriv(fixture.xprivs[2]); - let node4 = BITBOX.HDNode.fromXPriv(fixture.xprivs[3]); - let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - let originalAmount = fixture.amount; - let txid = fixture.txHash; - let pubKey1 = BITBOX.HDNode.toPublicKey(node1); - let pubKey2 = BITBOX.HDNode.toPublicKey(node2); - let pubKey3 = BITBOX.HDNode.toPublicKey(node3); - let pubKey4 = BITBOX.HDNode.toPublicKey(node4); - let buf1 = BITBOX.Script.pubKey.output.encode(pubKey1); - let buf2 = BITBOX.Script.pubKey.output.encode(pubKey2); - let buf3 = BITBOX.Script.pubKey.output.encode(pubKey3); - let buf4 = BITBOX.Script.pubKey.output.encode(pubKey4); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, buf1); - transactionBuilder.addInput(txid, 1, transactionBuilder.DEFAULT_SEQUENCE, buf2); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 3 }, { P2PKH: 3 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(buf3, Math.floor(sendAmount / 2)); - transactionBuilder.addOutput(buf4, Math.floor(sendAmount / 2)); - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - let redeemScript; - transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - }); - - describe('#fromMany', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2pk.fromMany.mainnet.forEach((fixture) => { - it(`should create many-to-1 P2PK transaction on mainnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let node3 = BITBOX.HDNode.fromXPriv(fixture.xprivs[2]); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let originalAmount = fixture.amount; - let txid = fixture.txHash; - let pubKey1 = BITBOX.HDNode.toPublicKey(node1); - let pubKey2 = BITBOX.HDNode.toPublicKey(node2); - let pubKey3 = BITBOX.HDNode.toPublicKey(node3); - let buf1 = BITBOX.Script.pubKey.output.encode(pubKey1); - let buf2 = BITBOX.Script.pubKey.output.encode(pubKey2); - let buf3 = BITBOX.Script.pubKey.output.encode(pubKey3); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, buf1); - transactionBuilder.addInput(txid, 1, transactionBuilder.DEFAULT_SEQUENCE, buf2); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 3 }, { P2PKH: 3 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(buf3, sendAmount); - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - let redeemScript; - transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - describe('#Testnet', () => { - fixtures.scripts.p2pk.fromMany.testnet.forEach((fixture) => { - it(`should create many-to-1 P2PK transaction on testnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let node3 = BITBOX.HDNode.fromXPriv(fixture.xprivs[2]); - let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - let originalAmount = fixture.amount; - let txid = fixture.txHash; - let pubKey1 = BITBOX.HDNode.toPublicKey(node1); - let pubKey2 = BITBOX.HDNode.toPublicKey(node2); - let pubKey3 = BITBOX.HDNode.toPublicKey(node3); - let buf1 = BITBOX.Script.pubKey.output.encode(pubKey1); - let buf2 = BITBOX.Script.pubKey.output.encode(pubKey2); - let buf3 = BITBOX.Script.pubKey.output.encode(pubKey3); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, buf1); - transactionBuilder.addInput(txid, 1, transactionBuilder.DEFAULT_SEQUENCE, buf2); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 3 }, { P2PKH: 3 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(buf3, sendAmount); - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - let redeemScript; - transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - }); - }); - - describe('#P2PKH', () => { - describe('#toOne', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2pkh.toOne.mainnet.forEach((fixture) => { - it(`should create 1-to-1 P2PKH transaction on mainnet`, () => { - let hdnode = BITBOX.HDNode.fromXPriv(fixture.xpriv); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let keyPair = BITBOX.HDNode.toKeyPair(hdnode); - let txHash = fixture.txHash; - // original amount of satoshis in vin - let originalAmount = fixture.amount; - transactionBuilder.addInput(txHash, fixture.vout); - // get byte count to calculate fee. paying 1 sat/byte - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 1 }); - // amount to send to receiver. It's the original amount - 1 sat/byte for tx size - let sendAmount = originalAmount - byteCount; - // add output w/ address and amount to send - let redeemScript - transactionBuilder.addOutput(fixture.outputs[0], sendAmount); - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - - // build tx - let tx = transactionBuilder.build(); - // output rawhex - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - describe('#Testnet', () => { - fixtures.scripts.p2pkh.toOne.testnet.forEach((fixture) => { - it(`should create 1-to-1 P2PKH transaction on testnet`, () => { - let hdnode = BITBOX.HDNode.fromXPriv(fixture.xpriv, 'testnet'); - let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - let keyPair = BITBOX.HDNode.toKeyPair(hdnode); - let txHash = fixture.txHash; - // original amount of satoshis in vin - let originalAmount = fixture.amount; - transactionBuilder.addInput(txHash, fixture.vout); - // get byte count to calculate fee. paying 1 sat/byte - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 1 }); - // amount to send to receiver. It's the original amount - 1 sat/byte for tx size - let sendAmount = originalAmount - (byteCount * 15); - // add output w/ address and amount to send - let redeemScript - transactionBuilder.addOutput(fixture.outputs[0], sendAmount); - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - - // build tx - let tx = transactionBuilder.build(); - // output rawhex - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - }); - - describe('#toMany', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2pkh.toMany.mainnet.forEach((fixture) => { - it(`should create 1-to-2 P2PKH transaction on mainnet`, () => { - let hdnode = BITBOX.HDNode.fromXPriv(fixture.xpriv); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let keyPair = BITBOX.HDNode.toKeyPair(hdnode); - let txHash = fixture.txHash; - // original amount of satoshis in vin - let originalAmount = fixture.amount; - transactionBuilder.addInput(txHash, fixture.vout); - // get byte count to calculate fee. paying 1 sat/byte - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 2 }); - // amount to send to receiver. It's the original amount - 1 sat/byte for tx size - let sendAmount = originalAmount - byteCount; - // add output w/ address and amount to send - transactionBuilder.addOutput(fixture.outputs[0], Math.floor(sendAmount / 2)); - transactionBuilder.addOutput(fixture.outputs[1], Math.floor(sendAmount / 2)); - let redeemScript - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - // build tx - let tx = transactionBuilder.build(); - // output rawhex - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - describe('#Testnet', () => { - fixtures.scripts.p2pkh.toMany.testnet.forEach((fixture) => { - // TODO pass in tesnet network config - it(`should create 1-to-2 P2PKH transaction on testnet`, () => { - let hdnode = BITBOX.HDNode.fromXPriv(fixture.xpriv); - let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - let keyPair = BITBOX.HDNode.toKeyPair(hdnode); - let txHash = fixture.txHash; - // original amount of satoshis in vin - let originalAmount = fixture.amount; - transactionBuilder.addInput(txHash, fixture.vout); - // get byte count to calculate fee. paying 1 sat/byte - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 2 }); - // amount to send to receiver. It's the original amount - 1 sat/byte for tx size - let sendAmount = originalAmount - (byteCount * 15); - // add output w/ address and amount to send - transactionBuilder.addOutput(fixture.outputs[0], Math.floor(sendAmount / 2)); - transactionBuilder.addOutput(fixture.outputs[1], Math.floor(sendAmount / 2)); - let redeemScript - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - // build tx - let tx = transactionBuilder.build(); - // output rawhex - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - }); - - describe('#manyToMany', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2pkh.manyToMany.mainnet.forEach((fixture) => { - it(`should create 2-to-2 P2PKH transaction on mainnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let txHash = fixture.txHash; - let originalAmount = fixture.amounts[0] + fixture.amounts[1]; - transactionBuilder.addInput(txHash, 0); - transactionBuilder.addInput(txHash, 1); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 2 }, { P2PKH: 2 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(fixture.outputs[0], Math.floor(sendAmount / 2)); - transactionBuilder.addOutput(fixture.outputs[1], Math.floor(sendAmount / 2)); - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - let redeemScript; - transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[0]); - transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[1]); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - describe('#Testnet', () => { - fixtures.scripts.p2pkh.manyToMany.testnet.forEach((fixture) => { - it(`should create 2-to-2 P2PKH transaction on testnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - let txHash = fixture.txHash; - let originalAmount = fixture.amounts[0] + fixture.amounts[1]; - transactionBuilder.addInput(txHash, 0); - transactionBuilder.addInput(txHash, 1); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 2 }, { P2PKH: 2 }); - let sendAmount = originalAmount - (byteCount * 15); - transactionBuilder.addOutput(fixture.outputs[0], Math.floor(sendAmount / 2)); - transactionBuilder.addOutput(fixture.outputs[1], Math.floor(sendAmount / 2)); - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - let redeemScript; - transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[0]); - transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[1]); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - }); - - describe('#fromMany', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2pkh.fromMany.mainnet.forEach((fixture) => { - it(`should create 2-to-1 P2PKH transaction on mainnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let txHash = fixture.txHash; - let originalAmount = fixture.amounts[0] + fixture.amounts[1]; - transactionBuilder.addInput(txHash, 0); - transactionBuilder.addInput(txHash, 1); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 2 }, { P2PKH: 1 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(fixture.outputs[0], sendAmount); - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - let redeemScript; - transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[0]); - transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[1]); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - describe('#Testnet', () => { - fixtures.scripts.p2pkh.fromMany.testnet.forEach((fixture) => { - it(`should create 2-to-1 P2PKH transaction on testnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - let txHash = fixture.txHash; - let originalAmount = fixture.amounts[0] + fixture.amounts[1]; - transactionBuilder.addInput(txHash, 0); - transactionBuilder.addInput(txHash, 1); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 2 }, { P2PKH: 1 }); - let sendAmount = originalAmount - (byteCount * 15); - transactionBuilder.addOutput(fixture.outputs[0], sendAmount); - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - let redeemScript; - transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[0]); - transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[1]); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - }); - }); - - describe('#op_return', () => { - describe('#Mainnet', () => { - fixtures.nulldata.mainnet.forEach((fixture) => { - it(`should create transaction w/ OP_RETURN output on mainnet`, () => { - let node = BITBOX.HDNode.fromXPriv(fixture.xpriv); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let txHash = fixture.txHash; - let originalAmount = fixture.amount; - transactionBuilder.addInput(txHash, 0); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 5 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(fixture.output, sendAmount); - let data = fixture.data; - let buf = BITBOX.Script.nullData.output.encode(Buffer.from(data, 'ascii')); - transactionBuilder.addOutput(buf, 0); - let keyPair = BITBOX.HDNode.toKeyPair(node); - let redeemScript; - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amount); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - describe('#Testnet', () => { - fixtures.nulldata.testnet.forEach((fixture) => { - it(`should create transaction w/ OP_RETURN output on testnet`, () => { - let node = BITBOX.HDNode.fromXPriv(fixture.xpriv); - let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - let txHash = fixture.txHash; - let originalAmount = fixture.amount; - transactionBuilder.addInput(txHash, 0); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 5 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(fixture.output, sendAmount); - let data = fixture.data; - let buf = BITBOX.Script.nullData.output.encode(Buffer.from(data, 'ascii')); - transactionBuilder.addOutput(buf, 0); - let keyPair = BITBOX.HDNode.toKeyPair(node); - let redeemScript; - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amount); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - }); - - describe('#P2PMS', () => { - describe('#toOne', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2ms.toOne.mainnet.forEach((fixture) => { - it(`should create 1-to-1 1-of-2 P2MS transaction on mainnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let node3 = BITBOX.HDNode.fromXPriv(fixture.xprivs[2]); - let node4 = BITBOX.HDNode.fromXPriv(fixture.xprivs[3]); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let txid = fixture.txHash; - let originalAmount = fixture.amount; - let pubKey1 = BITBOX.HDNode.toPublicKey(node1); - let pubKey2 = BITBOX.HDNode.toPublicKey(node2); - let buf1 = BITBOX.Script.multisig.output.encode(1, [pubKey1, pubKey2]); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, buf1); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 3 }, { P2PKH: 3 }); - let pubKey3 = BITBOX.HDNode.toPublicKey(node3); - let pubKey4 = BITBOX.HDNode.toPublicKey(node4); - let buf2 = BITBOX.Script.multisig.output.encode(1, [pubKey3, pubKey4]); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(buf2, sendAmount); - let redeemScript - let keyPair = BITBOX.HDNode.toKeyPair(node1); - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - // describe('#Testnet', () => { - // fixtures.scripts.p2ms.toOne.testnet.forEach((fixture) => { - // it(`should create 1-to-1 P2MS transaction on testnet`, () => { - // let hdnode = BITBOX.HDNode.fromXPriv(fixture.xpriv, 'testnet'); - // let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - // let keyPair = BITBOX.HDNode.toKeyPair(hdnode); - // let txHash = fixture.txHash; - // // original amount of satoshis in vin - // let originalAmount = fixture.amount; - // transactionBuilder.addInput(txHash, fixture.vout); - // // get byte count to calculate fee. paying 1 sat/byte - // let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 1 }); - // // amount to send to receiver. It's the original amount - 1 sat/byte for tx size - // let sendAmount = originalAmount - (byteCount * 15); - // // add output w/ address and amount to send - // let redeemScript - // transactionBuilder.addOutput(fixture.outputs[0], sendAmount); - // transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - // - // // build tx - // let tx = transactionBuilder.build(); - // // output rawhex - // let hex = tx.toHex(); - // assert.equal(hex, fixture.hex); - // }); - // }); - // }); - }); - - describe('#toMany', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2ms.toMany.mainnet.forEach((fixture) => { - it(`should create 1-to-2 P2MS transaction on mainnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let node3 = BITBOX.HDNode.fromXPriv(fixture.xprivs[2]); - let node4 = BITBOX.HDNode.fromXPriv(fixture.xprivs[3]); - let node5 = BITBOX.HDNode.fromXPriv(fixture.xprivs[4]); - let node6 = BITBOX.HDNode.fromXPriv(fixture.xprivs[5]); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let txid = fixture.txHash; - let originalAmount = fixture.amount; - let pubKey1 = BITBOX.HDNode.toPublicKey(node1); - let pubKey2 = BITBOX.HDNode.toPublicKey(node2); - let buf1 = BITBOX.Script.multisig.output.encode(1, [pubKey1, pubKey2]); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, buf1); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 3 }, { P2PKH: 3 }); - let sendAmount = originalAmount - byteCount; - let pubKey3 = BITBOX.HDNode.toPublicKey(node3); - let pubKey4 = BITBOX.HDNode.toPublicKey(node4); - let buf2 = BITBOX.Script.multisig.output.encode(1, [pubKey3, pubKey4]); - transactionBuilder.addOutput(buf2, Math.floor(sendAmount / 2)); - let pubKey5 = BITBOX.HDNode.toPublicKey(node5); - let pubKey6 = BITBOX.HDNode.toPublicKey(node6); - let buf3 = BITBOX.Script.multisig.output.encode(1, [pubKey5, pubKey6]); - transactionBuilder.addOutput(buf3, Math.floor(sendAmount / 2)); - let redeemScript - let keyPair = BITBOX.HDNode.toKeyPair(node1); - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - // describe('#Testnet', () => { - // fixtures.scripts.p2ms.toMany.testnet.forEach((fixture) => { - // // TODO pass in tesnet network config - // it(`should create 1-to-2 P2MS transaction on testnet`, () => { - // let hdnode = BITBOX.HDNode.fromXPriv(fixture.xpriv); - // let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - // let keyPair = BITBOX.HDNode.toKeyPair(hdnode); - // let txHash = fixture.txHash; - // // original amount of satoshis in vin - // let originalAmount = fixture.amount; - // transactionBuilder.addInput(txHash, fixture.vout); - // // get byte count to calculate fee. paying 1 sat/byte - // let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 2 }); - // // amount to send to receiver. It's the original amount - 1 sat/byte for tx size - // let sendAmount = originalAmount - (byteCount * 15); - // // add output w/ address and amount to send - // transactionBuilder.addOutput(fixture.outputs[0], Math.floor(sendAmount / 2)); - // transactionBuilder.addOutput(fixture.outputs[1], Math.floor(sendAmount / 2)); - // let redeemScript - // transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - // // build tx - // let tx = transactionBuilder.build(); - // // output rawhex - // let hex = tx.toHex(); - // assert.equal(hex, fixture.hex); - // }); - // }); - // }); - }); - - describe('#manyToMany', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2ms.manyToMany.mainnet.forEach((fixture) => { - it(`should create 2-to-2 P2MS transaction on mainnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let node3 = BITBOX.HDNode.fromXPriv(fixture.xprivs[2]); - let node4 = BITBOX.HDNode.fromXPriv(fixture.xprivs[3]); - let node5 = BITBOX.HDNode.fromXPriv(fixture.xprivs[4]); - let node6 = BITBOX.HDNode.fromXPriv(fixture.xprivs[5]); - let node7 = BITBOX.HDNode.fromXPriv(fixture.xprivs[6]); - let node8 = BITBOX.HDNode.fromXPriv(fixture.xprivs[7]); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let txid = fixture.txHash; - let originalAmount = fixture.amount; - let pubKey1 = BITBOX.HDNode.toPublicKey(node1); - let pubKey2 = BITBOX.HDNode.toPublicKey(node2); - let buf1 = BITBOX.Script.multisig.output.encode(1, [pubKey1, pubKey2]); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, buf1); - let pubKey3 = BITBOX.HDNode.toPublicKey(node3); - let pubKey4 = BITBOX.HDNode.toPublicKey(node4); - let buf2 = BITBOX.Script.multisig.output.encode(1, [pubKey3, pubKey4]); - transactionBuilder.addInput(txid, 1, transactionBuilder.DEFAULT_SEQUENCE, buf2); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 3 }, { P2PKH: 3 }); - let sendAmount = originalAmount - byteCount; - let pubKey5 = BITBOX.HDNode.toPublicKey(node5); - let pubKey6 = BITBOX.HDNode.toPublicKey(node6); - let buf3 = BITBOX.Script.multisig.output.encode(1, [pubKey5, pubKey6]); - transactionBuilder.addOutput(buf3, Math.floor(sendAmount / 2)); - let pubKey7 = BITBOX.HDNode.toPublicKey(node7); - let pubKey8 = BITBOX.HDNode.toPublicKey(node8); - let buf4 = BITBOX.Script.multisig.output.encode(1, [pubKey7, pubKey8]); - transactionBuilder.addOutput(buf4, Math.floor(sendAmount / 2)); - let redeemScript - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - let keyPair2 = BITBOX.HDNode.toKeyPair(node3); - transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - // describe('#Testnet', () => { - // fixtures.scripts.p2ms.manyToMany.testnet.forEach((fixture) => { - // it(`should create 2-to-2 P2MS transaction on testnet`, () => { - // let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - // let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - // let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - // let txHash = fixture.txHash; - // let originalAmount = fixture.amounts[0] + fixture.amounts[1]; - // transactionBuilder.addInput(txHash, 0); - // transactionBuilder.addInput(txHash, 1); - // let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 2 }, { P2PKH: 2 }); - // let sendAmount = originalAmount - (byteCount * 15); - // transactionBuilder.addOutput(fixture.outputs[0], Math.floor(sendAmount / 2)); - // transactionBuilder.addOutput(fixture.outputs[1], Math.floor(sendAmount / 2)); - // let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - // let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - // let redeemScript; - // transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[0]); - // transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[1]); - // let tx = transactionBuilder.build(); - // let hex = tx.toHex(); - // assert.equal(hex, fixture.hex); - // }); - // }); - // }); - }); - - describe('#fromMany', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2ms.fromMany.mainnet.forEach((fixture) => { - it(`should create 2-to-1 P2MS transaction on mainnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let node3 = BITBOX.HDNode.fromXPriv(fixture.xprivs[2]); - let node4 = BITBOX.HDNode.fromXPriv(fixture.xprivs[3]); - let node5 = BITBOX.HDNode.fromXPriv(fixture.xprivs[4]); - let node6 = BITBOX.HDNode.fromXPriv(fixture.xprivs[5]); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let txid = fixture.txHash; - let originalAmount = fixture.amount; - let pubKey1 = BITBOX.HDNode.toPublicKey(node1); - let pubKey2 = BITBOX.HDNode.toPublicKey(node2); - let buf1 = BITBOX.Script.multisig.output.encode(1, [pubKey1, pubKey2]); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, buf1); - let pubKey3 = BITBOX.HDNode.toPublicKey(node3); - let pubKey4 = BITBOX.HDNode.toPublicKey(node4); - let buf2 = BITBOX.Script.multisig.output.encode(1, [pubKey3, pubKey4]); - transactionBuilder.addInput(txid, 1, transactionBuilder.DEFAULT_SEQUENCE, buf2); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 3 }, { P2PKH: 3 }); - let sendAmount = originalAmount - byteCount; - let pubKey5 = BITBOX.HDNode.toPublicKey(node5); - let pubKey6 = BITBOX.HDNode.toPublicKey(node6); - let buf3 = BITBOX.Script.multisig.output.encode(1, [pubKey5, pubKey6]); - transactionBuilder.addOutput(buf3, sendAmount); - let redeemScript - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - let keyPair2 = BITBOX.HDNode.toKeyPair(node3); - transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - // describe('#Testnet', () => { - // fixtures.scripts.p2ms.fromMany.testnet.forEach((fixture) => { - // it(`should create 2-to-1 P2MS transaction on testnet`, () => { - // let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - // let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - // let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - // let txHash = fixture.txHash; - // let originalAmount = fixture.amounts[0] + fixture.amounts[1]; - // transactionBuilder.addInput(txHash, 0); - // transactionBuilder.addInput(txHash, 1); - // let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 2 }, { P2PKH: 1 }); - // let sendAmount = originalAmount - (byteCount * 15); - // transactionBuilder.addOutput(fixture.outputs[0], sendAmount); - // let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - // let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - // let redeemScript; - // transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[0]); - // transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[1]); - // let tx = transactionBuilder.build(); - // let hex = tx.toHex(); - // assert.equal(hex, fixture.hex); - // }); - // }); - // }); - }); - }); - - describe('#P2SH', () => { - describe('#toOne', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2sh.toOne.mainnet.forEach((fixture) => { - it(`should create 1-to-1 P2SH transaction on mainnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let txid = fixture.txHash; - let originalAmount = fixture.amount; - let identifier1 = BITBOX.HDNode.toIdentifier(node1); - let buf1 = BITBOX.Script.encode([ - BITBOX.Script.opcodes.OP_DUP, - BITBOX.Script.opcodes.OP_HASH160, - identifier1, - BITBOX.Script.opcodes.OP_EQUALVERIFY, - BITBOX.Script.opcodes.OP_CHECKSIG - ]); - let scriptHash1 = BITBOX.Crypto.hash160(buf1); - let data1 = BITBOX.Script.scriptHash.output.encode(scriptHash1); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, data1); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 2 }, { P2PKH: 1 }); - let sendAmount = originalAmount - byteCount; - let identifier2 = BITBOX.HDNode.toIdentifier(node2); - let buf2 = BITBOX.Script.encode([ - BITBOX.Script.opcodes.OP_DUP, - BITBOX.Script.opcodes.OP_HASH160, - identifier2, - BITBOX.Script.opcodes.OP_EQUALVERIFY, - BITBOX.Script.opcodes.OP_CHECKSIG - ]) - - let scriptHash2 = BITBOX.Crypto.hash160(buf2); - let data2 = BITBOX.Script.scriptHash.output.encode(scriptHash2); - transactionBuilder.addOutput(data2, sendAmount); - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - transactionBuilder.sign(0, keyPair1, buf1, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - // describe('#Testnet', () => { - // fixtures.scripts.p2sh.toOne.testnet.forEach((fixture) => { - // it(`should create 1-to-1 P2SH transaction on testnet`, () => { - // let hdnode = BITBOX.HDNode.fromXPriv(fixture.xpriv, 'testnet'); - // let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - // let keyPair = BITBOX.HDNode.toKeyPair(hdnode); - // let txHash = fixture.txHash; - // // original amount of satoshis in vin - // let originalAmount = fixture.amount; - // transactionBuilder.addInput(txHash, fixture.vout); - // // get byte count to calculate fee. paying 1 sat/byte - // let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 1 }); - // // amount to send to receiver. It's the original amount - 1 sat/byte for tx size - // let sendAmount = originalAmount - (byteCount * 15); - // // add output w/ address and amount to send - // let redeemScript - // transactionBuilder.addOutput(fixture.outputs[0], sendAmount); - // transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - // - // // build tx - // let tx = transactionBuilder.build(); - // // output rawhex - // let hex = tx.toHex(); - // assert.equal(hex, fixture.hex); - // }); - // }); - // }); - }); - - describe('#toMany', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2sh.toMany.mainnet.forEach((fixture) => { - it(`should create 1-to-2 P2SH transaction on mainnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let node3 = BITBOX.HDNode.fromXPriv(fixture.xprivs[2]); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let txid = fixture.txHash; - let originalAmount = fixture.amount; - let identifier1 = BITBOX.HDNode.toIdentifier(node1); - let buf1 = BITBOX.Script.encode([ - BITBOX.Script.opcodes.OP_DUP, - BITBOX.Script.opcodes.OP_HASH160, - identifier1, - BITBOX.Script.opcodes.OP_EQUALVERIFY, - BITBOX.Script.opcodes.OP_CHECKSIG - ]); - let scriptHash1 = BITBOX.Crypto.hash160(buf1); - let data1 = BITBOX.Script.scriptHash.output.encode(scriptHash1); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, data1); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 3 }, { P2PKH: 2 }); - let sendAmount = originalAmount - byteCount; - let identifier2 = BITBOX.HDNode.toIdentifier(node2); - let buf2 = BITBOX.Script.encode([ - BITBOX.Script.opcodes.OP_DUP, - BITBOX.Script.opcodes.OP_HASH160, - identifier2, - BITBOX.Script.opcodes.OP_EQUALVERIFY, - BITBOX.Script.opcodes.OP_CHECKSIG - ]) - let scriptHash2 = BITBOX.Crypto.hash160(buf2); - let data2 = BITBOX.Script.scriptHash.output.encode(scriptHash2); - transactionBuilder.addOutput(data2, Math.floor(sendAmount / 2)); - let identifier3 = BITBOX.HDNode.toIdentifier(node3); - let buf3 = BITBOX.Script.encode([ - BITBOX.Script.opcodes.OP_DUP, - BITBOX.Script.opcodes.OP_HASH160, - identifier3, - BITBOX.Script.opcodes.OP_EQUALVERIFY, - BITBOX.Script.opcodes.OP_CHECKSIG - ]) - let scriptHash3 = BITBOX.Crypto.hash160(buf3); - let data3 = BITBOX.Script.scriptHash.output.encode(scriptHash3); - transactionBuilder.addOutput(data3, Math.floor(sendAmount / 2)); - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - transactionBuilder.sign(0, keyPair1, buf1, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - // describe('#Testnet', () => { - // fixtures.scripts.p2sh.toMany.testnet.forEach((fixture) => { - // // TODO pass in tesnet network config - // it(`should create 1-to-2 P2SH transaction on testnet`, () => { - // let hdnode = BITBOX.HDNode.fromXPriv(fixture.xpriv); - // let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - // let keyPair = BITBOX.HDNode.toKeyPair(hdnode); - // let txHash = fixture.txHash; - // // original amount of satoshis in vin - // let originalAmount = fixture.amount; - // transactionBuilder.addInput(txHash, fixture.vout); - // // get byte count to calculate fee. paying 1 sat/byte - // let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 2 }); - // // amount to send to receiver. It's the original amount - 1 sat/byte for tx size - // let sendAmount = originalAmount - (byteCount * 15); - // // add output w/ address and amount to send - // transactionBuilder.addOutput(fixture.outputs[0], Math.floor(sendAmount / 2)); - // transactionBuilder.addOutput(fixture.outputs[1], Math.floor(sendAmount / 2)); - // let redeemScript - // transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); - // // build tx - // let tx = transactionBuilder.build(); - // // output rawhex - // let hex = tx.toHex(); - // assert.equal(hex, fixture.hex); - // }); - // }); - // }); - }); - - describe('#manyToMany', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2sh.manyToMany.mainnet.forEach((fixture) => { - it(`should create 2-to-2 P2SH transaction on mainnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let node3 = BITBOX.HDNode.fromXPriv(fixture.xprivs[2]); - let node4 = BITBOX.HDNode.fromXPriv(fixture.xprivs[3]); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let txid = fixture.txHash; - let originalAmount = fixture.amount; - let identifier1 = BITBOX.HDNode.toIdentifier(node1); - let buf1 = BITBOX.Script.encode([ - BITBOX.Script.opcodes.OP_DUP, - BITBOX.Script.opcodes.OP_HASH160, - identifier1, - BITBOX.Script.opcodes.OP_EQUALVERIFY, - BITBOX.Script.opcodes.OP_CHECKSIG - ]); - let scriptHash1 = BITBOX.Crypto.hash160(buf1); - let data1 = BITBOX.Script.scriptHash.output.encode(scriptHash1); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, data1); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 5 }, { P2PKH: 5 }); - let sendAmount = originalAmount - byteCount; - let identifier2 = BITBOX.HDNode.toIdentifier(node2); - let buf2 = BITBOX.Script.encode([ - BITBOX.Script.opcodes.OP_DUP, - BITBOX.Script.opcodes.OP_HASH160, - identifier2, - BITBOX.Script.opcodes.OP_EQUALVERIFY, - BITBOX.Script.opcodes.OP_CHECKSIG - ]) - let scriptHash2 = BITBOX.Crypto.hash160(buf2); - let data2 = BITBOX.Script.scriptHash.output.encode(scriptHash2); - transactionBuilder.addInput(txid, 1, transactionBuilder.DEFAULT_SEQUENCE, data2); - let identifier3 = BITBOX.HDNode.toIdentifier(node3); - let buf3 = BITBOX.Script.encode([ - BITBOX.Script.opcodes.OP_DUP, - BITBOX.Script.opcodes.OP_HASH160, - identifier3, - BITBOX.Script.opcodes.OP_EQUALVERIFY, - BITBOX.Script.opcodes.OP_CHECKSIG - ]) - let scriptHash3 = BITBOX.Crypto.hash160(buf3); - let data3 = BITBOX.Script.scriptHash.output.encode(scriptHash3); - transactionBuilder.addOutput(data3, Math.floor(sendAmount / 2)); - let identifier4 = BITBOX.HDNode.toIdentifier(node4); - let buf4 = BITBOX.Script.encode([ - BITBOX.Script.opcodes.OP_DUP, - BITBOX.Script.opcodes.OP_HASH160, - identifier4, - BITBOX.Script.opcodes.OP_EQUALVERIFY, - BITBOX.Script.opcodes.OP_CHECKSIG - ]) - let scriptHash4 = BITBOX.Crypto.hash160(buf4); - let data4 = BITBOX.Script.scriptHash.output.encode(scriptHash4); - transactionBuilder.addOutput(data4, Math.floor(sendAmount / 2)); - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - transactionBuilder.sign(0, keyPair1, buf1, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - transactionBuilder.sign(1, keyPair2, buf2, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - // describe('#Testnet', () => { - // fixtures.scripts.p2sh.manyToMany.testnet.forEach((fixture) => { - // it(`should create 2-to-2 P2SH transaction on testnet`, () => { - // let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - // let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - // let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - // let txHash = fixture.txHash; - // let originalAmount = fixture.amounts[0] + fixture.amounts[1]; - // transactionBuilder.addInput(txHash, 0); - // transactionBuilder.addInput(txHash, 1); - // let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 2 }, { P2PKH: 2 }); - // let sendAmount = originalAmount - (byteCount * 15); - // transactionBuilder.addOutput(fixture.outputs[0], Math.floor(sendAmount / 2)); - // transactionBuilder.addOutput(fixture.outputs[1], Math.floor(sendAmount / 2)); - // let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - // let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - // let redeemScript; - // transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[0]); - // transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[1]); - // let tx = transactionBuilder.build(); - // let hex = tx.toHex(); - // assert.equal(hex, fixture.hex); - // }); - // }); - // }); - }); - - describe('#fromMany', () => { - describe('#Mainnet', () => { - fixtures.scripts.p2sh.fromMany.mainnet.forEach((fixture) => { - it(`should create 2-to-1 P2SH transaction on mainnet`, () => { - let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - let node3 = BITBOX.HDNode.fromXPriv(fixture.xprivs[2]); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let txid = fixture.txHash; - let originalAmount = fixture.amount; - let identifier1 = BITBOX.HDNode.toIdentifier(node1); - let buf1 = BITBOX.Script.encode([ - BITBOX.Script.opcodes.OP_DUP, - BITBOX.Script.opcodes.OP_HASH160, - identifier1, - BITBOX.Script.opcodes.OP_EQUALVERIFY, - BITBOX.Script.opcodes.OP_CHECKSIG - ]); - let scriptHash1 = BITBOX.Crypto.hash160(buf1); - let data1 = BITBOX.Script.scriptHash.output.encode(scriptHash1); - transactionBuilder.addInput(txid, 0, transactionBuilder.DEFAULT_SEQUENCE, data1); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 3 }, { P2PKH: 2 }); - let sendAmount = originalAmount - byteCount; - let identifier2 = BITBOX.HDNode.toIdentifier(node2); - let buf2 = BITBOX.Script.encode([ - BITBOX.Script.opcodes.OP_DUP, - BITBOX.Script.opcodes.OP_HASH160, - identifier2, - BITBOX.Script.opcodes.OP_EQUALVERIFY, - BITBOX.Script.opcodes.OP_CHECKSIG - ]) - let scriptHash2 = BITBOX.Crypto.hash160(buf2); - let data2 = BITBOX.Script.scriptHash.output.encode(scriptHash2); - transactionBuilder.addInput(txid, 1, transactionBuilder.DEFAULT_SEQUENCE, data2); - let identifier3 = BITBOX.HDNode.toIdentifier(node3); - let buf3 = BITBOX.Script.encode([ - BITBOX.Script.opcodes.OP_DUP, - BITBOX.Script.opcodes.OP_HASH160, - identifier3, - BITBOX.Script.opcodes.OP_EQUALVERIFY, - BITBOX.Script.opcodes.OP_CHECKSIG - ]) - let scriptHash3 = BITBOX.Crypto.hash160(buf3); - let data3 = BITBOX.Script.scriptHash.output.encode(scriptHash3); - transactionBuilder.addOutput(data3, sendAmount); - let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - transactionBuilder.sign(0, keyPair1, buf1, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - transactionBuilder.sign(1, keyPair2, buf2, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount / 2); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - // describe('#Testnet', () => { - // fixtures.scripts.p2sh.fromMany.testnet.forEach((fixture) => { - // it(`should create 2-to-1 P2SH transaction on testnet`, () => { - // let node1 = BITBOX.HDNode.fromXPriv(fixture.xprivs[0]); - // let node2 = BITBOX.HDNode.fromXPriv(fixture.xprivs[1]); - // let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - // let txHash = fixture.txHash; - // let originalAmount = fixture.amounts[0] + fixture.amounts[1]; - // transactionBuilder.addInput(txHash, 0); - // transactionBuilder.addInput(txHash, 1); - // let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 2 }, { P2PKH: 1 }); - // let sendAmount = originalAmount - (byteCount * 15); - // transactionBuilder.addOutput(fixture.outputs[0], sendAmount); - // let keyPair1 = BITBOX.HDNode.toKeyPair(node1); - // let keyPair2 = BITBOX.HDNode.toKeyPair(node2); - // let redeemScript; - // transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[0]); - // transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[1]); - // let tx = transactionBuilder.build(); - // let hex = tx.toHex(); - // assert.equal(hex, fixture.hex); - // }); - // }); - // }); - }); - }); - - describe('#op_return', () => { - describe('#Mainnet', () => { - fixtures.nulldata.mainnet.forEach((fixture) => { - it(`should create transaction w/ OP_RETURN output on mainnet`, () => { - let node = BITBOX.HDNode.fromXPriv(fixture.xpriv); - let transactionBuilder = new BITBOX.TransactionBuilder(); - let txHash = fixture.txHash; - let originalAmount = fixture.amount; - transactionBuilder.addInput(txHash, 0); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 5 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(fixture.output, sendAmount); - let data = fixture.data; - let buf = BITBOX.Script.nullData.output.encode(Buffer.from(data, 'ascii')); - transactionBuilder.addOutput(buf, 0); - let keyPair = BITBOX.HDNode.toKeyPair(node); - let redeemScript; - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amount); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - - describe('#Testnet', () => { - fixtures.nulldata.testnet.forEach((fixture) => { - it(`should create transaction w/ OP_RETURN output on testnet`, () => { - let node = BITBOX.HDNode.fromXPriv(fixture.xpriv); - let transactionBuilder = new BITBOX.TransactionBuilder('testnet'); - let txHash = fixture.txHash; - let originalAmount = fixture.amount; - transactionBuilder.addInput(txHash, 0); - let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 5 }); - let sendAmount = originalAmount - byteCount; - transactionBuilder.addOutput(fixture.output, sendAmount); - let data = fixture.data; - let buf = BITBOX.Script.nullData.output.encode(Buffer.from(data, 'ascii')); - transactionBuilder.addOutput(buf, 0); - let keyPair = BITBOX.HDNode.toKeyPair(node); - let redeemScript; - transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amount); - let tx = transactionBuilder.build(); - let hex = tx.toHex(); - assert.equal(hex, fixture.hex); - }); - }); - }); - }); - - describe('#bip168', () => { - fixtures.bip68.encode.forEach((fixture) => { - it(`should encode as ${fixture.result}`, () => { - let transactionBuilder = new BITBOX.TransactionBuilder(); - let obj = {}; - obj[fixture.type] = fixture.value; - let encode = transactionBuilder.bip68.encode(obj); - assert.equal(encode, fixture.result); - }); - }); - - fixtures.bip68.decode.forEach((fixture) => { - it(`should decode ${fixture.result}`, () => { - let transactionBuilder = new BITBOX.TransactionBuilder(); - let obj = {}; - let decode = transactionBuilder.bip68.decode(fixture.result); - assert.equal(Object.keys(decode)[0], fixture.type); - assert.deepEqual(decode[Object.keys(decode)[0]], fixture.value); - }); - }); - }); -}); diff --git a/test/Util.js b/test/Util.js deleted file mode 100644 index 43f0f958..00000000 --- a/test/Util.js +++ /dev/null @@ -1,38 +0,0 @@ -// let fixtures = require('./fixtures/BitcoinCash.json') -let chai = require('chai'); -let assert = require('assert'); -let axios = require('axios'); -let BITBOXCli = require('./../lib/bitbox-cli').default; -let BITBOX = new BITBOXCli(); -let sinon = require('sinon'); - -describe('#Util', () => { - describe('#validateAddress', () => { - let sandbox; - beforeEach(() => sandbox = sinon.sandbox.create()); - afterEach(() => sandbox.restore()); - - it('should validate address', (done) => { - let data = { - isvalid: true, - address: 'bitcoincash:qpz7qtkuyhrsz4qmnnrvf8gz9zd0u9v7eqsewyk4w5', - scriptPubKey: '76a91445e02edc25c701541b9cc6c49d02289afe159ec888ac', - ismine: false, - iswatchonly: false, - isscript: false - }; - - const resolved = new Promise((r) => r({ data: data })); - sandbox.stub(axios, 'get').returns(resolved); - - BITBOX.Util.validateAddress('bitcoincash:qpz7qtkuyhrsz4qmnnrvf8gz9zd0u9v7eqsewyk4w5') - .then((result) => { - assert.deepEqual( - data, - result - ); - }) - .then(done, done); - }); - }); -}); diff --git a/test/e2e/send-raw-transaction-bulk/package.json b/test/e2e/send-raw-transaction-bulk/package.json new file mode 100644 index 00000000..6f2b009f --- /dev/null +++ b/test/e2e/send-raw-transaction-bulk/package.json @@ -0,0 +1,28 @@ +{ + "name": "sendrawtransaction", + "version": "1.0.0", + "description": "e2e test - Send two transactions in parallel.", + "main": "sendrawtransaction.js", + "scripts": { + "test": "echo no tests yet", + "start": "node sendrawtransaction.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Bitcoin-com/bitbox-javascript-sdk.git" + }, + "keywords": [ + "bitbox", + "bch", + "bitcoin", + "bitcoin cash", + "bitcoin.com", + "javascript" + ], + "author": "Chris Troutner ", + "license": "MIT", + "bugs": { + "url": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/issues" + }, + "homepage": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/blob/master/README.md" +} diff --git a/test/e2e/send-raw-transaction-bulk/sendrawtransaction.js b/test/e2e/send-raw-transaction-bulk/sendrawtransaction.js new file mode 100644 index 00000000..ce090749 --- /dev/null +++ b/test/e2e/send-raw-transaction-bulk/sendrawtransaction.js @@ -0,0 +1,281 @@ +/* + This is an end-to-end test adapted from the send-bch example. It's purpose + is to test the sendRawTransaction endpoint. Since the single call is tested + all the time, this test focuses on testing the bulk endpoint by sending + two transactions at once. + + Instructions: + - Ensure the address in the wallet.json file has some tBCH. + - Ensure the address in the wallet.json file has two UTXOs between 0.1 and + 0.001 tBCH + - This test will generate two transactions from two UTXOs and broadcast them + using the sendrawtransaction bulk endpoint. +*/ + +// Replace the address below with the address you want to send the BCH to. +const RECV_ADDR1 = `bchtest:qzfn2mly05t6fjsh5kjj0dqq0jjtct27ng089dgg05` +const RECV_ADDR2 = `bchtest:qz6yw0kqgfkknfy6jh2jvlfnkzmre3lt2u0pgcckdk` +const SATOSHIS_TO_SEND = 1000 + +// Instantiate bitbox. +const bitboxLib = "../../../lib/BITBOX" +const BITBOXSDK = require(bitboxLib) +const BITBOX = new BITBOXSDK({ restURL: "https://trest.bitcoin.com/v2/" }) +//const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" }) + +const util = require("util") + +// Open the wallet generated with create-wallet. +try { + var walletInfo = require(`./wallet.json`) +} catch (err) { + console.log( + `Could not open wallet.json. Generate a wallet with create-wallet first.` + ) + process.exit(0) +} + +const SEND_ADDR = walletInfo.cashAddress +const SEND_MNEMONIC = walletInfo.mnemonic + +async function testSend() { + try { + const hex1 = await buildTx1(RECV_ADDR1) + const hex2 = await buildTx2(RECV_ADDR2) + + console.log(`hex1: ${hex1}\n\n`) + console.log(`hex2: ${hex2}\n\n`) + + const broadcast = await bitbox.RawTransactions.sendRawTransaction([ + hex1, + hex2 + ]) + console.log(`Transaction IDs: ${JSON.stringify(broadcast, null, 2)}`) + console.log(`Should return an array of TXID strings.`) + } catch (err) { + console.log(`Error in testSend: `, err) + } +} +testSend() + +// Build a TX hex with the largest UTXO. +async function buildTx1(recAddr) { + try { + // Get the balance of the sending address. + const balance = await getBCHBalance(SEND_ADDR, false) + console.log(`balance: ${JSON.stringify(balance, null, 2)}`) + console.log(`Balance of sending address ${SEND_ADDR} is ${balance} BCH.`) + + // Exit if the balance is zero. + if (balance <= 0.0) { + console.log(`Balance of sending address is zero. Exiting.`) + process.exit(0) + } + + const SEND_ADDR_LEGACY = bitbox.Address.toLegacyAddress(SEND_ADDR) + const RECV_ADDR_LEGACY = bitbox.Address.toLegacyAddress(recAddr) + console.log(`Sender Legacy Address: ${SEND_ADDR_LEGACY}`) + console.log(`Receiver Legacy Address: ${RECV_ADDR_LEGACY}`) + + const balance2 = await getBCHBalance(recAddr, false) + //console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`) + + const u = await bitbox.Address.utxo(SEND_ADDR) + //console.log(`u: ${JSON.stringify(u, null, 2)}`) + const utxo = findBiggestUtxo(u.utxos) + console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`) + + // instance of transaction builder + const transactionBuilder = new bitbox.TransactionBuilder("testnet") + + const satoshisToSend = SATOSHIS_TO_SEND + const originalAmount = utxo.satoshis + const vout = utxo.vout + const txid = utxo.txid + + // add input with txid and index of vout + transactionBuilder.addInput(txid, vout) + + // get byte count to calculate fee. paying 1.2 sat/byte + const byteCount = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 2 } + ) + console.log(`byteCount: ${byteCount}`) + const satoshisPerByte = 1.0 + const txFee = Math.floor(satoshisPerByte * byteCount) + console.log(`txFee: ${txFee}`) + + // amount to send back to the sending address. + // It's the original amount - 1 sat/byte for tx size + const remainder = originalAmount - satoshisToSend - txFee + + // add output w/ address and amount to send + transactionBuilder.addOutput(recAddr, satoshisToSend) + transactionBuilder.addOutput(SEND_ADDR, remainder) + + // Generate a change address from a Mnemonic of a private key. + const change = changeAddrFromMnemonic(SEND_MNEMONIC) + + // Generate a keypair from the change address. + const keyPair = bitbox.HDNode.toKeyPair(change) + + // Sign the transaction with the HD node. + let redeemScript + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + + // build tx + const tx = transactionBuilder.build() + // output rawhex + const hex = tx.toHex() + + return hex + } catch (err) { + console.log(`Error in buildTx().`) + throw err + } +} + +// Build a TX hex with the SECOND largest UTXO. +async function buildTx2(recAddr) { + try { + // Get the balance of the sending address. + const balance = await getBCHBalance(SEND_ADDR, false) + console.log(`balance: ${JSON.stringify(balance, null, 2)}`) + console.log(`Balance of sending address ${SEND_ADDR} is ${balance} BCH.`) + + // Exit if the balance is zero. + if (balance <= 0.0) { + console.log(`Balance of sending address is zero. Exiting.`) + process.exit(0) + } + + const SEND_ADDR_LEGACY = bitbox.Address.toLegacyAddress(SEND_ADDR) + const RECV_ADDR_LEGACY = bitbox.Address.toLegacyAddress(recAddr) + console.log(`Sender Legacy Address: ${SEND_ADDR_LEGACY}`) + console.log(`Receiver Legacy Address: ${RECV_ADDR_LEGACY}`) + + const balance2 = await getBCHBalance(recAddr, false) + //console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`) + + const u = await bitbox.Address.utxo(SEND_ADDR) + //console.log(`u: ${JSON.stringify(u, null, 2)}`) + const utxo = findNextBiggestUtxo(u.utxos) + console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`) + + // instance of transaction builder + const transactionBuilder = new bitbox.TransactionBuilder("testnet") + + const satoshisToSend = SATOSHIS_TO_SEND + const originalAmount = utxo.satoshis + const vout = utxo.vout + const txid = utxo.txid + + // add input with txid and index of vout + transactionBuilder.addInput(txid, vout) + + // get byte count to calculate fee. paying 1.2 sat/byte + const byteCount = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 2 } + ) + console.log(`byteCount: ${byteCount}`) + const satoshisPerByte = 1.0 + const txFee = Math.floor(satoshisPerByte * byteCount) + console.log(`txFee: ${txFee}`) + + // amount to send back to the sending address. + // It's the original amount - 1 sat/byte for tx size + const remainder = originalAmount - satoshisToSend - txFee + + // add output w/ address and amount to send + transactionBuilder.addOutput(recAddr, satoshisToSend) + transactionBuilder.addOutput(SEND_ADDR, remainder) + + // Generate a change address from a Mnemonic of a private key. + const change = changeAddrFromMnemonic(SEND_MNEMONIC) + + // Generate a keypair from the change address. + const keyPair = bitbox.HDNode.toKeyPair(change) + + // Sign the transaction with the HD node. + let redeemScript + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + + // build tx + const tx = transactionBuilder.build() + // output rawhex + const hex = tx.toHex() + + return hex + } catch (err) { + console.log(`Error in buildTx().`) + throw err + } +} + +// Generate a change address from a Mnemonic of a private key. +function changeAddrFromMnemonic(mnemonic) { + // root seed buffer + const rootSeed = bitbox.Mnemonic.toSeed(mnemonic) + + // master HDNode + const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, "testnet") + + // HDNode of BIP44 account + const account = bitbox.HDNode.derivePath(masterHDNode, "m/44'/145'/0'") + + // derive the first external change address HDNode which is going to spend utxo + const change = bitbox.HDNode.derivePath(account, "0/0") + + return change +} + +// Get the balance in BCH of a BCH address. +async function getBCHBalance(addr, verbose) { + try { + const result = await bitbox.Address.details(addr) + + if (verbose) console.log(result) + + const bchBalance = result + + return bchBalance.balance + } catch (err) { + console.error(`Error in getBCHBalance: `, err) + console.log(`addr: ${addr}`) + throw err + } +} + +// Returns the utxo with the biggest balance from an array of utxos. +function findBiggestUtxo(utxos) { + // Sort the utxos by the amount of satoshis, largest first. + utxos.sort(function(a, b) { + return b.satoshis - a.satoshis + }) + + return utxos[0] +} + +// Returns the utxo with the 2nd biggest balance from an array of utxos. +function findNextBiggestUtxo(utxos) { + // Sort the utxos by the amount of satoshis, largest first. + utxos.sort(function(a, b) { + return b.satoshis - a.satoshis + }) + + return utxos[1] +} diff --git a/test/e2e/send-raw-transaction-single/package.json b/test/e2e/send-raw-transaction-single/package.json new file mode 100644 index 00000000..6f2b009f --- /dev/null +++ b/test/e2e/send-raw-transaction-single/package.json @@ -0,0 +1,28 @@ +{ + "name": "sendrawtransaction", + "version": "1.0.0", + "description": "e2e test - Send two transactions in parallel.", + "main": "sendrawtransaction.js", + "scripts": { + "test": "echo no tests yet", + "start": "node sendrawtransaction.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Bitcoin-com/bitbox-javascript-sdk.git" + }, + "keywords": [ + "bitbox", + "bch", + "bitcoin", + "bitcoin cash", + "bitcoin.com", + "javascript" + ], + "author": "Chris Troutner ", + "license": "MIT", + "bugs": { + "url": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/issues" + }, + "homepage": "https://github.com/Bitcoin-com/bitbox-javascript-sdk/blob/master/README.md" +} diff --git a/test/e2e/send-raw-transaction-single/sendrawtransaction.js b/test/e2e/send-raw-transaction-single/sendrawtransaction.js new file mode 100644 index 00000000..c936daa1 --- /dev/null +++ b/test/e2e/send-raw-transaction-single/sendrawtransaction.js @@ -0,0 +1,184 @@ +/* + This is an end-to-end test adapted from the send-bch example. It's purpose + is to test the sendRawTransaction endpoint. + + This version tests the single send call. + + Instructions: + - Ensure the address in the wallet.json file has some tBCH. + - Ensure the address in the wallet.json file has a UTXOs between 0.1 and + 0.001 tBCH + - This test will generate a single transaction from a UTXOs and broadcast it + using the sendrawtransaction single GET endpoint. +*/ + +// Replace the address below with the address you want to send the BCH to. +const RECV_ADDR1 = `bchtest:qzfn2mly05t6fjsh5kjj0dqq0jjtct27ng089dgg05` +const SATOSHIS_TO_SEND = 1000 + +// Instantiate bitbox. +const bitboxLib = "../../../lib/BITBOX" +const BITBOXSDK = require(bitboxLib) +const BITBOX = new BITBOXSDK({ restURL: "https://trest.bitcoin.com/v2/" }) +//const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" }) + +const util = require("util") + +// Open the wallet generated with create-wallet. +try { + var walletInfo = require(`./wallet.json`) +} catch (err) { + console.log( + `Could not open wallet.json. Generate a wallet with create-wallet first.` + ) + process.exit(0) +} + +const SEND_ADDR = walletInfo.cashAddress +const SEND_MNEMONIC = walletInfo.mnemonic + +async function testSend() { + try { + const hex1 = await buildTx1(RECV_ADDR1) + //const hex2 = await buildTx2(RECV_ADDR2) + + console.log(`hex1: ${hex1}\n\n`) + //console.log(`hex2: ${hex2}\n\n`) + + const broadcast = await bitbox.RawTransactions.sendRawTransaction(hex1) + + console.log(`Transaction IDs: ${JSON.stringify(broadcast, null, 2)}`) + console.log(`Should return a TXID string.`) + } catch (err) { + console.log(`Error in testSend: `, err) + } +} +testSend() + +// Build a TX hex with the largest UTXO. +async function buildTx1(recAddr) { + try { + // Get the balance of the sending address. + const balance = await getBCHBalance(SEND_ADDR, false) + console.log(`balance: ${JSON.stringify(balance, null, 2)}`) + console.log(`Balance of sending address ${SEND_ADDR} is ${balance} BCH.`) + + // Exit if the balance is zero. + if (balance <= 0.0) { + console.log(`Balance of sending address is zero. Exiting.`) + process.exit(0) + } + + const SEND_ADDR_LEGACY = bitbox.Address.toLegacyAddress(SEND_ADDR) + const RECV_ADDR_LEGACY = bitbox.Address.toLegacyAddress(recAddr) + console.log(`Sender Legacy Address: ${SEND_ADDR_LEGACY}`) + console.log(`Receiver Legacy Address: ${RECV_ADDR_LEGACY}`) + + const balance2 = await getBCHBalance(recAddr, false) + //console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`) + + const u = await bitbox.Address.utxo(SEND_ADDR) + //console.log(`u: ${JSON.stringify(u, null, 2)}`) + const utxo = findBiggestUtxo(u.utxos) + console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`) + + // instance of transaction builder + const transactionBuilder = new bitbox.TransactionBuilder("testnet") + + const satoshisToSend = SATOSHIS_TO_SEND + const originalAmount = utxo.satoshis + const vout = utxo.vout + const txid = utxo.txid + + // add input with txid and index of vout + transactionBuilder.addInput(txid, vout) + + // get byte count to calculate fee. paying 1.2 sat/byte + const byteCount = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 2 } + ) + console.log(`byteCount: ${byteCount}`) + const satoshisPerByte = 1.0 + const txFee = Math.floor(satoshisPerByte * byteCount) + console.log(`txFee: ${txFee}`) + + // amount to send back to the sending address. + // It's the original amount - 1 sat/byte for tx size + const remainder = originalAmount - satoshisToSend - txFee + + // add output w/ address and amount to send + transactionBuilder.addOutput(recAddr, satoshisToSend) + transactionBuilder.addOutput(SEND_ADDR, remainder) + + // Generate a change address from a Mnemonic of a private key. + const change = changeAddrFromMnemonic(SEND_MNEMONIC) + + // Generate a keypair from the change address. + const keyPair = bitbox.HDNode.toKeyPair(change) + + // Sign the transaction with the HD node. + let redeemScript + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + + // build tx + const tx = transactionBuilder.build() + // output rawhex + const hex = tx.toHex() + + return hex + } catch (err) { + console.log(`Error in buildTx().`) + throw err + } +} + +// Generate a change address from a Mnemonic of a private key. +function changeAddrFromMnemonic(mnemonic) { + // root seed buffer + const rootSeed = bitbox.Mnemonic.toSeed(mnemonic) + + // master HDNode + const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, "testnet") + + // HDNode of BIP44 account + const account = bitbox.HDNode.derivePath(masterHDNode, "m/44'/145'/0'") + + // derive the first external change address HDNode which is going to spend utxo + const change = bitbox.HDNode.derivePath(account, "0/0") + + return change +} + +// Get the balance in BCH of a BCH address. +async function getBCHBalance(addr, verbose) { + try { + const result = await bitbox.Address.details(addr) + + if (verbose) console.log(result) + + const bchBalance = result + + return bchBalance.balance + } catch (err) { + console.error(`Error in getBCHBalance: `, err) + console.log(`addr: ${addr}`) + throw err + } +} + +// Returns the utxo with the biggest balance from an array of utxos. +function findBiggestUtxo(utxos) { + // Sort the utxos by the amount of satoshis, largest first. + utxos.sort(function(a, b) { + return b.satoshis - a.satoshis + }) + + return utxos[0] +} diff --git a/test/fixtures/Address.json b/test/fixtures/Address.json deleted file mode 100644 index 8913722c..00000000 --- a/test/fixtures/Address.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "legacyMainnetP2PKH": [ - "18xHZ8g2feo4ceejGpvzHkvXT79fi2ZdTG", - "1K7Qb1dWkiYwPrZhLws3uUKhxKEU7dRnbQ", - "1Au7gWXS2zAgFSdWwT5QnTNeasye16kxoG", - "174uecjfRgh1XkVBYFzZymkV1JwmFQ91s9", - "1KLXUPMdq4vaU3VoQzSvLUx2mub5qzFkTc", - "12AqNsGTyL6RDR8SDEtW9EyfYruFNZ9Sjs", - "1P3Lq89iP27S76ZMKonty4mpJMDHp3a9NE", - "14A8F8jHiipwnKLd2JEWqPvbGiS6FA7VoG", - "1KgRZzxLUvZqL8EuufmdxqSjh3tgURwD6d", - "1GMApiWJoTfQ21jbtVX3Qz8YtnGUuZAJtS" - ], - "legacyMainnetP2SH": [ - "3DA6RBcFgLwLTpnF6BRAee8w6a9H6JQLCm", - "3AbtU1JSaiQijyGT21stxpBRZj1hixWcGB", - "3KfgmLeczB525pV2tJLQ6RM5qFMLaB2Kn1", - "3Bsr5dvAJ2Q8CpHxJSZkNdgD12Tkb9TaR7", - "3J78iYD4i4ht8Btp8pyRx71jg5yrRTkQaM", - "3EGxduodZm6a9FLN1jdVxN8pT5orCmFdUK", - "3DWvzGWYJCY19Gc4LcN8noHGpxdjRbJeYe", - "3Aw9ePtWrH8EEJoF5HW8swW9VXxpF4dP54", - "3QTQE5rt7TZg7hXZ4DsTQ6mUUZCbFY2RiL", - "3EoWFm3GcTzDFBQ9KGVevhH1nuSxa14eFM" - ], - "legacyTestnetP2PKH": [ - "mhTg9sgNgvAGfmJs192oUzQWqAXHH5nqLE", - "mmpjQ24UyGGfJ39k44prH6W2A7y1qVaQti", - "muEnSveRwu8cEJSvXzDTJZQWrr7y9i331i", - "n3jZn7rb3Bjepap4TWo8pyqcwuxAw439HW", - "mqHUen3SUNjQkAPjMxZfSnuyd8cmcbL6fq", - "n4g3swxSebC9cDHXTjYQcx3tRAe4EPrZrZ", - "n2yNUahmfBFLLzrpcXpMh8Votw7zbKVHtX", - "mqYM6bu8Vw6xFTTPhbtxWPPmFN8BwpVQeE", - "mrVbyCMyB3vhDya4rYSxdM8qivEGfn7JSP", - "mnqGaf1SbPFh1tdXdeXd7pWhJUY2ite6SY" - ], - "cashaddrMainnetP2PKH": [ - "bitcoincash:qptnmya5wkly7xf97wm5ak23yqdsz3l2cyj7k9vyyh", - "bitcoincash:qrr2suh9yjsrkl2qp3p967uhfg6u0r6xxsn9h5vuvr", - "bitcoincash:qpkfg4kck99wksyss6nvaqtafeahfnyrpsj0ed372t", - "bitcoincash:qppgmuuwy07g0x39sx2z0x2u8e34tvfdxvy0c2jvx7", - "bitcoincash:qryj8x4s7vfsc864jm0xaak9qfe8qgk245y9ska57l", - "bitcoincash:qqxdgs9x9rx4v7g4ea5kxyprj2k9wnv695578lwmt8", - "bitcoincash:qrcugfh4prxzl8qzqazyth7ytuc6k4qqcg50etp609", - "bitcoincash:qq32y2h0ljtyyv4xkk07gtyrclv2xwq5sq3pqrzjes", - "bitcoincash:qrxwdlhfx5f4xsfnl0g887e5ccs5puy8sgj0z0md6k", - "bitcoincash:qz595e7jwa3q4vw26whn6zcz6x074669lgnnvjkz5m" - ], - "cashaddrMainnetP2SH": [ - "bitcoincash:pp7ushdxf5we8mcpaa3wqgsuqt639cu59ur5xu5fug", - "bitcoincash:ppsup5akyvql5w46q9eszd9fxpx970acpyqkw79vq2", - "bitcoincash:prznrkhnf6zqsap6l664ayzu2xue67ue4gv686sjyu", - "bitcoincash:pphmm80pznl6pnkmzakz3ahafydmvhwzcslea4v5mz", - "bitcoincash:pz6pr25g6mulp0kes9xnmsda0u4rf442ase2un89pl", - "bitcoincash:pz9qe6ys8x0l98zegf0a9rae4zenk95yp5dv5xjnk5", - "bitcoincash:pzqmjwk8929jtqt7ac7szjuawtswmxhtu5xxm64upf", - "bitcoincash:ppjk2e4nz47n50hpg8z6nt5hfjeajy4cyyp0p2tvnp", - "bitcoincash:prum0t7tqczlyaw2d30tmpj3je9q2xlzwcqk9wx83u", - "bitcoincash:pz8a837lttkvjksg0jjmmulqvfkgpqrcdgufy8ns5s" - ], - "cashaddrTestnetP2PKH": [ - "bchtest:qq24rpar9qas3vc9r8d4p0prhwaf7jmx2u22nzt946", - "bchtest:qpzj67wmlsq8uttddddapjjawyusureca59ug9cak8", - "bchtest:qztg9c4u3ldhg68mqgzrple6ae92hwnfe5m6kyejfd", - "bchtest:qrem2cg43ksmvlampheur8gfgdhhk57mygy26y7f2e", - "bchtest:qp4jf3n740kffkladul96xnq5dtrflg4x5w5rfy22r", - "bchtest:qrlqxnzuu6hvvg9qer0m093ywkjnu7wm7ypj7unqzc", - "bchtest:qr44nfr9egxt7h7lxdktf9kajds9fwdxxcved7827j", - "bchtest:qpklfd26u70ta4j7p4twxv2k5apx95p0qqgm8cf2sd", - "bchtest:qpuxsqzgq3j0a58tnmwpgcrwwyrkenalevaeknklfg", - "bchtest:qpgrlg0yqmdf4y8q980e57tx6v7vrvds2ug89n8w8q" - ], - "mainnetXPub": [ - { - "xpub": "xpub6CVcpZVmPNjuniVYu1mLnLjDBfxWpx7LS25uxwRm5BLbXMCJmRaQgAxuqZDoYDeidJUh5QUatLJPWpeCkEK648hExyKFezqxJz4CMfEoYAc", - "addresses": [ - "bitcoincash:qp3c2e0ehq5lqgnf2v8kqk0qemkatnknmga3mwqkms", - "bitcoincash:qznkqj05zsx8uszyjfdyvfn55ecwltfsrq93jhwchv", - "bitcoincash:qpkvr2gs84g6nltzcs9d9ef7qerh7qqenca2zddlpz", - "bitcoincash:qpuchd6als5yc3fs55aktwylr20u0antyu5f99jt8k", - "bitcoincash:qq670p9knuarh75ae7er4c246w909nd0z5gx6h60vv" - ] - }, - { - "xpub": "xpub6CVcpZVmPNjuqYFnvSYoD9hE89PKmsWewFWGKeaCcVNSfDTgQgMuhm8Q2zreBsNQVMSJrBmQ3C95fi3SiRXYRQckQJMZuPXTJm9TcQejW13", - "addresses": [ - "bitcoincash:qqhkcs5fnchh99p68mcszcz68cecef5jfyeugnyysl", - "bitcoincash:qqxj4w8lgctdhpvl9um9w7tvgmc9se3ttcfkdfcv5e", - "bitcoincash:qp30m7fu27vljfqvqq26kwn8f4zp4g7wngqdzn40xh", - "bitcoincash:qrvtu7nw8x5343c9jgc5a58zw5vw3susful9x9yhrv", - "bitcoincash:qrjcyuxunxzt2w35ney2hzrvgynrcqg5qqj9366m6a" - ] - }, - { - "xpub": "xpub6CVcpZVmPNjuu1zjt9joxDzDrP9UNs6GVS5K1jSopnq76RBZswLsxy75qvJTVcSS6V9Y4Df6L7GDsbns99WrLrfmBNwocEdQm5CXFGExAgq", - "addresses": [ - "bitcoincash:qp3d5t96fdvjkurpt2h0t8nw5u4hr294q5q4dw6g9r", - "bitcoincash:qpusevag7l73543hs2lw69aqx4kzlsxamyg785mnsa", - "bitcoincash:qp48wzx62956wqux569mhm7dzyykya35aghd0y6qxf", - "bitcoincash:qqxd6u4lap7s9zcm8jdkd44uakyghcw8hqawurftc6", - "bitcoincash:qrn4gf9ufqp3ze4refp6yqh60s47crcwksqp20txs7" - ] - } - ], - "testnetXPub": [ - { - "xpub": "tpubDCrnMSKwDMAbxg82yqDt97peMvftCXk3EfBb9WgZh27mPbHGkysU3TW7qX5AwydmnVQfaGeNhUR6okQ3dS5AJTP9gEP7jk2Wcj6Xntc6gNh", - "addresses": [ - "bchtest:qrth8470sc9scek9u0jj2d0349t62gxzdstw2jukl8", - "bchtest:qpm56zc5re0nhms96r7p985aajthp0vxvg6e4ux3kc", - "bchtest:qqtu3tf6yyd73ejhk3a2ylqynpl3mzzhwuzt299jfd", - "bchtest:qzd7dvlnfukggjqsf5ju0qqwwltakfumjsck33js6m", - "bchtest:qq322ataqeas4n0pdn4gz2sdereh5ae43ylk4qdvus" - ] - }, - { - "xpub": "tpubDCrnMSKwDMAbzuN7eQDcFh9c6BsUvHHiL7j1AE9f9mE2ertgK6DwAZ6xmqtM3G5ifPkVynnjhMMMS87R1x4DTPrCbp4VjBttqMc4KmQEMRv", - "addresses": [ - "bchtest:qq2lnfskh8herq7hhj067uzfmhg2cf6arvc8eld50k", - "bchtest:qrjqt3vw8us9nc4d3h8j5fn6cxa0h5485ydd5zhq8y", - "bchtest:qze485w97jjhpucgk9dmh7h4fx56z8tmvgv4c3esmm", - "bchtest:qp6dvdwfu02z6d8cp6uqkpnjde66m89t9cexm00fmd", - "bchtest:qz266xueu99z6mh8af66gwnsv48jxva6aslmju2wat" - ] - }, - { - "xpub": "tpubDCrnMSKwDMAc4zKRDfxDqmzzxwLd85MFYF3cHzmdGDchnS7Sz2UiHD6HqaJR5Lefq6BhApPvGsdp3smjE1KRNkWHZ4wWogt7UYrgVznGfs1", - "addresses": [ - "bchtest:qqzkac72c0dygl92ru74zmwkkhdq7sc845n43ulmlw", - "bchtest:qzsm0ymr035a5eg0r8k4hxvyaxqyd0e8msd7f79v2z", - "bchtest:qqg6yea05gkqyxwdce6k5sjun8k9drgzn54d63cq5n", - "bchtest:qrfumvznl5ck903vq3sp3gfsrjt22tqa85lxzjv4p9", - "bchtest:qrd88na4869phkr0h44kzfakwc52w2jwmqjl6vlynn" - ] - } - ] -} diff --git a/test/integration/address.js b/test/integration/address.js new file mode 100644 index 00000000..74f70c9e --- /dev/null +++ b/test/integration/address.js @@ -0,0 +1,377 @@ +/* + Integration tests for the bitbox.Address library. Only covers calls made to + rest.bitcoin.com. + + TODO: + -Address.unconfirmed: + --Retrieves transient 0-conf UTXOs. Needs an E2E test to be effectively tested. +*/ + +const chai = require("chai") +const assert = chai.assert + +const BITBOX = require("../../lib/BITBOX").BITBOX +let bitbox = new BITBOX() + +if (process.env.SERVER === "local") + bitbox = new BITBOX({ restURL: "http://localhost:3000/v2/" }) +if (process.env.SERVER === "stage") + bitbox = new BITBOX({ restURL: "https://rest.btctest.net/v2/" }) +if (process.env.SERVER === "custom") + bitbox = new BITBOX({ restURL: process.env.SERVERIP }) + +// Inspect utility used for debugging. +const util = require("util") +util.inspect.defaultOptions = { + showHidden: true, + colors: true, + depth: 3 +} + +describe(`#address`, () => { + describe(`#details`, () => { + it(`should GET address details for a single address`, async () => { + const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf" + + const result = await bitbox.Address.details(addr) + //console.log(`result: ${util.inspect(result)}`) + + assert.hasAllKeys(result, [ + "balance", + "balanceSat", + "totalReceived", + "totalReceivedSat", + "totalSent", + "totalSentSat", + "unconfirmedBalance", + "unconfirmedBalanceSat", + "unconfirmedTxApperances", + "txApperances", + "transactions", + "legacyAddress", + "cashAddress", + "currentPage", + "pagesTotal", + "slpAddress" + ]) + assert.isArray(result.transactions) + }) + + it(`should GET address details for an array of addresses`, async () => { + const addr = [ + "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", + "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v" + ] + + const result = await bitbox.Address.details(addr) + //console.log(`result: ${util.inspect(result)}`) + + assert.isArray(result) + assert.hasAllKeys(result[0], [ + "balance", + "balanceSat", + "totalReceived", + "totalReceivedSat", + "totalSent", + "totalSentSat", + "unconfirmedBalance", + "unconfirmedBalanceSat", + "unconfirmedTxApperances", + "txApperances", + "transactions", + "legacyAddress", + "cashAddress", + "currentPage", + "pagesTotal", + "slpAddress" + ]) + assert.isArray(result[0].transactions) + }) + + it(`should throw an error for improper input`, async () => { + try { + const addr = 12345 + + await bitbox.Address.details(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input address must be a string or array of strings` + ) + } + }) + + it(`should throw error on array size rate limit`, async () => { + try { + const addr = [] + for (let i = 0; i < 25; i++) + addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf") + + const result = await bitbox.Address.details(addr) + + console.log(`result: ${util.inspect(result)}`) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, "Array too large") + } + }) + }) + + describe(`#utxo`, () => { + it(`should GET utxos for a single address`, async () => { + const addr = "bitcoincash:qzzn0zttjrt9jn6a7jfltl0s4270p5sulu5s7hkefw" + + const result = await bitbox.Address.utxo(addr) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, [ + "utxos", + "legacyAddress", + "cashAddress", + "scriptPubKey", + "slpAddress", + "asm" + ]) + assert.isArray(result.utxos) + assert.hasAnyKeys(result.utxos[0], [ + "txid", + "vout", + "amount", + "satoshis", + "height", + "confirmations" + ]) + }) + + it(`should GET utxo details for an array of addresses`, async () => { + const addr = [ + "bitcoincash:qzzn0zttjrt9jn6a7jfltl0s4270p5sulu5s7hkefw", + "bitcoincash:qrxhw5lmetex26903t59u5ej694akepzqug8sfljrl" + ] + + const result = await bitbox.Address.utxo(addr) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.hasAllKeys(result[0], [ + "utxos", + "legacyAddress", + "cashAddress", + "scriptPubKey", + "slpAddress", + "asm" + ]) + assert.isArray(result[0].utxos) + assert.hasAnyKeys(result[0].utxos[0], [ + "txid", + "vout", + "amount", + "satoshis", + "height", + "confirmations" + ]) + }) + + it(`should throw an error for improper input`, async () => { + try { + const addr = 12345 + + await bitbox.Address.utxo(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input address must be a string or array of strings` + ) + } + }) + + it(`should throw error on array size rate limit`, async () => { + try { + const addr = [] + for (let i = 0; i < 25; i++) + addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf") + + const result = await bitbox.Address.utxo(addr) + + console.log(`result: ${util.inspect(result)}`) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, "Array too large") + } + }) + }) + + describe(`#unconfirmed`, () => { + it(`should GET unconfirmed details on a single address`, async () => { + const addr = "bitcoincash:qz7teqlcltdhqjn2an8nspu7g2x6g3d3rcq8nk4nzs" + + const result = await bitbox.Address.unconfirmed(addr) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, [ + "utxos", + "legacyAddress", + "cashAddress", + "scriptPubKey", + "slpAddress", + "asm" + ]) + assert.isArray(result.utxos) + }) + + it(`should GET unconfirmed details on multiple addresses`, async () => { + const addr = [ + "bitcoincash:qz7teqlcltdhqjn2an8nspu7g2x6g3d3rcq8nk4nzs", + "bitcoincash:qqcp8fw06dmjd2gnfanpwytj7q93w408nv7usdqgsk" + ] + + const result = await bitbox.Address.unconfirmed(addr) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.hasAllKeys(result[0], [ + "utxos", + "legacyAddress", + "cashAddress", + "scriptPubKey", + "slpAddress", + "asm" + ]) + assert.isArray(result[0].utxos) + }) + + it(`should throw an error for improper input`, async () => { + try { + const addr = 12345 + + await bitbox.Address.unconfirmed(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input address must be a string or array of strings` + ) + } + }) + + it(`should throw error on array size rate limit`, async () => { + try { + const addr = [] + for (let i = 0; i < 25; i++) + addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf") + + const result = await bitbox.Address.unconfirmed(addr) + + console.log(`result: ${util.inspect(result)}`) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, "Array too large") + } + }) + }) + + describe(`#transactions`, () => { + it(`should GET transactions for a single address`, async () => { + const addr = "bitcoincash:qz7teqlcltdhqjn2an8nspu7g2x6g3d3rcq8nk4nzs" + + const result = await bitbox.Address.transactions(addr) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, [ + "txs", + "pagesTotal", + "cashAddress", + "currentPage", + "legacyAddress" + ]) + assert.isArray(result.txs) + assert.hasAnyKeys(result.txs[0], [ + "txid", + "version", + "locktime", + "vin", + "vout", + "confirmations", + "time", + "blocktime", + "valueOut", + "size", + "valueIn", + "fees" + ]) + }) + + it(`should get transactions on multiple addresses`, async () => { + const addr = [ + "bitcoincash:qz7teqlcltdhqjn2an8nspu7g2x6g3d3rcq8nk4nzs", + "bitcoincash:qqcp8fw06dmjd2gnfanpwytj7q93w408nv7usdqgsk" + ] + + const result = await bitbox.Address.transactions(addr) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.hasAllKeys(result[0], [ + "txs", + "pagesTotal", + "cashAddress", + "currentPage", + "legacyAddress" + ]) + assert.isArray(result[0].txs) + assert.hasAnyKeys(result[0].txs[0], [ + "txid", + "version", + "locktime", + "vin", + "vout", + "confirmations", + "time", + "blocktime", + "valueOut", + "size", + "valueIn", + "fees" + ]) + }) + + it(`should throw an error for improper input`, async () => { + try { + const addr = 12345 + + await bitbox.Address.transactions(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input address must be a string or array of strings` + ) + } + }) + + it(`should throw error on array size rate limit`, async () => { + try { + const addr = [] + for (let i = 0; i < 25; i++) + addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf") + + const result = await bitbox.Address.transactions(addr) + + console.log(`result: ${util.inspect(result)}`) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, "Array too large") + } + }) + }) +}) diff --git a/test/integration/block.js b/test/integration/block.js new file mode 100644 index 00000000..6f60225a --- /dev/null +++ b/test/integration/block.js @@ -0,0 +1,209 @@ +/* + Integration tests for the bitbox. Only covers calls made to + rest.bitcoin.com. +*/ + +const chai = require("chai") +const assert = chai.assert + +const BITBOX = require("../../lib/BITBOX").BITBOX +let bitbox = new BITBOX() + +if (process.env.SERVER === "local") + bitbox = new BITBOX({ restURL: "http://localhost:3000/v2/" }) +if (process.env.SERVER === "stage") + bitbox = new BITBOX({ restURL: "https://rest.btctest.net/v2/" }) +if (process.env.SERVER === "custom") + bitbox = new BITBOX({ restURL: process.env.SERVERIP }) + +// Inspect utility used for debugging. +const util = require("util") +util.inspect.defaultOptions = { + showHidden: true, + colors: true, + depth: 3 +} + +describe(`#block`, () => { + describe(`#detailsByHeight`, () => { + it(`should GET block details for a given Height`, async () => { + const block = 500000 + + const result = await bitbox.Block.detailsByHeight(block) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, [ + "hash", + "size", + "height", + "version", + "merkleroot", + "tx", + "time", + "nonce", + "bits", + "difficulty", + "chainwork", + "confirmations", + "previousblockhash", + "nextblockhash", + "reward", + "isMainChain", + "poolInfo" + ]) + }) + + it(`should GET block details for an array of blocks`, async () => { + const blocks = [500000, 500001] + + const result = await bitbox.Block.detailsByHeight(blocks) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.hasAllKeys(result[0], [ + "hash", + "size", + "height", + "version", + "merkleroot", + "tx", + "time", + "nonce", + "bits", + "difficulty", + "chainwork", + "confirmations", + "previousblockhash", + "nextblockhash", + "reward", + "isMainChain", + "poolInfo" + ]) + }) + + it(`should throw an error for improper single input`, async () => { + try { + const blocks = "asdf" + + await bitbox.Block.detailsByHeight(blocks) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input must be a number or array of numbers.` + ) + } + }) + + it(`should throw error on array size rate limit`, async () => { + try { + const blocks = [] + for (let i = 0; i < 25; i++) blocks.push(500000) + + const result = await bitbox.Block.detailsByHeight(blocks) + + console.log(`result: ${util.inspect(result)}`) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, "Array too large") + } + }) + }) + + describe("#detailsByHash", () => { + it(`should GET block details for a given hash`, async () => { + const hash = + "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201" + + const result = await bitbox.Block.detailsByHash(hash) + //console.log(`result: ${util.inspect(result)}`) + + assert.hasAllKeys(result, [ + "hash", + "size", + "height", + "version", + "merkleroot", + "tx", + "time", + "nonce", + "bits", + "difficulty", + "chainwork", + "confirmations", + "previousblockhash", + "nextblockhash", + "reward", + "isMainChain", + "poolInfo" + ]) + }) + + it(`should GET block details for an array of hashes`, async () => { + const hash = [ + "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201", + "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201" + ] + + const result = await bitbox.Block.detailsByHash(hash) + //console.log(`result: ${util.inspect(result)}`) + + assert.isArray(result) + assert.hasAllKeys(result[0], [ + "hash", + "size", + "height", + "version", + "merkleroot", + "tx", + "time", + "nonce", + "bits", + "difficulty", + "chainwork", + "confirmations", + "previousblockhash", + "nextblockhash", + "reward", + "isMainChain", + "poolInfo" + ]) + }) + + it(`should throw an error for improper single input`, async () => { + try { + const hash = 12345 + + await bitbox.Block.detailsByHash(hash) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input must be a string or array of strings` + ) + } + }) + + it(`should throw error on array size rate limit`, async () => { + try { + const data = [] + for (let i = 0; i < 25; i++) { + data.push( + "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201" + ) + } + + const result = await bitbox.Block.detailsByHash(data) + + console.log(`result: ${util.inspect(result)}`) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, "Array too large") + } + }) + }) +}) diff --git a/test/integration/blockchain.js b/test/integration/blockchain.js new file mode 100644 index 00000000..9735f596 --- /dev/null +++ b/test/integration/blockchain.js @@ -0,0 +1,340 @@ +/* + Integration tests for the bitbox. Only covers calls made to + rest.bitcoin.com. + + TODO + - getMempoolEntry() only works on TXs in the mempool, so it needs to be part + of an e2e test to be properly tested. +*/ + +const chai = require("chai") +const assert = chai.assert + +const BITBOX = require("../../lib/BITBOX").BITBOX +let bitbox = new BITBOX() + +if (process.env.SERVER === "local") + bitbox = new BITBOX({ restURL: "http://localhost:3000/v2/" }) +if (process.env.SERVER === "stage") + bitbox = new BITBOX({ restURL: "https://rest.btctest.net/v2/" }) +if (process.env.SERVER === "custom") + bitbox = new BITBOX({ restURL: process.env.SERVERIP }) + +// Inspect utility used for debugging. +const util = require("util") +util.inspect.defaultOptions = { + showHidden: true, + colors: true, + depth: 3 +} + +describe(`#blockchain`, () => { + describe(`#getBestBlockHash`, () => { + it(`should GET best block hash`, async () => { + const result = await bitbox.Blockchain.getBestBlockHash() + //console.log(`result: ${util.inspect(result)}`) + + assert.isString(result) + assert.equal(result.length, 64, "Specific hash length") + }) + }) + + describe("#getBlockHeader", () => { + it(`should GET block header for a single hash`, async () => { + const hash = + "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201" + + const result = await bitbox.Blockchain.getBlockHeader(hash) + + assert.hasAllKeys(result, [ + "hash", + "confirmations", + "height", + "version", + "versionHex", + "merkleroot", + "time", + "mediantime", + "nonce", + "bits", + "difficulty", + "chainwork", + "previousblockhash", + "nextblockhash" + ]) + }) + + it(`should GET block headers for an array of hashes`, async () => { + const hash = [ + "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201", + "00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3" + ] + + const result = await bitbox.Blockchain.getBlockHeader(hash) + + assert.isArray(result) + assert.hasAllKeys(result[0], [ + "hash", + "confirmations", + "height", + "version", + "versionHex", + "merkleroot", + "time", + "mediantime", + "nonce", + "bits", + "difficulty", + "chainwork", + "previousblockhash", + "nextblockhash" + ]) + }) + + it(`should throw an error for improper input`, async () => { + try { + const hash = 12345 + + await bitbox.Blockchain.getBlockHeader(hash) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.include( + err.message, + `Input hash must be a string or array of strings` + ) + } + }) + + it(`should throw error on array size rate limit`, async () => { + try { + const data = [] + for (let i = 0; i < 25; i++) { + data.push( + "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201" + ) + } + + const result = await bitbox.Blockchain.getBlockHeader(data) + + console.log(`result: ${util.inspect(result)}`) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, "Array too large") + } + }) + }) + + describe("#getMempoolEntry", () => { + /* + // To run this test, the txid must be unconfirmed. + const txid = + "defea04c38ee00cf73ad402984714ed22dc0dd99b2ae5cb50d791d94343ba79b" + + it(`should GET single mempool entry`, async () => { + const result = await bitbox.Blockchain.getMempoolEntry(txid) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAnyKeys(result, [ + "size", + "fee", + "modifiedfee", + "time", + "height", + "startingpriority", + "currentpriority", + "descendantcount", + "descendantsize", + "descendantfees", + "ancestorcount", + "ancestorsize", + "ancestorfees", + "depends" + ]) + }) + + it(`should get an array of mempool entries`, async () => { + const result = await bitbox.Blockchain.getMempoolEntry([txid, txid]) + console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.hasAnyKeys(result[0], [ + "size", + "fee", + "modifiedfee", + "time", + "height", + "startingpriority", + "currentpriority", + "descendantcount", + "descendantsize", + "descendantfees", + "ancestorcount", + "ancestorsize", + "ancestorfees", + "depends" + ]) + }) + */ + + it(`should throw an error if txid is not in mempool`, async () => { + try { + const txid = + "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7" + + await bitbox.Blockchain.getMempoolEntry(txid) + + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: ${util.inspect(err)}`) + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, `Transaction not in mempool`) + } + }) + + it(`should throw an error for improper single input`, async () => { + try { + const txid = 12345 + + await bitbox.Blockchain.getMempoolEntry(txid) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.include( + err.message, + `Input must be a string or array of strings` + ) + } + }) + }) + + describe(`#getTxOut`, () => { + it(`should get information on valid utxo`, async () => { + const txid = `91874bf385a36d54f06c2154b34bce887a03b99540bfddaa17ac78ebc65202d0` + + const result = await bitbox.Blockchain.getTxOut(txid, 0, true) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, [ + "bestblock", + "confirmations", + "value", + "scriptPubKey", + "coinbase" + ]) + assert.hasAllKeys(result.scriptPubKey, [ + "asm", + "hex", + "reqSigs", + "type", + "addresses" + ]) + }) + + it(`should return null for a spent utxo`, async () => { + const txid = `8db6dd4f8a5bb1308541d4a6d4ecdae6c65426679e79f783638ce32b2fb0725b` + + const result = await bitbox.Blockchain.getTxOut(txid, 0, true) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.equal(result, null) + }) + }) + + describe(`#getTxOutProof`, () => { + it(`should get single tx out proof`, async () => { + const txid = + "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7" + + const result = await bitbox.Blockchain.getTxOutProof(txid) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isString(result) + }) + + it(`should get an array of tx out proofs`, async () => { + const txid = [ + "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7", + "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33" + ] + + const result = await bitbox.Blockchain.getTxOutProof(txid) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.isString(result[0]) + }) + + it(`should throw an error for improper single input`, async () => { + try { + const txid = 12345 + + await bitbox.Blockchain.getTxOutProof(txid) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.include( + err.message, + `Input must be a string or array of strings` + ) + } + }) + }) + + describe(`#verifyTxOutProof`, () => { + const mockTxOutProof = + "0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01" + + it(`should verify a single proof`, async () => { + const result = await bitbox.Blockchain.verifyTxOutProof(mockTxOutProof) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.isString(result[0]) + assert.equal( + result[0], + "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7" + ) + }) + + it(`should verify an array of proofs`, async () => { + const proofs = [mockTxOutProof, mockTxOutProof] + const result = await bitbox.Blockchain.verifyTxOutProof(proofs) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.isString(result[0]) + assert.equal( + result[0], + "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7" + ) + }) + + it(`should throw an error for improper single input`, async () => { + try { + const txid = 12345 + + await bitbox.Blockchain.verifyTxOutProof(txid) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.include( + err.message, + `Input must be a string or array of strings` + ) + } + }) + + it(`should throw error on array size rate limit`, async () => { + try { + const data = [] + for (let i = 0; i < 25; i++) data.push(mockTxOutProof) + + const result = await bitbox.Blockchain.verifyTxOutProof(data) + + console.log(`result: ${util.inspect(result)}`) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, "Array too large") + } + }) + }) +}) diff --git a/test/integration/control.js b/test/integration/control.js new file mode 100644 index 00000000..000deada --- /dev/null +++ b/test/integration/control.js @@ -0,0 +1,35 @@ +const chai = require("chai") +const assert = chai.assert +const BITBOX = require("../../lib/BITBOX").BITBOX +let bitbox = new BITBOX() + +if (process.env.SERVER === "local") + bitbox = new BITBOX({ restURL: "http://localhost:3000/v2/" }) +if (process.env.SERVER === "stage") + bitbox = new BITBOX({ restURL: "https://rest.btctest.net/v2/" }) +if (process.env.SERVER === "custom") + bitbox = new BITBOX({ restURL: process.env.SERVERIP }) + +describe("#control", () => { + describe("#getNetworkInfo", () => { + it("should GET getNetworkInfo data", async () => { + const result = await bitbox.Control.getNetworkInfo() + //console.log(`getNetworkInfo: ${JSON.stringify(result, null, 2)}`) + + assert.hasAnyKeys(result, [ + "version", + "subversion", + "protocolversion", + "localservices", + "localrelay", + "timeoffset", + "networkactive", + "connections", + "networks", + "relayfee", + "excessutxocharge", + "warnings" + ]) + }) + }) +}) diff --git a/test/integration/other/README.md b/test/integration/other/README.md new file mode 100644 index 00000000..5c8068af --- /dev/null +++ b/test/integration/other/README.md @@ -0,0 +1,8 @@ +# Other Integration Tests + +This directory holds stand-alone integration tests that should not be part of +the integration test suite. + +An example of a test that fits this criteria are rate limit tests. Rate limit +tests are complex, require a solid internet connection, and can easily disrupt +other tests. For those reasons, it is better to run them on their own. diff --git a/test/integration/price.js b/test/integration/price.js new file mode 100644 index 00000000..7a10d058 --- /dev/null +++ b/test/integration/price.js @@ -0,0 +1,21 @@ +const assert = require("assert") +const BITBOX = require("../../lib/BITBOX").BITBOX +let bitbox = new BITBOX() + +if (process.env.SERVER === "local") + bitbox = new BITBOX({ restURL: "http://localhost:3000/v2/" }) +if (process.env.SERVER === "stage") + bitbox = new BITBOX({ restURL: "https://rest.btctest.net/v2/" }) +if (process.env.SERVER === "custom") + bitbox = new BITBOX({ restURL: process.env.SERVERIP }) + +describe("#price", () => { + describe("#current", () => { + describe("#single currency", () => { + it("should get current price for single currency", async () => { + const result = await bitbox.Price.current("usd") + assert.notEqual(0, result) + }) + }) + }) +}) diff --git a/test/integration/rawtransaction.js b/test/integration/rawtransaction.js new file mode 100644 index 00000000..83c6cb20 --- /dev/null +++ b/test/integration/rawtransaction.js @@ -0,0 +1,335 @@ +/* + Integration tests for the bitbox. Only covers calls made to + rest.bitcoin.com. + + TODO +*/ + +const chai = require("chai") +const assert = chai.assert + +const BITBOX = require("../../lib/BITBOX").BITBOX +let bitbox = new BITBOX() + +if (process.env.SERVER === "local") + bitbox = new BITBOX({ restURL: "http://localhost:3000/v2/" }) +if (process.env.SERVER === "stage") + bitbox = new BITBOX({ restURL: "https://rest.btctest.net/v2/" }) +if (process.env.SERVER === "custom") + bitbox = new BITBOX({ restURL: process.env.SERVERIP }) + +// Inspect utility used for debugging. +const util = require("util") +util.inspect.defaultOptions = { + showHidden: true, + colors: true, + depth: 3 +} + +describe("#rawtransaction", () => { + describe("#decodeRawTransaction", () => { + it("should decode tx for a single hex", async () => { + const hex = + "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000" + + const result = await bitbox.RawTransactions.decodeRawTransaction(hex) + //console.log(`result ${JSON.stringify(result, null, 2)}`) + + assert.hasAnyKeys(result, [ + "txid", + "hash", + "size", + "version", + "locktime", + "vin", + "vout" + ]) + assert.isArray(result.vin) + assert.isArray(result.vout) + }) + + it("should decode an array of tx hexes", async () => { + const hexes = [ + "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000", + "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000" + ] + + const result = await bitbox.RawTransactions.decodeRawTransaction(hexes) + //console.log(`result ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.hasAnyKeys(result[0], [ + "txid", + "hash", + "size", + "version", + "locktime", + "vin", + "vout" + ]) + assert.isArray(result[0].vin) + assert.isArray(result[0].vout) + }) + + it(`should throw an error for improper single input`, async () => { + try { + const addr = 12345 + + await bitbox.RawTransactions.decodeRawTransaction(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input must be a string or array of strings.` + ) + } + }) + + it(`should throw error on array size rate limit`, async () => { + try { + const data = [] + for (let i = 0; i < 25; i++) { + data.push( + "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000" + ) + } + + const result = await bitbox.RawTransactions.decodeRawTransaction(data) + + console.log(`result: ${util.inspect(result)}`) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, "Array too large") + } + }) + }) + + describe("#getRawTransaction", () => { + it("should decode a single txid, with concise output", async () => { + const txid = + "23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1" + const verbose = false + + const result = await bitbox.RawTransactions.getRawTransaction( + txid, + verbose + ) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isString(result) + }) + + it("should decode a single txid, with verbose output", async () => { + const txid = + "23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1" + const verbose = true + + const result = await bitbox.RawTransactions.getRawTransaction( + txid, + verbose + ) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAnyKeys(result, [ + "hex", + "txid", + "hash", + "size", + "version", + "locktime", + "vin", + "vout", + "blockhash", + "confirmations", + "time", + "blocktime" + ]) + assert.isArray(result.vin) + assert.isArray(result.vout) + }) + + it("should decode an array of txids, with a concise output", async () => { + const txid = [ + "23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1", + "b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f" + ] + const verbose = false + + const result = await bitbox.RawTransactions.getRawTransaction( + txid, + verbose + ) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.isString(result[0]) + }) + + it("should decode an array of txids, with a verbose output", async () => { + const txid = [ + "23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1", + "b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f" + ] + const verbose = true + + const result = await bitbox.RawTransactions.getRawTransaction( + txid, + verbose + ) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.hasAnyKeys(result[0], [ + "hex", + "txid", + "hash", + "size", + "version", + "locktime", + "vin", + "vout", + "blockhash", + "confirmations", + "time", + "blocktime" + ]) + assert.isArray(result[0].vin) + assert.isArray(result[0].vout) + }) + + it(`should throw error on array size rate limit`, async () => { + try { + const dataMock = + "23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1" + const data = [] + for (let i = 0; i < 25; i++) data.push(dataMock) + + const result = await bitbox.RawTransactions.getRawTransaction(data) + + console.log(`result: ${util.inspect(result)}`) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, "Array too large") + } + }) + }) + + describe("#decodeScript", () => { + it("should decode script for a single hex", async () => { + const hex = + "4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16" + + const result = await bitbox.RawTransactions.decodeScript(hex) + //console.log(`result ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, ["asm", "type", "p2sh"]) + }) + + // CT 2/20/19 - Waiting for this PR to be merged complete the test: + // https://github.com/Bitcoin-com/rest.bitcoin.com/pull/312 + /* + it("should decode an array of tx hexes", async () => { + const hexes = [ + "4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16", + "4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16" + ] + + const result = await bitbox.RawTransactions.decodeScript(hexes) + console.log(`result ${JSON.stringify(result, null, 2)}`) + }) +*/ + /* + it(`should throw an error for improper single input`, async () => { + try { + const addr = 12345 + + await bitbox.RawTransactions.decodeRawTransaction(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input must be a string or array of strings.` + ) + } + }) +*/ + }) + + /* + Testing sentRawTransaction isn't really possible with an integration test, + as the endpoint really needs an e2e test to be properly tested. The tests + below expect error messages returned from the server, but at least test + that the server is responding on those endpoints, and responds consistently. + */ + describe("sendRawTransaction", () => { + it("should send a single transaction hex", async () => { + try { + const hex = + "01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000" + + await bitbox.RawTransactions.sendRawTransaction(hex) + //console.log(`result ${JSON.stringify(result, null, 2)}`) + + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: ${util.inspect(err)}`) + + assert.hasAllKeys(err, ["error"]) + assert.include(err.error, "Missing inputs") + } + }) + + it("should send an array of tx hexes", async () => { + try { + const hexes = [ + "01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000", + "01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000" + ] + + const result = await bitbox.RawTransactions.sendRawTransaction(hexes) + console.log(`result ${JSON.stringify(result, null, 2)}`) + } catch (err) { + // console.log(`err: ${util.inspect(err)}`) + + assert.hasAllKeys(err, ["error"]) + assert.include(err.error, "Missing inputs") + } + }) + + it(`should throw an error for improper single input`, async () => { + try { + const addr = 12345 + + await bitbox.RawTransactions.sendRawTransaction(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input hex must be a string or array of strings` + ) + } + }) + + it(`should throw error on array size rate limit`, async () => { + try { + const dataMock = + "01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000" + const data = [] + for (let i = 0; i < 25; i++) data.push(dataMock) + + const result = await bitbox.RawTransactions.sendRawTransaction(data) + + console.log(`result: ${util.inspect(result)}`) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, "Array too large") + } + }) + }) +}) diff --git a/test/integration/transaction.js b/test/integration/transaction.js new file mode 100644 index 00000000..71936d4f --- /dev/null +++ b/test/integration/transaction.js @@ -0,0 +1,99 @@ +/* + Integration tests for the bitbox. Only covers calls made to + rest.bitcoin.com. +*/ + +const chai = require("chai") +const assert = chai.assert + +const BITBOX = require("../../lib/BITBOX").BITBOX +let bitbox = new BITBOX() + +if (process.env.SERVER === "local") + bitbox = new BITBOX({ restURL: "http://localhost:3000/v2/" }) +if (process.env.SERVER === "stage") + bitbox = new BITBOX({ restURL: "https://rest.btctest.net/v2/" }) +if (process.env.SERVER === "custom") + bitbox = new BITBOX({ restURL: process.env.SERVERIP }) + +// Inspect utility used for debugging. +const util = require("util") +util.inspect.defaultOptions = { + showHidden: true, + colors: true, + depth: 3 +} + +describe(`#Transaction`, () => { + describe(`#details`, () => { + it(`should GET details for a given txid`, async () => { + const txid = + "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33" + + const result = await bitbox.Transaction.details(txid) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, [ + "txid", + "version", + "locktime", + "vin", + "vout", + "blockhash", + "blockheight", + "confirmations", + "time", + "blocktime", + "isCoinBase", + "valueOut", + "size" + ]) + }) + + it(`should GET details for an array of txids`, async () => { + const txids = [ + "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33", + "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33" + ] + + const result = await bitbox.Transaction.details(txids) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + }) + + it(`should throw an error for improper single input`, async () => { + try { + const txid = 12345 + + await bitbox.Transaction.details(txid) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input txid must be a string or array of strings` + ) + } + }) + + it(`should throw error on array size rate limit`, async () => { + try { + const dataMock = + "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33" + const data = [] + for (let i = 0; i < 25; i++) data.push(dataMock) + + const result = await bitbox.Transaction.details(data) + + // console.log(`result: ${util.inspect(result)}`) + assert.equal(false, false, "Unexpected result!") + } catch (err) { + // console.log(`err: ${util.inspect(err)}`) + + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, "Array too large") + } + }) + }) +}) diff --git a/test/integration/util.js b/test/integration/util.js new file mode 100644 index 00000000..3ba6a568 --- /dev/null +++ b/test/integration/util.js @@ -0,0 +1,113 @@ +/* + Integration tests for the bitbox. Only covers calls made to + rest.bitcoin.com. +*/ + +const chai = require("chai") +const assert = chai.assert + +const BITBOX = require("../../lib/BITBOX").BITBOX +let bitbox = new BITBOX() + +if (process.env.SERVER === "local") + bitbox = new BITBOX({ restURL: "http://localhost:3000/v2/" }) +if (process.env.SERVER === "stage") + bitbox = new BITBOX({ restURL: "https://rest.btctest.net/v2/" }) +if (process.env.SERVER === "custom") + bitbox = new BITBOX({ restURL: process.env.SERVERIP }) + +// Inspect utility used for debugging. +const util = require("util") +util.inspect.defaultOptions = { + showHidden: true, + colors: true, + depth: 3 +} + +describe(`#util`, () => { + describe(`#validateAddress`, () => { + it(`should return false for testnet addr on mainnet`, async () => { + const address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y` + + const result = await bitbox.Util.validateAddress(address) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, ["isvalid"]) + assert.equal(result.isvalid, false) + }) + + it(`should return false for bad address`, async () => { + const address = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peu` + + const result = await bitbox.Util.validateAddress(address) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, ["isvalid"]) + assert.equal(result.isvalid, false) + }) + + it(`should return a valid address`, async () => { + const address = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z` + + const result = await bitbox.Util.validateAddress(address) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, [ + "isvalid", + "address", + "scriptPubKey", + "isscript" + ]) + assert.equal(result.isvalid, true) + }) + + it(`should validate an array of addresses`, async () => { + const address = [ + `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`, + `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z` + ] + + const result = await bitbox.Util.validateAddress(address) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.hasAllKeys(result[0], [ + "isvalid", + "address", + "scriptPubKey", + "isscript" + ]) + }) + + it(`should throw an error for improper single input`, async () => { + try { + const address = 15432 + + await bitbox.Util.validateAddress(address) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input must be a string or array of strings.` + ) + } + }) + + it(`should throw error on array size rate limit`, async () => { + try { + const dataMock = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z` + const data = [] + for (let i = 0; i < 25; i++) data.push(dataMock) + + const result = await bitbox.Util.validateAddress(data) + + console.log(`result: ${util.inspect(result)}`) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, "Array too large") + } + }) + }) +}) diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 00000000..db8d849a --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1,4 @@ +--require ts-node/register/transpile-only +--require source-map-support/register +--recursivee +test/unit/**/*.ts \ No newline at end of file diff --git a/test/unit/Address.ts b/test/unit/Address.ts new file mode 100644 index 00000000..28ddd878 --- /dev/null +++ b/test/unit/Address.ts @@ -0,0 +1,1395 @@ +// imports +import { + AddressDetailsResult, + AddressUnconfirmedResult, + AddressUtxoResult +} from "bitcoin-com-rest" +import * as chai from "chai" +import { Address } from "../../lib/Address" +import { BITBOX, REST_URL } from "../../lib/BITBOX" + +import axios from "axios" + +// consts +const bitbox: BITBOX = new BITBOX() +const assert: Chai.AssertStatic = chai.assert + +// TODO: port from require to import syntax +const fixtures = require("./fixtures/Address.json") +const Bitcoin = require("@bitcoin-dot-com/bitcoincashjs2-lib") +const sinon = require("sinon") +const addressMock = require("./mocks/address-mock.js") + +function flatten(arrays: any) { + return [].concat.apply([], arrays) +} + +const XPUBS: any[] = flatten([fixtures.mainnetXPub, fixtures.testnetXPub]) +const XPRIVS: any[] = flatten([fixtures.mainnetXPriv, fixtures.testnetXPriv]) + +const LEGACY_ADDRESSES: string[] = flatten([ + fixtures.legacyMainnetP2PKH, + fixtures.legacyMainnetP2SH, + fixtures.legacyTestnetP2PKH, + fixtures.legacyTestnetP2SH +]) + +const mainnet_xpubs: string[] = [] +fixtures.mainnetXPub.forEach((f: any) => { + mainnet_xpubs.push(f.xpub) +}) +const MAINNET_ADDRESSES: string[] = flatten([ + mainnet_xpubs, + fixtures.legacyMainnetP2PKH, + fixtures.legacyMainnetP2SH, + fixtures.cashaddrMainnetP2PKH +]) + +const testnet_xpubs: string[] = [] +fixtures.testnetXPub.forEach((f: any) => { + testnet_xpubs.push(f.xpub) +}) +const TESTNET_ADDRESSES: string[] = flatten([ + testnet_xpubs, + fixtures.legacyTestnetP2PKH, + fixtures.cashaddrTestnetP2PKH +]) + +const CASHADDR_ADDRESSES: string[] = flatten([ + fixtures.cashaddrMainnetP2PKH, + fixtures.cashaddrMainnetP2SH, + fixtures.cashaddrTestnetP2PKH, + fixtures.cashaddrTestnetP2SH +]) + +const CASHADDR_ADDRESSES_NO_PREFIX: string[] = CASHADDR_ADDRESSES.map( + (address: string) => { + const parts: string[] = address.split(":") + return parts[1] + } +) + +const REGTEST_ADDRESSES: string[] = fixtures.cashaddrRegTestP2PKH + +const REGTEST_ADDRESSES_NO_PREFIX: string[] = REGTEST_ADDRESSES.map( + (address: string) => { + const parts: string[] = address.split(":") + return parts[1] + } +) + +const HASH160_HASHES: string[] = flatten([ + fixtures.hash160MainnetP2PKH, + fixtures.hash160MainnetP2SH, + fixtures.hash160TestnetP2PKH, + fixtures.hash160TestnetP2SH +]) + +const P2PKH_ADDRESSES: string[] = flatten([ + fixtures.legacyMainnetP2PKH, + fixtures.legacyTestnetP2PKH, + fixtures.cashaddrMainnetP2PKH, + fixtures.cashaddrTestnetP2PKH, + fixtures.cashaddrRegTestP2PKH +]) + +const P2SH_ADDRESSES: string[] = flatten([ + fixtures.legacyMainnetP2SH, + fixtures.cashaddrMainnetP2SH +]) +const util = require("util") +util.inspect.defaultOptions = { + showHidden: true, + colors: true, + depth: 3 +} + +describe("#Address", (): void => { + describe("#AddressConstructor", (): void => { + it("should create instance of Address", (): void => { + const address: Address = new Address() + assert.equal(address instanceof Address, true) + }) + + it("should have a restURL property", (): void => { + const address: Address = new Address() + assert.equal(address.restURL, REST_URL) + }) + }) + + describe("#addressConversion", (): void => { + describe("#toLegacyAddress", (): void => { + it("should translate legacy address format to itself correctly", (): void => { + assert.deepEqual( + LEGACY_ADDRESSES.map((address: string) => + bitbox.Address.toLegacyAddress(address) + ), + LEGACY_ADDRESSES + ) + }) + + it("should convert cashaddr address to legacy base58Check", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES.map((address: string) => + bitbox.Address.toLegacyAddress(address) + ), + LEGACY_ADDRESSES + ) + }) + + it("should convert cashaddr regtest address to legacy base58Check", (): void => { + assert.deepEqual( + REGTEST_ADDRESSES.map((address: string) => + bitbox.Address.toLegacyAddress(address) + ), + fixtures.legacyTestnetP2PKH + ) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.toLegacyAddress() + }, "") + assert.throws(() => { + bitbox.Address.toLegacyAddress("some invalid address") + }, "") + }) + }) + }) + + describe("#toCashAddress", (): void => { + it("should convert legacy base58Check address to cashaddr", (): void => { + assert.deepEqual( + LEGACY_ADDRESSES.map((address: string) => + bitbox.Address.toCashAddress(address, true) + ), + CASHADDR_ADDRESSES + ) + }) + + it("should convert legacy base58Check address to regtest cashaddr", (): void => { + assert.deepEqual( + fixtures.legacyTestnetP2PKH.map((address: string) => + bitbox.Address.toCashAddress(address, true, true) + ), + REGTEST_ADDRESSES + ) + }) + + it("should translate cashaddr address format to itself correctly", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES.map((address: string) => + bitbox.Address.toCashAddress(address, true) + ), + CASHADDR_ADDRESSES + ) + }) + + it("should translate regtest cashaddr address format to itself correctly", (): void => { + assert.deepEqual( + REGTEST_ADDRESSES.map((address: string) => + bitbox.Address.toCashAddress(address, true, true) + ), + REGTEST_ADDRESSES + ) + }) + + it("should translate no-prefix cashaddr address format to itself correctly", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.toCashAddress(address, true) + ), + CASHADDR_ADDRESSES + ) + }) + + it("should translate no-prefix regtest cashaddr address format to itself correctly", (): void => { + assert.deepEqual( + REGTEST_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.toCashAddress(address, true, true) + ), + REGTEST_ADDRESSES + ) + }) + + it("should translate cashaddr address format to itself of no-prefix correctly", (): void => { + CASHADDR_ADDRESSES.forEach((address: string) => { + const noPrefix = bitbox.Address.toCashAddress(address, false) + assert.equal(address.split(":")[1], noPrefix) + }) + }) + + it("should translate regtest cashaddr address format to itself of no-prefix correctly", (): void => { + REGTEST_ADDRESSES.forEach((address: string) => { + const noPrefix = bitbox.Address.toCashAddress(address, false, true) + assert.equal(address.split(":")[1], noPrefix) + }) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.toCashAddress() + }, "") + assert.throws(() => { + bitbox.Address.toCashAddress("some invalid address") + }, "") + }) + }) + }) + describe("#legacyToHash160", (): void => { + it("should convert legacy base58check address to hash160", (): void => { + assert.deepEqual( + LEGACY_ADDRESSES.map((address: string) => + bitbox.Address.legacyToHash160(address) + ), + HASH160_HASHES + ) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.legacyToHash160() + }, "") + assert.throws(() => { + bitbox.Address.legacyToHash160("some invalid address") + }, "") + }) + }) + }) + describe("#cashToHash160", (): void => { + it("should convert cashaddr address to hash160", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES.map((address: string) => + bitbox.Address.cashToHash160(address) + ), + HASH160_HASHES + ) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.cashToHash160() + }, "") + assert.throws(() => { + bitbox.Address.cashToHash160("some invalid address") + }, "") + }) + }) + }) + // describe("#regtestToHash160", () => { + // it("should convert regtest address to hash160", () => { + // assert.deepEqual( + // REGTEST_ADDRESSES.map((address: string) => + // bitbox.Address.regtestToHash160(address) + // ), + // fixtures.hash160TestnetP2PKH + // ) + // }) + // + // describe("errors", () => { + // it("should fail when called with an invalid address", () => { + // assert.throws(() => { + // bitbox.Address.regtestToHash160() + // }, '') + // assert.throws(() => { + // bitbox.Address.regtestToHash160("some invalid address") + // }, '') + // }) + // }) + // }) + describe("#fromHash160", (): void => { + it("should convert hash160 to mainnet P2PKH legacy base58check address", (): void => { + assert.deepEqual( + fixtures.hash160MainnetP2PKH.map((hash160: string) => + bitbox.Address.hash160ToLegacy(hash160) + ), + fixtures.legacyMainnetP2PKH + ) + }) + + it("should convert hash160 to mainnet P2SH legacy base58check address", (): void => { + assert.deepEqual( + fixtures.hash160MainnetP2SH.map((hash160: string) => + bitbox.Address.hash160ToLegacy( + hash160, + Bitcoin.networks.bitcoin.scriptHash + ) + ), + fixtures.legacyMainnetP2SH + ) + }) + + it("should convert hash160 to testnet P2PKH legacy base58check address", (): void => { + assert.deepEqual( + fixtures.hash160TestnetP2PKH.map((hash160: string) => + bitbox.Address.hash160ToLegacy( + hash160, + Bitcoin.networks.testnet.pubKeyHash + ) + ), + fixtures.legacyTestnetP2PKH + ) + }) + + it("should convert hash160 to mainnet P2PKH cash address", (): void => { + assert.deepEqual( + fixtures.hash160MainnetP2PKH.map((hash160: string) => + bitbox.Address.hash160ToCash(hash160) + ), + fixtures.cashaddrMainnetP2PKH + ) + }) + + it("should convert hash160 to mainnet P2SH cash address", (): void => { + assert.deepEqual( + fixtures.hash160MainnetP2SH.map((hash160: string) => + bitbox.Address.hash160ToCash( + hash160, + Bitcoin.networks.bitcoin.scriptHash + ) + ), + fixtures.cashaddrMainnetP2SH + ) + }) + + it("should convert hash160 to testnet P2PKH cash address", (): void => { + assert.deepEqual( + fixtures.hash160TestnetP2PKH.map((hash160: string) => + bitbox.Address.hash160ToCash( + hash160, + Bitcoin.networks.testnet.pubKeyHash + ) + ), + fixtures.cashaddrTestnetP2PKH + ) + }) + + it("should convert hash160 to regtest P2PKH cash address", (): void => { + assert.deepEqual( + fixtures.hash160TestnetP2PKH.map((hash160: string) => + bitbox.Address.hash160ToCash( + hash160, + Bitcoin.networks.testnet.pubKeyHash, + true + ) + ), + REGTEST_ADDRESSES + ) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.hash160ToLegacy() + }, "") + assert.throws(() => { + bitbox.Address.hash160ToLegacy("some invalid address") + }, "") + assert.throws(() => { + // @ts-ignore + bitbox.Address.hash160ToCash() + }, "") + assert.throws(() => { + bitbox.Address.hash160ToCash("some invalid address") + }, "") + }) + }) + }) + }) + + describe("address format detection", (): void => { + describe("#isLegacyAddress", (): void => { + describe("is legacy", (): void => { + LEGACY_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a legacy base58Check address`, (): void => { + const isBase58Check = bitbox.Address.isLegacyAddress(address) + assert.equal(isBase58Check, true) + }) + }) + }) + describe("is not legacy", (): void => { + CASHADDR_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a legacy address`, (): void => { + const isBase58Check = bitbox.Address.isLegacyAddress(address) + assert.equal(isBase58Check, false) + }) + }) + + REGTEST_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a legacy address`, (): void => { + const isBase58Check = bitbox.Address.isLegacyAddress(address) + assert.equal(isBase58Check, false) + }) + }) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.isLegacyAddress() + }, "") + assert.throws(() => { + bitbox.Address.isLegacyAddress("some invalid address") + }, "") + }) + }) + }) + + describe("#isCashAddress", (): void => { + describe("is cashaddr", (): void => { + CASHADDR_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a cashaddr address`, (): void => { + const isCashaddr = bitbox.Address.isCashAddress(address) + assert.equal(isCashaddr, true) + }) + }) + + REGTEST_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a cashaddr address`, (): void => { + const isCashaddr = bitbox.Address.isCashAddress(address) + assert.equal(isCashaddr, true) + }) + }) + }) + + describe("is not cashaddr", (): void => { + LEGACY_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a cashaddr address`, (): void => { + const isCashaddr = bitbox.Address.isCashAddress(address) + assert.equal(isCashaddr, false) + }) + }) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.isCashAddress() + }, "") + assert.throws(() => { + bitbox.Address.isCashAddress("some invalid address") + }, "") + }) + }) + }) + describe("#isHash160", (): void => { + describe("is hash160", (): void => { + HASH160_HASHES.forEach((address: string) => { + it(`should detect ${address} is a hash160 hash`, (): void => { + const isHash160 = bitbox.Address.isHash160(address) + assert.equal(isHash160, true) + }) + }) + }) + describe("is not hash160", (): void => { + LEGACY_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a hash160 hash`, (): void => { + const isHash160 = bitbox.Address.isHash160(address) + assert.equal(isHash160, false) + }) + }) + + CASHADDR_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a hash160 hash`, (): void => { + const isHash160 = bitbox.Address.isHash160(address) + assert.equal(isHash160, false) + }) + }) + + REGTEST_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a legacy address`, (): void => { + const isHash160 = bitbox.Address.isHash160(address) + assert.equal(isHash160, false) + }) + }) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.isHash160() + }, "") + assert.throws(() => { + bitbox.Address.isHash160("some invalid address") + }, "") + }) + }) + }) + }) + + describe("network detection", (): void => { + describe("#isMainnetAddress", (): void => { + describe("is mainnet", (): void => { + MAINNET_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a mainnet address`, (): void => { + const isMainnet = bitbox.Address.isMainnetAddress(address) + assert.equal(isMainnet, true) + }) + }) + }) + + describe("is not mainnet", (): void => { + TESTNET_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a mainnet address`, (): void => { + const isMainnet = bitbox.Address.isMainnetAddress(address) + assert.equal(isMainnet, false) + }) + }) + + REGTEST_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a mainnet address`, (): void => { + const isMainnet = bitbox.Address.isMainnetAddress(address) + assert.equal(isMainnet, false) + }) + }) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.isMainnetAddress() + }, "") + assert.throws(() => { + bitbox.Address.isMainnetAddress("some invalid address") + }, "") + }) + }) + }) + + describe("#isTestnetAddress", (): void => { + describe("is testnet", (): void => { + TESTNET_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a testnet address`, (): void => { + const isTestnet = bitbox.Address.isTestnetAddress(address) + assert.equal(isTestnet, true) + }) + }) + }) + + describe("is not testnet", (): void => { + MAINNET_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a testnet address`, (): void => { + const isTestnet = bitbox.Address.isTestnetAddress(address) + assert.equal(isTestnet, false) + }) + }) + + REGTEST_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a testnet address`, (): void => { + const isTestnet = bitbox.Address.isTestnetAddress(address) + assert.equal(isTestnet, false) + }) + }) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.isTestnetAddress() + }, "") + assert.throws(() => { + bitbox.Address.isTestnetAddress("some invalid address") + }, "") + }) + }) + }) + + describe("#isRegTestAddress", (): void => { + describe("is testnet", () => { + REGTEST_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a regtest address`, (): void => { + const isRegTest = bitbox.Address.isRegTestAddress(address) + assert.equal(isRegTest, true) + }) + }) + }) + + describe("is not testnet", (): void => { + MAINNET_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a regtest address`, (): void => { + const isRegTest = bitbox.Address.isRegTestAddress(address) + assert.equal(isRegTest, false) + }) + }) + + TESTNET_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a regtest address`, (): void => { + const isRegTest = bitbox.Address.isRegTestAddress(address) + assert.equal(isRegTest, false) + }) + }) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.isRegTestAddress() + }, "") + assert.throws(() => { + bitbox.Address.isRegTestAddress("some invalid address") + }, "") + }) + }) + }) + }) + + describe("address type detection", (): void => { + describe("#isP2PKHAddress", (): void => { + describe("is P2PKH", (): void => { + P2PKH_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a P2PKH address`, (): void => { + const isP2PKH = bitbox.Address.isP2PKHAddress(address) + assert.equal(isP2PKH, true) + }) + }) + }) + + describe("is not P2PKH", (): void => { + P2SH_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a P2PKH address`, (): void => { + const isP2PKH = bitbox.Address.isP2PKHAddress(address) + assert.equal(isP2PKH, false) + }) + }) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.isP2PKHAddress() + }, "") + assert.throws(() => { + bitbox.Address.isP2PKHAddress("some invalid address") + }, "") + }) + }) + }) + + describe("#isP2SHAddress", (): void => { + describe("is P2SH", (): void => { + P2SH_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a P2SH address`, (): void => { + const isP2SH = bitbox.Address.isP2SHAddress(address) + assert.equal(isP2SH, true) + }) + }) + }) + + describe("is not P2SH", (): void => { + P2PKH_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is not a P2SH address`, (): void => { + const isP2SH = bitbox.Address.isP2SHAddress(address) + assert.equal(isP2SH, false) + }) + }) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.isP2SHAddress() + }, "") + assert.throws(() => { + bitbox.Address.isP2SHAddress("some invalid address") + }, "") + }) + }) + }) + }) + + describe("cashaddr prefix detection", (): void => { + it("should return the same result for detectAddressFormat", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.detectAddressFormat(address) + ), + CASHADDR_ADDRESSES.map((address: string) => + bitbox.Address.detectAddressFormat(address) + ) + ) + assert.deepEqual( + REGTEST_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.detectAddressFormat(address) + ), + REGTEST_ADDRESSES.map((address: string) => + bitbox.Address.detectAddressFormat(address) + ) + ) + }) + it("should return the same result for detectAddressNetwork", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.detectAddressNetwork(address) + ), + CASHADDR_ADDRESSES.map((address: string) => + bitbox.Address.detectAddressNetwork(address) + ) + ) + assert.deepEqual( + REGTEST_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.detectAddressNetwork(address) + ), + REGTEST_ADDRESSES.map((address: string) => + bitbox.Address.detectAddressNetwork(address) + ) + ) + }) + it("should return the same result for detectAddressType", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.detectAddressType(address) + ), + CASHADDR_ADDRESSES.map((address: string) => + bitbox.Address.detectAddressType(address) + ) + ) + assert.deepEqual( + REGTEST_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.detectAddressType(address) + ), + REGTEST_ADDRESSES.map((address: string) => + bitbox.Address.detectAddressType(address) + ) + ) + }) + it("should return the same result for toLegacyAddress", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.toLegacyAddress(address) + ), + CASHADDR_ADDRESSES.map((address: string) => + bitbox.Address.toLegacyAddress(address) + ) + ) + assert.deepEqual( + REGTEST_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.toLegacyAddress(address) + ), + REGTEST_ADDRESSES.map((address: string) => + bitbox.Address.toLegacyAddress(address) + ) + ) + }) + it("should return the same result for isLegacyAddress", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.isLegacyAddress(address) + ), + CASHADDR_ADDRESSES.map((address: string) => + bitbox.Address.isLegacyAddress(address) + ) + ) + assert.deepEqual( + REGTEST_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.isLegacyAddress(address) + ), + REGTEST_ADDRESSES.map((address: string) => + bitbox.Address.isLegacyAddress(address) + ) + ) + }) + it("should return the same result for isCashAddress", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.isCashAddress(address) + ), + CASHADDR_ADDRESSES.map((address: string) => + bitbox.Address.isCashAddress(address) + ) + ) + assert.deepEqual( + REGTEST_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.isCashAddress(address) + ), + REGTEST_ADDRESSES.map((address: string) => + bitbox.Address.isCashAddress(address) + ) + ) + }) + it("should return the same result for isMainnetAddress", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.isMainnetAddress(address) + ), + CASHADDR_ADDRESSES.map((address: string) => + bitbox.Address.isMainnetAddress(address) + ) + ) + assert.deepEqual( + REGTEST_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.isMainnetAddress(address) + ), + REGTEST_ADDRESSES.map((address: string) => + bitbox.Address.isMainnetAddress(address) + ) + ) + }) + it("should return the same result for isTestnetAddress", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.isTestnetAddress(address) + ), + CASHADDR_ADDRESSES.map((address: string) => + bitbox.Address.isTestnetAddress(address) + ) + ) + assert.deepEqual( + REGTEST_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.isTestnetAddress(address) + ), + REGTEST_ADDRESSES.map((address: string) => + bitbox.Address.isTestnetAddress(address) + ) + ) + }) + it("should return the same result for isP2PKHAddress", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.isP2PKHAddress(address) + ), + CASHADDR_ADDRESSES.map((address: string) => + bitbox.Address.isP2PKHAddress(address) + ) + ) + assert.deepEqual( + REGTEST_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.isP2PKHAddress(address) + ), + REGTEST_ADDRESSES.map((address: string) => + bitbox.Address.isP2PKHAddress(address) + ) + ) + }) + it("should return the same result for isP2SHAddress", (): void => { + assert.deepEqual( + CASHADDR_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.isP2SHAddress(address) + ), + CASHADDR_ADDRESSES.map((address: string) => + bitbox.Address.isP2SHAddress(address) + ) + ) + assert.deepEqual( + REGTEST_ADDRESSES_NO_PREFIX.map((address: string) => + bitbox.Address.isP2SHAddress(address) + ), + REGTEST_ADDRESSES.map((address: string) => + bitbox.Address.isP2SHAddress(address) + ) + ) + }) + }) + + describe("#detectAddressFormat", (): void => { + LEGACY_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a legacy base58Check address`, (): void => { + const isBase58Check = bitbox.Address.detectAddressFormat(address) + assert.equal(isBase58Check, "legacy") + }) + }) + + CASHADDR_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a legacy cashaddr address`, (): void => { + const isCashaddr = bitbox.Address.detectAddressFormat(address) + assert.equal(isCashaddr, "cashaddr") + }) + }) + + REGTEST_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a legacy cashaddr address`, (): void => { + const isCashaddr = bitbox.Address.detectAddressFormat(address) + assert.equal(isCashaddr, "cashaddr") + }) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.detectAddressFormat() + }, "") + assert.throws(() => { + bitbox.Address.detectAddressFormat("some invalid address") + }, "") + }) + }) + }) + + describe("#detectAddressNetwork", (): void => { + MAINNET_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a mainnet address`, (): void => { + const isMainnet = bitbox.Address.detectAddressNetwork(address) + assert.equal(isMainnet, "mainnet") + }) + }) + + TESTNET_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a testnet address`, (): void => { + const isTestnet = bitbox.Address.detectAddressNetwork(address) + assert.equal(isTestnet, "testnet") + }) + }) + + REGTEST_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a testnet address`, (): void => { + const isTestnet = bitbox.Address.detectAddressNetwork(address) + assert.equal(isTestnet, "regtest") + }) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.detectAddressNetwork() + }, "") + assert.throws(() => { + bitbox.Address.detectAddressNetwork("some invalid address") + }, "") + }) + }) + }) + + describe("#detectAddressType", (): void => { + P2PKH_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a P2PKH address`, (): void => { + const isP2PKH: string = bitbox.Address.detectAddressType(address) + assert.equal(isP2PKH, "p2pkh") + }) + }) + + P2SH_ADDRESSES.forEach((address: string) => { + it(`should detect ${address} is a P2SH address`, (): void => { + const isP2SH: string = bitbox.Address.detectAddressType(address) + assert.equal(isP2SH, "p2sh") + }) + }) + + describe("errors", (): void => { + it("should fail when called with an invalid address", (): void => { + assert.throws(() => { + // @ts-ignore + bitbox.Address.detectAddressType() + }, "") + assert.throws(() => { + bitbox.Address.detectAddressType("some invalid address") + }, "") + }) + }) + }) + + describe("#fromXPub", (): void => { + XPUBS.forEach( + (xpub: any): void => { + xpub.addresses.forEach( + (address: any, j: number): void => { + it(`should generate public external change address ${j} for ${ + xpub.xpub + }`, (): void => { + assert.equal( + bitbox.Address.fromXPub(xpub.xpub, `0/${j}`), + address + ) + }) + } + ) + } + ) + + it(`should generate public external change address ${ + XPUBS[0].addresses[0] + } for ${XPUBS[0].xpub}`, (): void => { + const address: string = XPUBS[0].addresses[0] + assert.equal(bitbox.Address.fromXPub(XPUBS[0].xpub), address) + }) + }) + + describe("#fromXPriv", (): void => { + XPRIVS.forEach( + (xpriv: any): void => { + xpriv.addresses.forEach( + (address: string, j: number): void => { + it(`should generate hardened address ${j} for ${ + xpriv.xpriv + }`, (): void => { + assert.equal( + bitbox.Address.fromXPriv(xpriv.xpriv, `0'/${j}`), + address + ) + }) + } + ) + } + ) + + it(`should generate hardened address ${XPRIVS[0].addresses[0]} for ${ + XPRIVS[0].xpriv + }`, (): void => { + const address: string = XPRIVS[0].addresses[0] + assert.equal(bitbox.Address.fromXPriv(XPRIVS[0].xpriv), address) + }) + }) + + describe("#fromOutputScript", (): void => { + const script: Buffer = bitbox.Script.encode([ + Buffer.from("BOX", "ascii"), + bitbox.Script.opcodes.OP_CAT, + Buffer.from("BITBOX", "ascii"), + bitbox.Script.opcodes.OP_EQUAL + ]) + + // hash160 script buffer + const p2sh_hash160: Buffer = bitbox.Crypto.hash160(script) + + // encode hash160 as P2SH output + const scriptPubKey: Buffer = bitbox.Script.encodeP2SHOutput(p2sh_hash160) + fixtures.p2shMainnet.forEach( + (address: string): void => { + const p2shAddress: string = bitbox.Address.fromOutputScript( + scriptPubKey + ) + it(`generate mainnet address from output script`, (): void => { + assert.equal(p2shAddress, address) + }) + } + ) + + fixtures.p2shTestnet.forEach( + (address: string): void => { + const p2shAddress: any = bitbox.Address.fromOutputScript( + scriptPubKey, + "testnet" + ) + it(`generate testnet address from output script`, (): void => { + assert.equal(p2shAddress, address) + }) + } + ) + }) + + describe("#details", () => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it(`should GET address details for a single address`, async (): Promise< + any + > => { + // Mock out data for unit test, to prevent live network call. + const data: any = addressMock.details + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + const addr: string = + "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf" + + const result: + | AddressDetailsResult + | AddressDetailsResult[] = await bitbox.Address.details(addr) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.hasAllKeys(result, [ + "balance", + "balanceSat", + "totalReceived", + "totalReceivedSat", + "totalSent", + "totalSentSat", + "unconfirmedBalance", + "unconfirmedBalanceSat", + "unconfirmedTxApperances", + "txApperances", + "transactions", + "legacyAddress", + "cashAddress", + "slpAddress", + "currentPage", + "pagesTotal" + ]) + if (!Array.isArray(result)) assert.isArray(result.transactions) + }) + + it(`should POST address details for an array of addresses`, async (): Promise< + any + > => { + const addr: string[] = [ + "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", + "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v" + ] + + // Mock out data for unit test, to prevent live network call. + const data: any = [addressMock.details, addressMock.details] + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "post").returns(resolved) + + const result: + | AddressDetailsResult + | AddressDetailsResult[] = await bitbox.Address.details(addr) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.isArray(result) + if (Array.isArray(result)) { + assert.hasAllKeys(result[0], [ + "balance", + "balanceSat", + "totalReceived", + "totalReceivedSat", + "totalSent", + "totalSentSat", + "unconfirmedBalance", + "unconfirmedBalanceSat", + "unconfirmedTxApperances", + "txApperances", + "transactions", + "legacyAddress", + "cashAddress", + "slpAddress", + "currentPage", + "pagesTotal" + ]) + assert.isArray(result[0].transactions) + } + }) + + it(`should pass error from server to user`, async () => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws( + "error", + "Input address must be a string or array of strings." + ) + + const addr: any = 12345 + + await bitbox.Address.details(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input address must be a string or array of strings` + ) + } + }) + }) + + describe("#utxo", () => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it(`should GET utxo details for a single address`, async (): Promise< + any + > => { + // Mock out data for unit test, to prevent live network call. + const data: any = addressMock.utxos1 + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + const addr: string = + "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf" + + const result: any = await bitbox.Address.utxo(addr) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.deepEqual(addressMock.utxos1, result) + }) + + it(`should POST utxo details for an array of addresses`, async (): Promise< + any + > => { + const addr: string[] = [ + "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", + "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v" + ] + + // Mock out data for unit test, to prevent live network call. + const data: any = [addressMock.utxos1, addressMock.utxos2] + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "post").returns(resolved) + + const result: any = await bitbox.Address.utxo(addr) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.hasAllKeys(result[0], [ + "utxos", + "legacyAddress", + "cashAddress", + "slpAddress", + "scriptPubKey" + ]) + assert.isArray(result[0].utxos) + }) + + it(`should pass error from server to user`, async () => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws( + "error", + "Input address must be a string or array of strings." + ) + + const addr: any = 12345 + + await bitbox.Address.utxo(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input address must be a string or array of strings` + ) + } + }) + }) + + describe("#unconfirmed", () => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it(`should GET unconfirmed utxos for a single address`, async (): Promise< + any + > => { + // Mock out data for unit test, to prevent live network call. + const data: any = addressMock.unconfirmed1 + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + const addr: string = + "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf" + + const result: any = await bitbox.Address.unconfirmed(addr) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.deepEqual(addressMock.unconfirmed1, result) + }) + + it(`should POST unconfirmed details for an array of addresses`, async (): Promise< + any + > => { + const addr: string[] = [ + "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", + "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v" + ] + + // Mock out data for unit test, to prevent live network call. + const data: any = [addressMock.unconfirmed1, addressMock.unconfirmed2] + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "post").returns(resolved) + + const result: any = await bitbox.Address.unconfirmed(addr) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.deepEqual(data, result) + }) + + it(`should pass error from server to user`, async () => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws( + "error", + "Input address must be a string or array of strings." + ) + + const addr: any = 12345 + + await bitbox.Address.unconfirmed(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input address must be a string or array of strings` + ) + } + }) + }) + + describe(`#transactions`, (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it(`should GET transactions for a single address`, async (): Promise< + any + > => { + // Mock out data for unit test, to prevent live network call. + const data: any = addressMock.transactions + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + const addr: string = + "bitcoincash:qrvk436u4r0ew2wj0rd9pnxhx4w90p2yfc29ta0d2n" + + const result: any = await bitbox.Address.transactions(addr) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.deepEqual(data, result) + }) + + it(`should get transactions on multiple addresses`, async (): Promise< + any + > => { + // Mock out data for unit test, to prevent live network call. + const data: any = [addressMock.transactions, addressMock.transactions] + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "post").returns(resolved) + + const addr: string[] = [ + "bitcoincash:qz7teqlcltdhqjn2an8nspu7g2x6g3d3rcq8nk4nzs", + "bitcoincash:qqcp8fw06dmjd2gnfanpwytj7q93w408nv7usdqgsk" + ] + const result: any = await bitbox.Address.transactions(addr) + + assert.deepEqual(data, result) + }) + + it(`should pass error from server to user`, async () => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws( + "error", + "Input address must be a string or array of strings." + ) + + const addr: any = 12345 + + await bitbox.Address.transactions(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input address must be a string or array of strings` + ) + } + }) + }) +}) diff --git a/test/unit/BITBOX.ts b/test/unit/BITBOX.ts new file mode 100644 index 00000000..44cbc3ef --- /dev/null +++ b/test/unit/BITBOX.ts @@ -0,0 +1,121 @@ +// imports +import * as assert from "assert"; +import { BITBOX } from "../../lib/BITBOX" +import { Address } from "../../lib/Address" +import { BitcoinCash } from "../../lib/BitcoinCash" +import { Block } from "../../lib/Block" +import { Blockchain } from "../../lib/Blockchain" +import { Control } from "../../lib/Control" +import { Generating } from "../../lib/Generating" +import { HDNode } from "../../lib/HDNode" +import { Mining } from "../../lib/Mining" +import { Mnemonic } from "../../lib/Mnemonic" +import { Price } from "../../lib/Price" +import { RawTransactions } from "../../lib/RawTransactions" +import { Script } from "../../lib/Script" +import { Transaction } from "../../lib/Transaction" +import { TransactionBuilder } from "../../lib/TransactionBuilder" +import { Util } from "../../lib/Util" +import { Schnorr } from "../../lib/Schnorr" +import { REST_URL } from "../../lib/BITBOX" +import { Socket } from "../../lib/Socket" + + +describe("#BITBOX", (): void => { + describe("#BITBOXConstructor", (): void => { + it("should create instance of BITBOX", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox instanceof BITBOX, true) + }) + + it("should have a restURL property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: "https://rest.bitcoin.com/v2/" }) + assert.equal(bitbox.restURL, REST_URL) + }) + + it("should have a Address property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.Address instanceof Address, true) + }) + + it("should have a BitcoinCash property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.BitcoinCash instanceof BitcoinCash, true) + }) + + it("should have a Block property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.Block instanceof Block, true) + }) + + it("should have a Blockchain property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.Blockchain instanceof Blockchain, true) + }) + + it("should have a Control property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.Control instanceof Control, true) + }) + + it("should have a Generating property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.Generating instanceof Generating, true) + }) + + it("should have a HDNode property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.HDNode instanceof HDNode, true) + }) + + it("should have a Mining property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.Mining instanceof Mining, true) + }) + + it("should have a Mnemonic property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.Mnemonic instanceof Mnemonic, true) + }) + + it("should have a Price property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.Price instanceof Price, true) + }) + + it("should have a RawTransactions property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.RawTransactions instanceof RawTransactions, true) + }) + + it("should have a Script property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.Script instanceof Script, true) + }) + + it("should have a Transaction property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.Transaction instanceof Transaction, true) + }) + + // it("should have a TransactionBuilder property", (): void => { + // const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + // assert.equal(bitbox.TransactionBuilder instanceof TransactionBuilder, true) + // }) + + it("should have a Util property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.Util instanceof Util, true) + }) + + it("should have a Schnorr property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.equal(bitbox.Schnorr instanceof Schnorr, true) + }) + + it("should have a Socket property", (): void => { + const bitbox: BITBOX = new BITBOX({ restURL: REST_URL }) + assert.strictEqual(bitbox.Socket, Socket) + }) + }) +}) diff --git a/test/unit/BitcoinCash.ts b/test/unit/BitcoinCash.ts new file mode 100644 index 00000000..02196609 --- /dev/null +++ b/test/unit/BitcoinCash.ts @@ -0,0 +1,358 @@ +// imports +import * as chai from "chai" +import { BITBOX } from "../../lib/BITBOX" +import { BitcoinCash, BIP21Object } from "../../lib/BitcoinCash" + +// consts +const bitbox: BITBOX = new BITBOX() +const assert: Chai.AssertStatic = chai.assert + +// TODO: port from require to import syntax +const fixtures = require("./fixtures/BitcoinCash.json") + +// TODO +// 1. generate testnet p2sh +// 2. generate cashaddr mainnet p2sh +// 3. generate cashaddr testnet p2sh +// 4. create BITBOX fromBase58 method +// * confirm xpub cannot generate WIF +// * confirm xpriv can generate WIF +// 5. create fromXPriv method w/ tests and docs +// 1. mainnet +// * confirm xpriv generates address +// * confirm xpriv generates WIF +// 2. testnet +// * confirm xpriv generates address +// * confirm xpriv generates WIF +// 6. More error test cases. + +describe("#BitcoinCash", (): void => { + + describe("#BitcoinCashConstructor", (): void => { + it("should create instance of BitcoinCash", (): void => { + const bitcoinCash: BitcoinCash = new BitcoinCash() + assert.equal(bitcoinCash instanceof BitcoinCash, true) + }) + }) + + describe("price conversion", (): void => { + describe("#toBitcoinCash", (): void => { + fixtures.conversion.toBCH.satoshis.forEach((satoshi: any): void => { + it(`should convert ${satoshi[0]} Satoshis to ${ + satoshi[1] + } $BCH`, (): void => { + assert.equal(bitbox.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1]) + }) + }) + + fixtures.conversion.toBCH.strings.forEach((satoshi: any): void => { + it(`should convert "${satoshi[0]}" Satoshis as a string to ${ + satoshi[1] + } $BCH`, (): void => { + assert.equal(bitbox.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1]) + }) + }) + + fixtures.conversion.toBCH.not.forEach((bch: any): void => { + it(`converts ${bch[0]} to Bitcoin Cash, not to ${ + bch[1] + } Satoshi`, (): void => { + assert.notEqual(bitbox.BitcoinCash.toBitcoinCash(bch[0]), bch[1]) + }) + }) + + fixtures.conversion.toBCH.rounding.forEach((satoshi: any): void => { + it(`rounding ${satoshi[0]} to ${satoshi[1]} $BCH`, (): void => { + assert.equal(bitbox.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1]) + }) + }) + }) + + describe("#toSatoshi", (): void => { + fixtures.conversion.toSatoshi.bch.forEach((bch: any): void => { + it(`should convert ${bch[0]} $BCH to ${bch[1]} Satoshis`, (): void => { + assert.equal(bitbox.BitcoinCash.toSatoshi(bch[0]), bch[1]) + }) + }) + + fixtures.conversion.toSatoshi.strings.forEach((bch: any): void => { + it(`should convert "${bch[0]}" $BCH as a string to ${ + bch[1] + } Satoshis`, (): void => { + assert.equal(bitbox.BitcoinCash.toSatoshi(bch[0]), bch[1]) + }) + }) + + fixtures.conversion.toSatoshi.not.forEach((satoshi: any): void => { + it(`converts ${satoshi[0]} to Satoshi, not to ${ + satoshi[1] + } Bitcoin Cash`, (): void => { + assert.notEqual(bitbox.BitcoinCash.toSatoshi(satoshi[0]), satoshi[1]) + }) + }) + + fixtures.conversion.toSatoshi.rounding.forEach((bch: any): void => { + it(`rounding ${bch[0]} to ${bch[1]} Satoshi`, (): void => { + assert.equal(bitbox.BitcoinCash.toSatoshi(bch[0]), bch[1]) + }) + }) + }) + }) + + describe("#toBits", (): void => { + fixtures.conversion.satsToBits.bch.forEach((bch: any): void => { + it(`should convert ${bch[0]} BCH to ${bch[1]} bits`, (): void => { + assert.equal( + bitbox.BitcoinCash.toBits(bitbox.BitcoinCash.toSatoshi(bch[0])), + bch[1] + ) + }) + + fixtures.conversion.satsToBits.strings.forEach((bch: any): void => { + it(`should convert "${bch[0]}" BCH as a string to ${ + bch[1] + } bits`, (): void => { + assert.equal( + bitbox.BitcoinCash.toBits(bitbox.BitcoinCash.toSatoshi(bch[0])), + bch[1] + ) + }) + }) + }) + + describe("#satsToBits", (): void => { + fixtures.conversion.satsToBits.bch.forEach((bch: any): void => { + it(`should convert ${bch[0]} BCH to ${bch[1]} bits`, (): void => { + assert.equal( + bitbox.BitcoinCash.satsToBits(bitbox.BitcoinCash.toSatoshi(bch[0])), + bch[1] + ) + }) + }) + + fixtures.conversion.satsToBits.strings.forEach((bch: any): void => { + it(`should convert "${bch[0]}" BCH as a string to ${ + bch[1] + } bits`, (): void => { + assert.equal( + bitbox.BitcoinCash.satsToBits(bitbox.BitcoinCash.toSatoshi(bch[0])), + bch[1] + ) + }) + }) + }) + + describe("sign and verify messages", (): void => { + describe("#signMessageWithPrivKey", (): void => { + fixtures.signatures.sign.forEach((sign: any): void => { + it(`should sign a message w/ ${sign.network} ${ + sign.privateKeyWIF + }`, () => { + const privateKeyWIF: string = sign.privateKeyWIF + const message: string = sign.message + const signature: string = bitbox.BitcoinCash.signMessageWithPrivKey( + privateKeyWIF, + message + ) + assert.equal(signature, sign.signature) + }) + }) + }) + + describe("#verifyMessage", (): void => { + fixtures.signatures.verify.forEach((sign: any): void => { + it(`should verify a valid signed message from ${ + sign.network + } cashaddr address ${sign.address}`, (): void => { + assert.equal( + bitbox.BitcoinCash.verifyMessage( + sign.address, + sign.signature, + sign.message + ), + true + ) + }) + }) + + fixtures.signatures.verify.forEach((sign: any): void => { + const legacyAddress = bitbox.Address.toLegacyAddress(sign.address) + it(`should verify a valid signed message from ${ + sign.network + } legacy address ${legacyAddress}`, (): void => { + assert.equal( + bitbox.BitcoinCash.verifyMessage( + legacyAddress, + sign.signature, + sign.message + ), + true + ) + }) + }) + + fixtures.signatures.verify.forEach((sign: any): void => { + const legacyAddress = bitbox.Address.toLegacyAddress(sign.address) + it(`should not verify an invalid signed message from ${ + sign.network + } cashaddr address ${sign.address}`, (): void => { + assert.equal( + bitbox.BitcoinCash.verifyMessage( + sign.address, + sign.signature, + "nope" + ), + false + ) + }) + }) + }) + }) + + describe("encode and decode to base58Check", (): void => { + describe("#encodeBase58Check", (): void => { + fixtures.encodeBase58Check.forEach((base58Check: any): void => { + it(`encode ${base58Check.hex} as base58Check ${ + base58Check.base58Check + }`, (): void => { + assert.equal( + bitbox.BitcoinCash.encodeBase58Check(base58Check.hex), + base58Check.base58Check + ) + }) + }) + }) + + describe("#decodeBase58Check", (): void => { + fixtures.encodeBase58Check.forEach((base58Check: any): void => { + it(`decode ${base58Check.base58Check} as ${base58Check.hex}`, (): void => { + assert.equal( + bitbox.BitcoinCash.decodeBase58Check(base58Check.base58Check), + base58Check.hex + ) + }) + }) + }) + }) + + describe("encode and decode BIP21 urls", (): void => { + describe("#encodeBIP21", (): void => { + fixtures.bip21.valid.forEach((bip21: any): void => { + it(`encode ${bip21.address} as url`, (): void => { + const url: string = bitbox.BitcoinCash.encodeBIP21( + bip21.address, + bip21.options + ) + assert.equal(url, bip21.url) + }) + }) + fixtures.bip21.valid_regtest.forEach((bip21: any): void => { + it(`encode ${bip21.address} as url`, (): void => { + const url: string = bitbox.BitcoinCash.encodeBIP21( + bip21.address, + bip21.options, + true + ) + assert.equal(url, bip21.url) + }) + }) + }) + + describe("#decodeBIP21", (): void => { + fixtures.bip21.valid.forEach((bip21: any): void => { + it(`decodes ${bip21.url}`, (): void => { + const decoded: BIP21Object = bitbox.BitcoinCash.decodeBIP21(bip21.url) + assert.equal( + bitbox.Address.toCashAddress(decoded.address), + bitbox.Address.toCashAddress(bip21.address) + ) + if (decoded.options) { + assert.equal(decoded.options.amount, bip21.options.amount) + assert.equal(decoded.options.label, bip21.options.label) + } + }) + }) + // fixtures.bip21.valid_regtest.forEach((bip21, i) => { + // it(`decodes ${bip21.url}`, () => { + // const decoded = bitbox.BitcoinCash.decodeBIP21(bip21.url) + // assert.equal(decoded.options.amount, bip21.options.amount) + // assert.equal(decoded.options.label, bip21.options.label) + // assert.equal( + // bitbox.Address.toCashAddress(decoded.address, true, true), + // bitbox.Address.toCashAddress(bip21.address, true, true) + // ) + // }) + // }) + }) + }) + + describe("#getByteCount", (): void => { + fixtures.getByteCount.forEach((fixture: any): void => { + it(`get byte count`, (): void => { + const byteCount: number = bitbox.BitcoinCash.getByteCount( + fixture.inputs, + fixture.outputs + ) + assert.equal(byteCount, fixture.byteCount) + }) + }) + }) + + describe("#bip38", (): void => { + describe("#encryptBIP38", (): void => { + fixtures.bip38.encrypt.mainnet.forEach((fixture: any): void => { + it(`BIP 38 encrypt wif ${fixture.wif} with password ${ + fixture.password + } on mainnet`, (): void => { + const encryptedKey: string = bitbox.BitcoinCash.encryptBIP38( + fixture.wif, + fixture.password + ) + assert.equal(encryptedKey, fixture.encryptedKey) + }) + }) + + fixtures.bip38.encrypt.testnet.forEach((fixture: any): void => { + it(`BIP 38 encrypt wif ${fixture.wif} with password ${ + fixture.password + } on testnet`, (): void => { + const encryptedKey: string = bitbox.BitcoinCash.encryptBIP38( + fixture.wif, + fixture.password + ) + assert.equal(encryptedKey, fixture.encryptedKey) + }) + }) + }) + + describe("#decryptBIP38", (): void => { + fixtures.bip38.decrypt.mainnet.forEach((fixture: any): void => { + it(`BIP 38 decrypt encrypted key ${ + fixture.encryptedKey + } on mainnet`, (): void => { + const wif: string = bitbox.BitcoinCash.decryptBIP38( + fixture.encryptedKey, + fixture.password, + "mainnet" + ) + assert.equal(wif, fixture.wif) + }) + }) + + fixtures.bip38.decrypt.testnet.forEach((fixture: any): void => { + it(`BIP 38 decrypt encrypted key ${ + fixture.encryptedKey + } on testnet`, (): void => { + const wif: string = bitbox.BitcoinCash.decryptBIP38( + fixture.encryptedKey, + fixture.password, + "testnet" + ) + assert.equal(wif, fixture.wif) + }) + }) + }) + }) + }) +}) + diff --git a/test/unit/Block.ts b/test/unit/Block.ts new file mode 100644 index 00000000..e648530f --- /dev/null +++ b/test/unit/Block.ts @@ -0,0 +1,146 @@ +// imports +import * as chai from "chai" +import axios from "axios" +import * as sinon from "sinon" +import { BITBOX } from "../../lib/BITBOX" +import { Block } from "../../lib/Block" +import { REST_URL } from "../../lib/BITBOX" +import * as util from "util" +import { BlockDetailsResult } from "bitcoin-com-rest" + +// consts +const bitbox: BITBOX = new BITBOX() +const assert: Chai.AssertStatic = chai.assert +const blockMock: any = require("./mocks/block-mock") + +util.inspect.defaultOptions = { + showHidden: true, + colors: true, + depth: 3 +} + +describe("#Block", (): void => { + describe("#BlockConstructor", (): void => { + it("should create instance of Block", (): void => { + const block: Block = new Block() + assert.equal(block instanceof Block, true) + }) + }) + + it("should have a restURL property", (): void => { + const block: Block = new Block() + assert.equal(block.restURL, REST_URL) + }) + + describe("#detailsByHash", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it(`should GET a single hash`, async (): Promise => { + // Mock out data for unit test, to prevent live network call. + const data: any = blockMock.details + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + const result: any = await bitbox.Block.detailsByHash( + "000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0" + ) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.deepEqual(blockMock.details, result) + }) + + it(`should POST an array of hashes`, async (): Promise => { + const hashes: string[] = [ + "000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0", + "000000000000000002160687d7f39b6232b5acbb2e2b44cd68e3c6b2debe9ea3" + ] + + // Mock out data for unit test, to prevent live network call. + const data: any = [blockMock.details, blockMock.details] + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "post").returns(resolved) + + const result: any = await bitbox.Block.detailsByHash(hashes) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.deepEqual(data, result) + }) + + it(`should pass error from server to user`, async () => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws("error", "Input must be a string or array of strings.") + + const hash: any = 12345 + + await bitbox.Block.detailsByHash(hash) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input must be a string or array of strings.` + ) + } + }) + }) + + describe("#detailsByHeight", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it(`should GET a single height`, async (): Promise => { + // Mock out data for unit test, to prevent live network call. + const data: any = blockMock.details + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + const height: number = 500007 + + const result: any = await bitbox.Block.detailsByHeight(height) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.deepEqual(blockMock.details, result) + }) + + it(`should POST an array of heights`, async (): Promise => { + const heights: number[] = [500007, 500008] + + // Mock out data for unit test, to prevent live network call. + const data: any = [blockMock.details, blockMock.details] + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "post").returns(resolved) + + const result: any = await bitbox.Block.detailsByHeight(heights) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.deepEqual(data, result) + }) + + it(`should pass error from server to user`, async () => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws("error", "Input must be a number or array of numbers.") + + const height: any = "abc123" + + await bitbox.Block.detailsByHeight(height) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + + assert.include( + err.message, + `Input must be a number or array of numbers.` + ) + } + }) + }) +}) diff --git a/test/unit/Blockchain.ts b/test/unit/Blockchain.ts new file mode 100644 index 00000000..4ce9f2fa --- /dev/null +++ b/test/unit/Blockchain.ts @@ -0,0 +1,789 @@ +// imports +import * as chai from "chai" +import axios from "axios" +import * as sinon from "sinon" +import { BITBOX } from "../../lib/BITBOX" +import { Blockchain } from "../../lib/Blockchain" +import { REST_URL } from "../../lib/BITBOX" +import * as util from "util" +import { BlockHeaderResult } from "bitcoin-com-rest" + +const mockData = require("./mocks/blockchain-mock") + +// consts +const bitbox: BITBOX = new BITBOX() +const assert: Chai.AssertStatic = chai.assert +const blockchainMock = require("./mocks/blockchain-mock") + +util.inspect.defaultOptions = { + showHidden: true, + colors: true, + depth: 3 +} + +describe("#Blockchain", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + describe("#BlockchainConstructor", (): void => { + it("should create instance of Blockchain", (): void => { + const blockchain: Blockchain = new Blockchain() + assert.equal(blockchain instanceof Blockchain, true) + }) + + it("should have a restURL property", (): void => { + const blockchain: Blockchain = new Blockchain() + assert.equal(blockchain.restURL, REST_URL) + }) + }) + + describe("#getBlock", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = { + hash: "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", + confirmations: 526807, + size: 216, + height: 1000, + version: 1, + versionHex: "00000001", + merkleroot: + "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33", + tx: ["fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33"], + time: 1232346882, + mediantime: 1232344831, + nonce: 2595206198, + bits: "1d00ffff", + difficulty: 1, + chainwork: + "000000000000000000000000000000000000000000000000000003e903e903e9", + previousblockhash: + "0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d", + nextblockhash: + "00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6" + } + + it("should get block by hash", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Blockchain.getBlock( + "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09" + ) + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getBlockchainInfo", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = { + chain: "main", + blocks: 527810, + headers: 527810, + bestblockhash: + "000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0", + difficulty: 576023394804.6666, + mediantime: 1524878499, + verificationprogress: 0.9999990106793685, + chainwork: + "00000000000000000000000000000000000000000096da5b040913fa09249b4e", + pruned: false, + softforks: [ + { id: "bip34", version: 2, reject: [Object] }, + { id: "bip66", version: 3, reject: [Object] }, + { id: "bip65", version: 4, reject: [Object] } + ], + bip9_softforks: { + csv: { + status: "active", + startTime: 1462060800, + timeout: 1493596800, + since: 419328 + } + } + } + + it("should get blockchain info", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Blockchain.getBlockchainInfo() + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getBlockCount", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = 527810 + + it("should get block count", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Blockchain.getBlockCount() + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getBlockHash", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data: string = + "000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0" + + it("should get block hash by height", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Blockchain.getBlockHash(527810) + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getBlockHeader", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = { + hash: "000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0", + confirmations: 1, + height: 527810, + version: 536870912, + versionHex: "20000000", + merkleroot: + "9298432bbebe4638456aa19cb7ef91639da87668a285d88d0ecd6080424d223b", + time: 1524881438, + mediantime: 1524878499, + nonce: 3326843941, + bits: "1801e8a5", + difficulty: 576023394804.6666, + chainwork: + "00000000000000000000000000000000000000000096da5b040913fa09249b4e", + previousblockhash: + "000000000000000000b33251708bc7a7b4540e61880d8c376e8e2db6a19a4789" + } + + it("should get block header by hash", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Blockchain.getBlockHeader( + "000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0", + true + ) + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getDifficulty", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = "577528469277.1339" + + it("should get difficulty", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Blockchain.getDifficulty() + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getMempoolAncestors", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = "Transaction not in mempool" + + it("should get mempool ancestors", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Blockchain.getMempoolAncestors( + "daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88", + true + ) + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getMempoolDescendants", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = { + result: "Transaction not in mempool" + } + + it("should get mempool descendants", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Blockchain.getMempoolDescendants( + "daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88", + true + ) + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getMempoolEntry", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = { + result: "Transaction not in mempool" + } + + it("should get mempool entry", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Blockchain.getMempoolEntry( + "daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88" + ) + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getMempoolInfo", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = { + result: { + size: 317, + bytes: 208583, + usage: 554944, + maxmempool: 300000000, + mempoolminfee: 0 + } + } + + it("should get mempool info", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Blockchain.getMempoolInfo() + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getRawMempool", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = { + result: { + transactions: [ + { + txid: + "ab36d68dd0a618592fe34e4a898e8beeeb4049133547dbb16f9338384084af96", + size: 191, + fee: 0.00047703, + modifiedfee: 0.00047703, + time: 1524883317, + height: 527811, + startingpriority: 5287822727.272727, + currentpriority: 5287822727.272727, + descendantcount: 1, + descendantsize: 191, + descendantfees: 47703, + ancestorcount: 1, + ancestorsize: 191, + ancestorfees: 47703, + depends: [] + } + ] + } + } + + it("should get mempool info", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Blockchain.getRawMempool() + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getTxOut", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = { + result: {} + } + + it("should throw an error for improper txid.", async () => { + try { + await bitbox.Blockchain.getTxOut("badtxid", 0) + } catch (err) { + assert.include(err.message, "txid needs to be a proper transaction ID") + } + }) + + it("should throw an error if vout is not an integer.", async () => { + try { + await bitbox.Blockchain.getTxOut( + "daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88", 'a' + ) + } catch (err) { + assert.include(err.message, "n must be an integer") + } + }) + + it("should get information on an unspent tx", async () => { + sandbox.stub(axios, "get").resolves({ data: mockData.txOutUnspent }) + + const result = await bitbox.Blockchain.getTxOut( + "62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8", + 0, + true + ) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, [ + "bestblock", + "confirmations", + "value", + "scriptPubKey", + "coinbase" + ]) + }) + + it("should get information on a spent tx", async () => { + sandbox.stub(axios, "get").resolves({ data: null }) + + const result = await bitbox.Blockchain.getTxOut( + "87380e52d151856b23173d6d8a3db01b984c6b50f77ea045a5a1cf4f54497871", + 0, + true + ) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.equal(result, null) + }) + }) + + describe("#preciousBlock", (): void => { + // TODO finish this test + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = { + result: {} + } + + it("should get TODO", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + // @ts-ignore + bitbox.Blockchain.preciousBlock() + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#pruneBlockchain", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = "Cannot prune blocks because node is not in prune mode." + + it("should prune blockchain", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "post").returns(resolved) + + bitbox.Blockchain.pruneBlockchain(507) + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#verifyChain", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = true + + it("should verify blockchain", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Blockchain.verifyChain(3, 6) + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#verifyTxOutProof", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + const data = "proof must be hexadecimal string (not '')" + + it("should verify utxo proof", done => { + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Blockchain.verifyTxOutProof("3") + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe(`#getBestBlockHash`, (): void => { + it(`should GET best block hash`, async () => { + // Mock out data for unit test, to prevent live network call. + const data: any = blockchainMock.bestBlockHash + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + const result: string = await bitbox.Blockchain.getBestBlockHash() + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + // Assert that BITBOX returns the same data passed to it by rest. + assert.deepEqual(result, blockchainMock.bestBlockHash) + }) + }) + + describe("#getBlockHeader", (): void => { + it(`should GET block header for a single hash`, async () => { + // Mock out data for unit test, to prevent live network call. + const data: any = blockchainMock.blockHeader + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + const hash: string = + "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201" + + const result: + | BlockHeaderResult + | BlockHeaderResult[] = await bitbox.Blockchain.getBlockHeader(hash) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.hasAllKeys(result, [ + "hash", + "confirmations", + "height", + "version", + "versionHex", + "merkleroot", + "time", + "mediantime", + "nonce", + "bits", + "difficulty", + "chainwork", + "previousblockhash", + "nextblockhash" + ]) + }) + + it(`should POST block headers for an array of hashes`, async () => { + // Mock out data for unit test, to prevent live network call. + const data: any = [blockchainMock.blockHeader, blockchainMock.blockHeader] + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "post").returns(resolved) + + const hash: string[] = [ + "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201", + "00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3" + ] + + const result: + | BlockHeaderResult + | BlockHeaderResult[] = await bitbox.Blockchain.getBlockHeader(hash) + + assert.isArray(result) + if (Array.isArray(result)) { + assert.hasAllKeys(result[0], [ + "hash", + "confirmations", + "height", + "version", + "versionHex", + "merkleroot", + "time", + "mediantime", + "nonce", + "bits", + "difficulty", + "chainwork", + "previousblockhash", + "nextblockhash" + ]) + } + }) + + it(`should pass error from server to user`, async () => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws("error", "Input hash must be a string or array of strings") + + const hash: any = 12345 + + await bitbox.Blockchain.getBlockHeader(hash) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.include( + err.message, + `Input hash must be a string or array of strings` + ) + } + }) + }) + + describe("#getMempoolEntry", (): void => { + /* + // To run this test, the txid must be unconfirmed. + const txid = + "defea04c38ee00cf73ad402984714ed22dc0dd99b2ae5cb50d791d94343ba79b" + + it(`should GET single mempool entry`, async () => { + const result = await bitbox.Blockchain.getMempoolEntry(txid) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAnyKeys(result, [ + "size", + "fee", + "modifiedfee", + "time", + "height", + "startingpriority", + "currentpriority", + "descendantcount", + "descendantsize", + "descendantfees", + "ancestorcount", + "ancestorsize", + "ancestorfees", + "depends" + ]) + }) + + it(`should get an array of mempool entries`, async () => { + const result = await bitbox.Blockchain.getMempoolEntry([txid, txid]) + console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.hasAnyKeys(result[0], [ + "size", + "fee", + "modifiedfee", + "time", + "height", + "startingpriority", + "currentpriority", + "descendantcount", + "descendantsize", + "descendantfees", + "ancestorcount", + "ancestorsize", + "ancestorfees", + "depends" + ]) + }) + */ + + it(`should pass error from server to user`, async (): Promise => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws({ error: "Transaction not in mempool" }) + + const txid: string = + "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7" + + await bitbox.Blockchain.getMempoolEntry(txid) + + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: ${util.inspect(err)}`) + assert.hasAnyKeys(err, ["error"]) + assert.include(err.error, `Transaction not in mempool`) + } + }) + + it(`should throw an error for improper single input`, async (): Promise< + any + > => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws("error", "Input hash must be a string or array of strings") + + const txid: any = 12345 + + await bitbox.Blockchain.getMempoolEntry(txid) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.include( + err.message, + `Input must be a string or array of strings` + ) + } + }) + }) + + describe(`#getTxOutProof`, (): void => { + it(`should get single tx out proof`, async (): Promise => { + // Mock out data for unit test, to prevent live network call. + const data: any = blockchainMock.txOutProof + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + const txid: string = + "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7" + + const result = await bitbox.Blockchain.getTxOutProof(txid) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.isString(result) + }) + + it(`should POST an array of tx out proofs`, async (): Promise => { + // Mock out data for unit test, to prevent live network call. + const data: any = [blockchainMock.txOutProof, blockchainMock.txOutProof] + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "post").returns(resolved) + + const txid: string[] = [ + "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7", + "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33" + ] + + const result = await bitbox.Blockchain.getTxOutProof(txid) + + assert.isArray(result) + assert.isString(result[0]) + }) + + it(`should pass error from server to user`, async (): Promise => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws("error", "Input hash must be a string or array of strings") + + const txid: any = 12345 + + await bitbox.Blockchain.getTxOutProof(txid) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.include( + err.message, + `Input must be a string or array of strings` + ) + } + }) + }) + + describe(`#verifyTxOutProof`, (): void => { + const mockTxOutProof: string = + "0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01" + + it(`should verify a single proof`, async (): Promise => { + // Mock out data for unit test, to prevent live network call. + const data: any = [blockchainMock.verifiedProof] + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + const result = await bitbox.Blockchain.verifyTxOutProof(mockTxOutProof) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.isArray(result) + assert.isString(result[0]) + }) + + it(`should verify an array of proofs`, async (): Promise => { + // Mock out data for unit test, to prevent live network call. + const data: any = [ + blockchainMock.verifiedProof, + blockchainMock.verifiedProof + ] + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "post").returns(resolved) + + const proofs: string[] = [mockTxOutProof, mockTxOutProof] + const result = await bitbox.Blockchain.verifyTxOutProof(proofs) + + assert.isArray(result) + assert.isString(result[0]) + }) + + it(`should pass error from server to user`, async (): Promise => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws("error", "Input must be a string or array of strings") + + const txid: any = 12345 + + await bitbox.Blockchain.verifyTxOutProof(txid) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.include( + err.message, + `Input must be a string or array of strings` + ) + } + }) + }) +}) diff --git a/test/unit/CashAccounts.ts b/test/unit/CashAccounts.ts new file mode 100644 index 00000000..77733727 --- /dev/null +++ b/test/unit/CashAccounts.ts @@ -0,0 +1,126 @@ +// imports +import axios from "axios" +import { + CashAccountCheckResult, + CashAccountLookupResult, + CashAccountReverseLookupResult +} from "bitcoin-com-rest" +import * as chai from "chai" +import * as util from "util" +import { BITBOX, REST_URL } from "../../lib/BITBOX" +import { CashAccounts } from "../../lib/CashAccounts" + +// consts +const bitbox: BITBOX = new BITBOX() +const assert: Chai.AssertStatic = chai.assert + +// TODO: port from require to import syntax +const sinon = require("sinon") +const cashAccountsMock = require("./mocks/cashaccounts-mock.js") + +util.inspect.defaultOptions = { + showHidden: true, + colors: true, + depth: 3 +} + +describe("#CashAccounts", (): void => { + describe("#CashAccountsConstructor", (): void => { + it("should create instance of CashAccounts", (): void => { + const cashAccounts: CashAccounts = new CashAccounts() + assert.equal(cashAccounts instanceof CashAccounts, true) + }) + + it("should have a restURL property", (): void => { + const cashAccounts: CashAccounts = new CashAccounts() + assert.equal(cashAccounts.restURL, REST_URL) + }) + }) + + describe("#lookup", () => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it(`should lookup CashAccount details by account, number and collision`, async (): Promise< + any + > => { + // Mock out data for unit test, to prevent live network call. + const data: any = cashAccountsMock.lookup + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + const account: string = "cgcardona" + const number: number = 122 + const collision: number = 6383276713 + + const result = (await bitbox.CashAccounts.lookup( + account, + number, + collision + )) as CashAccountLookupResult + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.hasAllKeys(result, ["identifier", "information"]) + }) + }) + + describe("#check", () => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it(`should check CashAccount by account and number`, async (): Promise< + any + > => { + // Mock out data for unit test, to prevent live network call. + const data: any = cashAccountsMock.check + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + const account: string = "cgcardona" + const number: number = 122 + + const result = (await bitbox.CashAccounts.check( + account, + number + )) as CashAccountCheckResult + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.hasAllKeys(result, ["identifier", "block", "results"]) + }) + }) + + describe("#reverseLookup", () => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it(`should reverse lookup CashAccount details by cash address`, async (): Promise< + any + > => { + // Mock out data for unit test, to prevent live network call. + const data: any = cashAccountsMock.reverseLookup + const resolved: any = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + const cashAddress: string = + "bitcoincash:qr4aadjrpu73d2wxwkxkcrt6gqxgu6a7usxfm96fst" + + const result = (await bitbox.CashAccounts.reverseLookup( + cashAddress + )) as CashAccountReverseLookupResult + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.hasAllKeys(result.results[0], [ + "accountEmoji", + "nameText", + "accountNumber", + "accountHash", + "accountCollisionLength", + "payloadType", + "payloadAddress" + ]) + }) + }) +}) diff --git a/test/unit/Control.ts b/test/unit/Control.ts new file mode 100644 index 00000000..81a730ad --- /dev/null +++ b/test/unit/Control.ts @@ -0,0 +1,111 @@ +// imports +import * as assert from "assert"; +import axios from "axios"; +import * as sinon from "sinon"; +import { BITBOX } from "../../lib/BITBOX" +import { Control } from "../../lib/Control" +import { REST_URL } from "../../lib/BITBOX" + +// consts +const bitbox: BITBOX = new BITBOX() + +describe("#Control", (): void => { + describe("#ControlConstructor", (): void => { + it("should create instance of Control", (): void => { + const control: Control = new Control() + assert.equal(control instanceof Control, true) + }) + + it("should have a restURL property", (): void => { + const control: Control = new Control() + assert.equal(control.restURL, REST_URL) + }) + }) + + describe("#getInfo", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it("should get info", done => { + const data = { + version: 170000, + protocolversion: 70015, + blocks: 527813, + timeoffset: 0, + connections: 21, + proxy: "", + difficulty: 581086703759.5878, + testnet: false, + paytxfee: 0, + relayfee: 0.00001, + errors: "" + } + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Control.getInfo() + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getNetworkInfo", () => { + let sandbox: any + beforeEach(() => (sandbox = sinon.createSandbox())) + afterEach(() => sandbox.restore()) + + it("should get network info", done => { + const data = { + version: 170000, + protocolversion: 70015, + blocks: 527813, + timeoffset: 0, + connections: 21, + proxy: "", + difficulty: 581086703759.5878, + testnet: false, + paytxfee: 0, + relayfee: 0.00001, + errors: "" + } + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Control.getNetworkInfo() + .then(result => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + // describe("#getMemoryInfo", () => { + // let sandbox: any + // beforeEach(() => (sandbox = sinon.sandbox.create())) + // afterEach(() => sandbox.restore()) + + // it("should get memory info", done => { + // const data = { + // locked: { + // used: 0, + // free: 65536, + // total: 65536, + // locked: 65536, + // chunks_used: 0, + // chunks_free: 1 + // } + // } + // const resolved = new Promise(r => r({ data: data })) + // sandbox.stub(axios, "get").returns(resolved) + + // bitbox.Control.getMemoryInfo() + // .then((result: any) => { + // assert.deepEqual(data, result) + // }) + // .then(done, done) + // }) + // }) +}) diff --git a/test/unit/Crypto.ts b/test/unit/Crypto.ts new file mode 100644 index 00000000..e20991b1 --- /dev/null +++ b/test/unit/Crypto.ts @@ -0,0 +1,137 @@ +// imports +import * as assert from "assert"; +import { BITBOX } from "../../lib/BITBOX" +import { Buffer } from "buffer" + +// consts +const bitbox: BITBOX = new BITBOX() + +// TODO: port from require to import syntax +const fixtures = require("./fixtures/Crypto.json") + +describe("#Crypto", (): void => { + describe("#sha1", (): void => { + fixtures.sha1.forEach((fixture: any): void => { + it(`should create SHA1 Hash hex encoded ${fixture.hash} from ${ + fixture.hex + }`, (): void => { + const data: Buffer = Buffer.from(fixture.hex, "hex") + const sha1Hash: string = bitbox.Crypto.sha1(data).toString("hex") + assert.equal(sha1Hash, fixture.hash) + }) + + it(`should create 40 character SHA1 Hash hex encoded`, (): void => { + const data: Buffer = Buffer.from(fixture.hex, "hex") + const sha1Hash: string = bitbox.Crypto.sha1(data).toString("hex") + assert.equal(sha1Hash.length, 40) + }) + }) + }) + + describe("#sha256", (): void => { + fixtures.sha256.forEach((fixture: any): void => { + it(`should create SHA256 Hash hex encoded ${fixture.hash} from ${ + fixture.hex + }`, (): void => { + const data: Buffer = Buffer.from(fixture.hex, "hex") + const sha256Hash: string = bitbox.Crypto.sha256(data).toString("hex") + assert.equal(sha256Hash, fixture.hash) + }) + + it(`should create 64 character SHA256Hash hex encoded`, (): void => { + const data: Buffer = Buffer.from(fixture.hex, "hex") + const sha256Hash: string = bitbox.Crypto.sha256(data).toString("hex") + assert.equal(sha256Hash.length, 64) + }) + }) + }) + + describe("#ripemd160", (): void => { + fixtures.ripemd160.forEach((fixture: any): void => { + it(`should create RIPEMD160 Hash hex encoded ${fixture.hash} from ${ + fixture.hex + }`, (): void => { + const data: Buffer = Buffer.from(fixture.hex, "hex") + const ripemd160: string = bitbox.Crypto.ripemd160(data).toString("hex") + assert.equal(ripemd160, fixture.hash) + }) + + it(`should create 64 character RIPEMD160Hash hex encoded`, (): void => { + const data: Buffer = Buffer.from(fixture.hex, "hex") + const ripemd160: string = bitbox.Crypto.ripemd160(data).toString("hex") + assert.equal(ripemd160.length, 40) + }) + }) + }) + + describe("#hash256", (): void => { + fixtures.hash256.forEach((fixture: any): void => { + it(`should create double SHA256 Hash hex encoded ${fixture.hash} from ${ + fixture.hex + }`, (): void => { + const data: Buffer = Buffer.from(fixture.hex, "hex") + const hash256: string = bitbox.Crypto.hash256(data).toString("hex") + assert.equal(hash256, fixture.hash) + }) + + it(`should create 64 character SHA256 Hash hex encoded`, (): void => { + const data: Buffer = Buffer.from(fixture.hex, "hex") + const hash256: string = bitbox.Crypto.hash256(data).toString("hex") + assert.equal(hash256.length, 64) + }) + }) + }) + + describe("#hash160", (): void => { + fixtures.hash160.forEach((fixture: any): void => { + it(`should create RIPEMD160(SHA256()) hex encoded ${fixture.hash} from ${ + fixture.hex + }`, (): void => { + const data: Buffer = Buffer.from(fixture.hex, "hex") + const hash160: string = bitbox.Crypto.hash160(data).toString("hex") + assert.equal(hash160, fixture.hash) + }) + + it(`should create 64 character SHA256Hash hex encoded`, (): void => { + const data: Buffer = Buffer.from(fixture.hex, "hex") + const hash160: string = bitbox.Crypto.hash160(data).toString("hex") + assert.equal(hash160.length, 40) + }) + }) + }) + + + describe("#randomBytes", (): void => { + for (let i: number = 0; i < 6; i++) { + it("should return 16 bytes of entropy hex encoded via default value", (): void => { + const entropy: Buffer = bitbox.Crypto.randomBytes() + assert.equal(Buffer.byteLength(entropy), 16) + }) + + it("should return 16 bytes of entropy hex encoded", (): void => { + const entropy: Buffer = bitbox.Crypto.randomBytes(16) + assert.equal(Buffer.byteLength(entropy), 16) + }) + + it("should return 20 bytes of entropy hex encoded", (): void => { + const entropy: Buffer = bitbox.Crypto.randomBytes(20) + assert.equal(Buffer.byteLength(entropy), 20) + }) + + it("should return 24 bytes of entropy hex encoded", (): void => { + const entropy: Buffer = bitbox.Crypto.randomBytes(24) + assert.equal(Buffer.byteLength(entropy), 24) + }) + + it("should return 28 bytes of entropy hex encoded", (): void => { + const entropy: Buffer = bitbox.Crypto.randomBytes(28) + assert.equal(Buffer.byteLength(entropy), 28) + }) + + it("should return 32 bytes of entropy hex encoded", (): void => { + const entropy: Buffer = bitbox.Crypto.randomBytes(32) + assert.equal(Buffer.byteLength(entropy), 32) + }) + } + }) +}) diff --git a/test/unit/ECPair.ts b/test/unit/ECPair.ts new file mode 100644 index 00000000..b5a54784 --- /dev/null +++ b/test/unit/ECPair.ts @@ -0,0 +1,187 @@ +// imports +import * as assert from "assert" +import { Buffer } from "buffer" +import { BITBOX } from "../../lib/BITBOX" +import { ECPair } from "../../lib/ECPair" + +// consts +const bitbox: BITBOX = new BITBOX() + +// TODO: port from require to import syntax +const fixtures = require("./fixtures/ECPair.json") + +describe("#ECPair", (): void => { + describe("#ECPairConstructor", (): void => { + it("should create instance of ECPair", (): void => { + const ecpair: ECPair = new ECPair() + assert.equal(ecpair instanceof ECPair, true) + }) + }) + + describe("#fromWIF", (): void => { + fixtures.fromWIF.forEach( + (fixture: any): void => { + it(`should create ECPair from WIF ${ + fixture.privateKeyWIF + }`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromWIF(fixture.privateKeyWIF) + assert.equal(typeof ecpair, "object") + }) + + it(`should get ${fixture.legacy} legacy address`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromWIF(fixture.privateKeyWIF) + assert.equal(bitbox.ECPair.toLegacyAddress(ecpair), fixture.legacy) + }) + + it(`should get ${fixture.cashAddr} cash address`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromWIF(fixture.privateKeyWIF) + assert.equal(bitbox.ECPair.toCashAddress(ecpair), fixture.cashAddr) + }) + + it(`should get ${fixture.regtestAddr} cash address`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromWIF(fixture.privateKeyWIF) + assert.equal( + bitbox.ECPair.toCashAddress(ecpair, true), + fixture.regtestAddr + ) + }) + } + ) + }) + + describe("#toWIF", (): void => { + fixtures.toWIF.forEach( + (fixture: any): void => { + it(`should get WIF ${fixture.privateKeyWIF} from ECPair`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromWIF(fixture.privateKeyWIF) + const wif: string = bitbox.ECPair.toWIF(ecpair) + assert.equal(wif, fixture.privateKeyWIF) + }) + } + ) + }) + + describe("#fromPublicKey", (): void => { + fixtures.fromPublicKey.forEach( + (fixture: any): void => { + it(`should create ECPair from public key buffer`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromPublicKey( + Buffer.from(fixture.pubkeyHex, "hex") + ) + assert.equal(typeof ecpair, "object") + }) + + it(`should get ${fixture.legacy} legacy address`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromPublicKey( + Buffer.from(fixture.pubkeyHex, "hex") + ) + assert.equal(bitbox.ECPair.toLegacyAddress(ecpair), fixture.legacy) + }) + + it(`should get ${fixture.cashAddr} cash address`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromPublicKey( + Buffer.from(fixture.pubkeyHex, "hex") + ) + assert.equal(bitbox.ECPair.toCashAddress(ecpair), fixture.cashAddr) + }) + + it(`should get ${fixture.regtestAddr} cash address`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromPublicKey( + Buffer.from(fixture.pubkeyHex, "hex") + ) + assert.equal( + bitbox.ECPair.toCashAddress(ecpair, true), + fixture.regtestAddr + ) + }) + } + ) + }) + + describe("#toPublicKey", (): void => { + fixtures.toPublicKey.forEach( + (fixture: any): void => { + it(`should create a public key buffer from an ECPair`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromPublicKey( + Buffer.from(fixture.pubkeyHex, "hex") + ) + const pubkeyBuffer: Buffer = bitbox.ECPair.toPublicKey(ecpair) + assert.equal(typeof pubkeyBuffer, "object") + }) + } + ) + }) + + describe("#toLegacyAddress", (): void => { + fixtures.toLegacyAddress.forEach( + (fixture: any): void => { + it(`should create legacy address ${ + fixture.legacy + } from an ECPair`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromWIF(fixture.privateKeyWIF) + const legacyAddress: string = bitbox.ECPair.toLegacyAddress(ecpair) + assert.equal(legacyAddress, fixture.legacy) + }) + } + ) + }) + + describe("#toCashAddress", (): void => { + fixtures.toCashAddress.forEach( + (fixture: any): void => { + it(`should create cash address ${ + fixture.cashAddr + } from an ECPair`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromWIF(fixture.privateKeyWIF) + const cashAddr: string = bitbox.ECPair.toCashAddress(ecpair) + assert.equal(cashAddr, fixture.cashAddr) + }) + } + ) + + fixtures.toCashAddress.forEach( + (fixture: any): void => { + it(`should create regtest cash address ${ + fixture.regtestAddr + } from an ECPair`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromWIF(fixture.privateKeyWIF) + const regtestAddr: string = bitbox.ECPair.toCashAddress(ecpair, true) + assert.equal(regtestAddr, fixture.regtestAddr) + }) + } + ) + }) + + describe("#sign", (): void => { + fixtures.sign.forEach( + (fixture: any): void => { + it(`should sign 32 byte hash buffer`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromWIF(fixture.privateKeyWIF) + const buf: Buffer = Buffer.from(bitbox.Crypto.sha256(fixture.data)) + const sig: any = bitbox.ECPair.sign(ecpair, buf) + .toDER() + .toString("hex") + const schnorrSig: any = bitbox.ECPair.sign(ecpair, buf, 0x01) + .toDER() + .toString("hex") + assert.equal(sig, fixture.sig) + assert.equal(schnorrSig, fixture.schnorrSig) + }) + } + ) + }) + + describe("#verify", (): void => { + fixtures.verify.forEach( + (fixture: any): void => { + it(`should verify signed 32 byte hash buffer`, (): void => { + const ecpair: ECPair = bitbox.ECPair.fromWIF(fixture.privateKeyWIF1) + const buf: Buffer = Buffer.from(bitbox.Crypto.sha256(fixture.data)) + const signature: Buffer = bitbox.ECPair.sign(ecpair, buf) + const verify: boolean = bitbox.ECPair.verify(ecpair, buf, signature) + assert.equal(verify, true) + }) + } + ) + }) +}) diff --git a/test/unit/Generating.ts b/test/unit/Generating.ts new file mode 100644 index 00000000..a882601e --- /dev/null +++ b/test/unit/Generating.ts @@ -0,0 +1,44 @@ +// imports +import * as assert from "assert"; +import axios from "axios"; +import * as sinon from "sinon"; +import { BITBOX, REST_URL } from "../../lib/BITBOX" +import { Generating } from "../../lib/Generating" + +// consts +const bitbox: BITBOX = new BITBOX() + +describe("#Generating", (): void => { + describe("#GeneratingConstructor", (): void => { + it("should create instance of Generating", (): void => { + const generating: Generating = new Generating() + assert.equal(generating instanceof Generating, true) + }) + + it("should have a restURL property", (): void => { + const generating: Generating = new Generating() + assert.equal(generating.restURL, REST_URL) + }) + }) + + describe("#generateToAddress", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it("should generate", done => { + const data: any = [] + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "post").returns(resolved) + + bitbox.Generating.generateToAddress( + 1, + "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf" + ) + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) +}) diff --git a/test/unit/HDNode.ts b/test/unit/HDNode.ts new file mode 100644 index 00000000..e2d0b8ab --- /dev/null +++ b/test/unit/HDNode.ts @@ -0,0 +1,358 @@ +// imports +import * as assert from "assert"; +import { BITBOX } from "../../lib/BITBOX" +import { HDNode } from "../../lib/HDNode" +import * as bcl from "bitcoincashjs-lib" + +// consts +const bitbox: BITBOX = new BITBOX() + +// TODO: port from require to import syntax +const fixtures = require("./fixtures/HDNode.json") + +describe("#HDNode", (): void => { + describe("#HDNodeConstructor", (): void => { + it("should create instance of HDNode", (): void => { + const hdnode: HDNode = new HDNode() + assert.equal(hdnode instanceof HDNode, true) + }) + }) + + describe("#fromSeed", (): void => { + fixtures.fromSeed.forEach((mnemonic: string): void => { + it(`should create an HDNode from root seed buffer`, (): void => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + assert.notEqual(hdNode, null) + }) + }) + }) + + describe("#derive", (): void => { + fixtures.derive.forEach((derive: any): void => { + it(`should derive non hardened child HDNode`, (): void => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(derive.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + const childHDNode: bcl.HDNode = bitbox.HDNode.derive(hdNode, 0) + assert.equal(bitbox.HDNode.toXPub(childHDNode), derive.xpub) + assert.equal(bitbox.HDNode.toXPriv(childHDNode), derive.xpriv) + }) + }) + }) + + describe("#deriveHardened", (): void => { + fixtures.deriveHardened.forEach((derive: any): void => { + it(`should derive hardened child HDNode`, (): void => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(derive.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + const childHDNode: bcl.HDNode = bitbox.HDNode.deriveHardened(hdNode, 0) + assert.equal(bitbox.HDNode.toXPub(childHDNode), derive.xpub) + assert.equal(bitbox.HDNode.toXPriv(childHDNode), derive.xpriv) + }) + }) + + describe("derive BIP44 $BCH account", (): void => { + fixtures.deriveBIP44.forEach((derive: any): void => { + it(`should derive BIP44 $BCH account`, (): void => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(derive.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + const purpose: bcl.HDNode = bitbox.HDNode.deriveHardened(hdNode, 44) + const coin: bcl.HDNode = bitbox.HDNode.deriveHardened(purpose, 145) + const childHDNode: bcl.HDNode = bitbox.HDNode.deriveHardened(coin, 0) + assert.equal(bitbox.HDNode.toXPub(childHDNode), derive.xpub) + assert.equal(bitbox.HDNode.toXPriv(childHDNode), derive.xpriv) + }) + }) + }) + }) + + describe("#derivePath", (): void => { + describe("derive non hardened Path", (): void => { + fixtures.derivePath.forEach((derive: any): void => { + it(`should derive non hardened child HDNode from path`, (): void => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(derive.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + const childHDNode: bcl.HDNode = bitbox.HDNode.derivePath(hdNode, "0") + assert.equal(bitbox.HDNode.toXPub(childHDNode), derive.xpub) + assert.equal(bitbox.HDNode.toXPriv(childHDNode), derive.xpriv) + }) + }) + }) + + describe("derive hardened Path", (): any => { + fixtures.deriveHardenedPath.forEach((derive: any): any => { + it(`should derive hardened child HDNode from path`, (): any => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(derive.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + const childHDNode: bcl.HDNode = bitbox.HDNode.derivePath(hdNode, "0'") + assert.equal(bitbox.HDNode.toXPub(childHDNode), derive.xpub) + assert.equal(bitbox.HDNode.toXPriv(childHDNode), derive.xpriv) + }) + }) + }) + + describe("derive BIP44 $BCH account", (): void => { + fixtures.deriveBIP44.forEach((derive: any): void => { + it(`should derive BIP44 $BCH account`, (): void => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(derive.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + const childHDNode: bcl.HDNode = bitbox.HDNode.derivePath(hdNode, "44'/145'/0'") + assert.equal(bitbox.HDNode.toXPub(childHDNode), derive.xpub) + assert.equal(bitbox.HDNode.toXPriv(childHDNode), derive.xpriv) + }) + }) + }) + }) + + describe("#toLegacyAddress", (): void => { + fixtures.toLegacyAddress.forEach((fixture: any): void => { + it(`should get address ${fixture.address} from HDNode`, (): void => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(fixture.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + const childHDNode: bcl.HDNode = bitbox.HDNode.derivePath(hdNode, "0") + const addy: string = bitbox.HDNode.toLegacyAddress(childHDNode) + assert.equal(addy, fixture.address) + }) + }) + }) + + describe("#toCashAddress", (): void => { + fixtures.toCashAddress.forEach((fixture: any): void => { + it(`should get address ${fixture.address} from HDNode`, (): void => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(fixture.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + const childHDNode: bcl.HDNode = bitbox.HDNode.derivePath(hdNode, "0") + const addy: string = bitbox.HDNode.toCashAddress(childHDNode) + assert.equal(addy, fixture.address) + }) + + it(`should get address ${fixture.regtestAddress} from HDNode`, (): void => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(fixture.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + const childHDNode: bcl.HDNode = bitbox.HDNode.derivePath(hdNode, "0") + const addr: string = bitbox.HDNode.toCashAddress(childHDNode, true) + assert.equal(addr, fixture.regtestAddress) + }) + }) + }) + + describe("#toWIF", (): void => { + fixtures.toWIF.forEach((fixture: any): void => { + it(`should get privateKeyWIF ${ + fixture.privateKeyWIF + } from HDNode`, (): void => { + const hdNode: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + assert.equal(bitbox.HDNode.toWIF(hdNode), fixture.privateKeyWIF) + }) + }) + }) + + describe("#toXPub", (): void => { + fixtures.toXPub.forEach((fixture: any): void => { + it(`should create xpub ${fixture.xpub} from an HDNode`, (): void => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(fixture.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + const xpub: string = bitbox.HDNode.toXPub(hdNode) + assert.equal(xpub, fixture.xpub) + }) + }) + }) + + describe("#toXPriv", (): void => { + fixtures.toXPriv.forEach((fixture: any): void => { + it(`should create xpriv ${fixture.xpriv} from an HDNode`, (): void => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(fixture.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + const xpriv: string = bitbox.HDNode.toXPriv(hdNode) + assert.equal(xpriv, fixture.xpriv) + }) + }) + }) + + describe("#toKeyPair", (): void => { + fixtures.toKeyPair.forEach((fixture: any): void => { + it(`should get ECPair from an HDNode`, (): void => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(fixture.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + const keyPair: bcl.ECPair = bitbox.HDNode.toKeyPair(hdNode) + assert.equal(typeof keyPair, "object") + }) + }) + }) + + describe("#toPublicKey", (): void => { + fixtures.toPublicKey.forEach((fixture: any): void => { + it(`should create public key buffer from an HDNode`, (): void => { + const rootSeedBuffer: any = bitbox.Mnemonic.toSeed(fixture.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(rootSeedBuffer) + const publicKeyBuffer: any = bitbox.HDNode.toPublicKey(hdNode) + assert.equal(typeof publicKeyBuffer, "object") + }) + }) + }) + + describe("#fromXPriv", (): any => { + fixtures.fromXPriv.forEach((fixture: any): any => { + const hdNode: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + it(`should create HDNode from xpriv ${fixture.xpriv}`, (): any => { + assert.notEqual(hdNode, null) + }) + + it(`should export xpriv ${fixture.xpriv}`, (): any => { + assert.equal(bitbox.HDNode.toXPriv(hdNode), fixture.xpriv) + }) + + it(`should export xpub ${fixture.xpub}`, (): any => { + assert.equal(bitbox.HDNode.toXPub(hdNode), fixture.xpub) + }) + + it(`should export legacy address ${fixture.legacy}`, (): any => { + assert.equal(bitbox.HDNode.toLegacyAddress(hdNode), fixture.legacy) + }) + + it(`should export cashaddress ${fixture.cashaddress}`, (): any => { + assert.equal(bitbox.HDNode.toCashAddress(hdNode), fixture.cashaddress) + }) + + it(`should export regtest cashaddress ${fixture.regtestaddress}`, (): any => { + assert.equal( + bitbox.HDNode.toCashAddress(hdNode, true), + fixture.regtestaddress + ) + }) + + it(`should export privateKeyWIF ${fixture.privateKeyWIF}`, (): any => { + assert.equal(bitbox.HDNode.toWIF(hdNode), fixture.privateKeyWIF) + }) + }) + }) + + describe("#fromXPub", (): any => { + fixtures.fromXPub.forEach((fixture: any): any => { + const hdNode: bcl.HDNode = bitbox.HDNode.fromXPub(fixture.xpub) + it(`should create HDNode from xpub ${fixture.xpub}`, (): any => { + assert.notEqual(hdNode, null) + }) + + it(`should export xpub ${fixture.xpub}`, (): any => { + assert.equal(bitbox.HDNode.toXPub(hdNode), fixture.xpub) + }) + + it(`should export legacy address ${fixture.legacy}`, (): any => { + assert.equal(bitbox.HDNode.toLegacyAddress(hdNode), fixture.legacy) + }) + + it(`should export cashaddress ${fixture.cashaddress}`, (): any => { + assert.equal(bitbox.HDNode.toCashAddress(hdNode), fixture.cashaddress) + }) + + it(`should export regtest cashaddress ${fixture.regtestaddress}`, (): any => { + assert.equal( + bitbox.HDNode.toCashAddress(hdNode, true), + fixture.regtestaddress + ) + }) + }) + }) + + describe("#bip32", (): any => { + describe("create accounts and addresses", (): any => { + fixtures.accounts.forEach((fixture: any): any => { + const seedBuffer: any = bitbox.Mnemonic.toSeed(fixture.mnemonic) + const hdNode: bcl.HDNode = bitbox.HDNode.fromSeed(seedBuffer) + const a: bcl.HDNode = bitbox.HDNode.derivePath(hdNode, "0'") + const external: bcl.HDNode = bitbox.HDNode.derivePath(a, "0") + const account: any = bitbox.HDNode.createAccount([external]) + + it(`#createAccount`, (): void => { + assert.notEqual(account, null) + }) + + describe("#getChainAddress", (): void => { + const external1 = bitbox.Address.toCashAddress( + account.getChainAddress(0) + ) + it(`should create external change address ${external1}`, (): void => { + assert.equal(external1, fixture.externals[0]) + }) + }) + + describe("#nextChainAddress", (): void => { + for (let i: number = 0; i < 4; i++) { + const ex: string = bitbox.Address.toCashAddress(account.nextChainAddress(0)) + it(`should create external change address ${ex}`, (): void => { + assert.equal(ex, fixture.externals[i + 1]) + }) + } + }) + }) + }) + }) + + describe("#sign", (): void => { + fixtures.sign.forEach((fixture: any): void => { + it(`should sign 32 byte hash buffer`, (): void => { + const hdnode: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.privateKeyWIF) + const buf: Buffer = Buffer.from(bitbox.Crypto.sha256(Buffer.from(fixture.data, "hex"))) + const signatureBuf: any = bitbox.HDNode.sign(hdnode, buf) + assert.equal(typeof signatureBuf, "object") + }) + }) + }) + + describe("#verify", (): void => { + fixtures.verify.forEach((fixture: any): void => { + it(`should verify signed 32 byte hash buffer`, (): void => { + const hdnode1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.privateKeyWIF1) + const buf: Buffer = Buffer.from(bitbox.Crypto.sha256(Buffer.from(fixture.data, "hex"))) + const signature: Buffer = bitbox.HDNode.sign(hdnode1, buf) + const verify: boolean = bitbox.HDNode.verify(hdnode1, buf, signature) + assert.equal(verify, true) + }) + }) + }) + + describe("#isPublic", (): void => { + fixtures.isPublic.forEach((fixture: any): void => { + it(`should verify hdnode is public`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPub(fixture.xpub) + assert.equal(bitbox.HDNode.isPublic(node), true) + }) + }) + + fixtures.isPublic.forEach((fixture: any): void => { + it(`should verify hdnode is not public`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + assert.equal(bitbox.HDNode.isPublic(node), false) + }) + }) + }) + + describe("#isPrivate", (): void => { + fixtures.isPrivate.forEach((fixture: any): void => { + it(`should verify hdnode is not private`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPub(fixture.xpub) + assert.equal(bitbox.HDNode.isPrivate(node), false) + }) + }) + + fixtures.isPrivate.forEach((fixture: any): void => { + it(`should verify hdnode is private`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + assert.equal(bitbox.HDNode.isPrivate(node), true) + }) + }) + }) + + describe("#toIdentifier", (): void => { + fixtures.toIdentifier.forEach((fixture: any): void => { + it(`should get identifier of hdnode`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const publicKeyBuffer: any = bitbox.HDNode.toPublicKey(node) + const hash160: Buffer = bitbox.Crypto.hash160(publicKeyBuffer) + const identifier: Buffer = bitbox.HDNode.toIdentifier(node) + assert.equal(identifier.toString('hex'), hash160.toString("hex")) + }) + }) + }) +}) diff --git a/test/unit/Mining.ts b/test/unit/Mining.ts new file mode 100644 index 00000000..7b394e0b --- /dev/null +++ b/test/unit/Mining.ts @@ -0,0 +1,121 @@ +// imports +import * as assert from "assert"; +import axios from "axios"; +import * as sinon from "sinon"; +import { BITBOX, REST_URL } from "../../lib/BITBOX" +import { Mining } from "../../lib/Mining" + +// consts +const bitbox: BITBOX = new BITBOX() + +describe("#Mining", (): void => { + describe("#MiningConstructor", (): void => { + it("should create instance of Mining", (): void => { + const mining: Mining = new Mining() + assert.equal(mining instanceof Mining, true) + }) + + it("should have a restURL property", (): void => { + const mining: Mining = new Mining() + assert.equal(mining.restURL, REST_URL) + }) + }) + + describe("#getBlockTemplate", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it("should get block template", done => { + const data = { + data: + "01000000017f6305e3b0b05f5b57a82f4e6d4187e148bbe56a947208390e488bad36472368000000006a47304402203b0079ff5b896187feb02e2679c87ac2fb8d483b60e0721ed33601e2c0eecc700220590f8a0e1a51b53b368294861fd5fc99db3a6607d0f4e543f6217108e208c1834121024c93c841d7f576584ffbf513b7abd8283e6562669905f6554f788fce4cc67a34ffffffff0228100000000000001976a914af78709a76abc8a28e568c9210c8247dd10cff2c88ac22020000000000001976a914f339927678803f451b41400737e7dc83c6a8682188ac00000000", + txid: + "7f462d71c649a0d8cfbaa2d20d8ff86677966b308f0ac9906ee015bf4453f97a", + hash: + "7f462d71c649a0d8cfbaa2d20d8ff86677966b308f0ac9906ee015bf4453f97a", + depends: [], + fee: 226, + sigops: 2 + } + + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Mining.getBlockTemplate("") + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getMiningInfo", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it("should get mining info", done => { + const data = { + blocks: 527816, + currentblocksize: 89408, + currentblocktx: 156, + difficulty: 568757800682.7649, + blockprioritypercentage: 5, + errors: "", + networkhashps: 4347259225696976000, + pooledtx: 184, + chain: "main" + } + + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Mining.getMiningInfo() + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) + + describe("#getNetworkHashps", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it("should get network hashps", done => { + const data: number = 3586365937646890000 + + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "get").returns(resolved) + + bitbox.Mining.getNetworkHashps() + .then((result: any) => { + assert.equal(data, result) + }) + .then(done, done) + }) + }) + + describe("#submitBlock", (): void => { + // TODO finish + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + it("should TODO", done => { + const data: any = {} + + const resolved = new Promise(r => r({ data: data })) + sandbox.stub(axios, "post").returns(resolved) + + // @ts-ignore + bitbox.Mining.submitBlock() + .then((result: any) => { + assert.deepEqual(data, result) + }) + .then(done, done) + }) + }) +}) diff --git a/test/unit/Mnemonic.ts b/test/unit/Mnemonic.ts new file mode 100644 index 00000000..e7bc082b --- /dev/null +++ b/test/unit/Mnemonic.ts @@ -0,0 +1,355 @@ +// imports +import * as assert from "assert"; +import { BITBOX } from "../../lib/BITBOX" +import { Mnemonic } from "../../lib/Mnemonic" + +// consts +const bitbox: BITBOX = new BITBOX() + +// TODO: port from require to import syntax +const fixtures = require("./fixtures/Mnemonic.json") + +describe("#Mnemonic", (): void => { + describe("#MnemonicConstructor", (): void => { + it("should create instance of Mnemonic", (): void => { + const mnemonic: Mnemonic = new Mnemonic() + assert.equal(mnemonic instanceof Mnemonic, true) + }) + }) + + describe("#generate", (): void => { + it("should generate a 12 word mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(128) + assert.equal(mnemonic.split(" ").length, 12) + }) + + it("should generate a 15 word mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(160) + assert.equal(mnemonic.split(" ").length, 15) + }) + + it("should generate a 18 word mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(192) + assert.equal(mnemonic.split(" ").length, 18) + }) + + it("should generate an 21 word mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(224) + assert.equal(mnemonic.split(" ").length, 21) + }) + + it("should generate an 24 word mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(256) + assert.equal(mnemonic.split(" ").length, 24) + }) + + it("should generate an 24 word italian mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate( + 256, + bitbox.Mnemonic.wordLists().italian + ) + assert.equal(mnemonic.split(" ").length, 24) + }) + }) + + describe("#fromEntropy", (): void => { + it("should generate a 12 word mnemonic from 16 bytes of entropy", (): void => { + const rand: Buffer = bitbox.Crypto.randomBytes(16) + const mnemonic: string = bitbox.Mnemonic.fromEntropy(rand) + assert.equal(mnemonic.split(" ").length, 12) + }) + + it("should generate a 15 word mnemonic from 20 bytes of entropy", (): void => { + const rand: Buffer = bitbox.Crypto.randomBytes(20) + const mnemonic: string = bitbox.Mnemonic.fromEntropy(rand) + assert.equal(mnemonic.split(" ").length, 15) + }) + + it("should generate an 18 word mnemonic from 24 bytes of entropy", (): void => { + const rand: Buffer = bitbox.Crypto.randomBytes(24) + const mnemonic: string = bitbox.Mnemonic.fromEntropy(rand) + assert.equal(mnemonic.split(" ").length, 18) + }) + + it("should generate an 21 word mnemonic from 28 bytes of entropy", (): void => { + const rand: Buffer = bitbox.Crypto.randomBytes(28) + const mnemonic: string = bitbox.Mnemonic.fromEntropy(rand) + assert.equal(mnemonic.split(" ").length, 21) + }) + + it("should generate an 24 word mnemonic from 32 bytes of entropy", (): void => { + const rand: Buffer = bitbox.Crypto.randomBytes(32) + const mnemonic: string = bitbox.Mnemonic.fromEntropy(rand) + assert.equal(mnemonic.split(" ").length, 24) + }) + + it("should generate an 24 french word mnemonic 32 bytes of entropy", (): void => { + const rand: Buffer = bitbox.Crypto.randomBytes(32) + const mnemonic: string = bitbox.Mnemonic.fromEntropy( + rand, + bitbox.Mnemonic.wordLists().french + ) + assert.equal(mnemonic.split(" ").length, 24) + }) + + fixtures.fromEntropy.forEach((entropy: any): void => { + const mnemonic: string = bitbox.Mnemonic.fromEntropy(entropy.entropy) + it(`should convert ${entropy.entropy} to ${entropy.mnemonic}`, (): void => { + assert.equal(mnemonic, entropy.mnemonic) + }) + }) + }) + + describe("#toEntropy", (): void => { + it("should turn a 12 word mnemonic to entropy", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(128) + const entropy: Buffer = bitbox.Mnemonic.toEntropy(mnemonic) + assert.equal(entropy.length, 16) + }) + + it("should turn a 15 word mnemonic to entropy", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(160) + const entropy: Buffer = bitbox.Mnemonic.toEntropy(mnemonic) + assert.equal(entropy.length, 20) + }) + + it("should turn a 18 word mnemonic to entropy", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(192) + const entropy: Buffer = bitbox.Mnemonic.toEntropy(mnemonic) + assert.equal(entropy.length, 24) + }) + + it("should turn a 21 word mnemonic to entropy", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(224) + const entropy: Buffer = bitbox.Mnemonic.toEntropy(mnemonic) + assert.equal(entropy.length, 28) + }) + + it("should turn a 24 word mnemonic to entropy", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(256) + const entropy: Buffer = bitbox.Mnemonic.toEntropy(mnemonic) + assert.equal(entropy.length, 32) + }) + + it("should turn a 24 word spanish mnemonic to entropy", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate( + 256, + bitbox.Mnemonic.wordLists().spanish + ) + const entropy: Buffer = bitbox.Mnemonic.toEntropy( + mnemonic, + bitbox.Mnemonic.wordLists().spanish + ) + assert.equal(entropy.length, 32) + }) + + fixtures.fromEntropy.forEach((fixture: any): void => { + const entropy: Buffer = bitbox.Mnemonic.toEntropy(fixture.mnemonic) + it(`should convert ${fixture.mnemonic} to ${fixture.entropy}`, (): void => { + assert.equal(entropy.toString("hex"), fixture.entropy) + }) + }) + }) + + describe("#validate", (): void => { + it("fails for a mnemonic that is too short", (): void => { + assert.equal( + bitbox.Mnemonic.validate( + "mixed winner", + bitbox.Mnemonic.wordLists().english + ), + "Invalid mnemonic" + ) + }) + + it("fails for a mnemonic that is too long", (): void => { + assert.equal( + bitbox.Mnemonic.validate( + "mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake mixed winner decide drift danger together twice planet impose asthma catch require select mask awkward spy relief front work solar pitch economy render cake", + bitbox.Mnemonic.wordLists().english + ), + "Invalid mnemonic" + ) + }) + + it("fails if mnemonic words are not in the word list", (): void => { + assert.equal( + bitbox.Mnemonic.validate( + "failsauce one two three four five six seven eight nine ten eleven", + bitbox.Mnemonic.wordLists().english + ), + "failsauce is not in wordlist, did you mean balance?" + ) + }) + + it("validate a 128 bit mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(128) + assert.equal( + bitbox.Mnemonic.validate(mnemonic, bitbox.Mnemonic.wordLists().english), + "Valid mnemonic" + ) + }) + + it("validate a 160 bit mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(160) + assert.equal( + bitbox.Mnemonic.validate(mnemonic, bitbox.Mnemonic.wordLists().english), + "Valid mnemonic" + ) + }) + + it("validate a 192 bit mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(192) + assert.equal( + bitbox.Mnemonic.validate(mnemonic, bitbox.Mnemonic.wordLists().english), + "Valid mnemonic" + ) + }) + + it("validate a 224 bit mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(224) + assert.equal( + bitbox.Mnemonic.validate(mnemonic, bitbox.Mnemonic.wordLists().english), + "Valid mnemonic" + ) + }) + + it("validate a 256 bit mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(256) + assert.equal( + bitbox.Mnemonic.validate(mnemonic, bitbox.Mnemonic.wordLists().english), + "Valid mnemonic" + ) + }) + + it("validate a 256 bit chinese simplified mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate( + 256, + bitbox.Mnemonic.wordLists().chinese_simplified + ) + assert.equal( + bitbox.Mnemonic.validate( + mnemonic, + bitbox.Mnemonic.wordLists().chinese_simplified + ), + "Valid mnemonic" + ) + }) + }) + + describe("#toSeed", (): void => { + it("should create 512 bit / 64 byte HMAC-SHA512 root seed from a 128 bit mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(128) + const rootSeedBuffer: Buffer = bitbox.Mnemonic.toSeed(mnemonic, "") + assert.equal(rootSeedBuffer.byteLength, 64) + }) + + it("should create 512 bit / 64 byte HMAC-SHA512 root seed from a 160 bit mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(160) + const rootSeedBuffer: Buffer = bitbox.Mnemonic.toSeed(mnemonic, "") + assert.equal(rootSeedBuffer.byteLength, 64) + }) + + it("should create 512 bit / 64 byte HMAC-SHA512 root seed from a 192 bit mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(192) + const rootSeedBuffer: Buffer = bitbox.Mnemonic.toSeed(mnemonic, "") + assert.equal(rootSeedBuffer.byteLength, 64) + }) + + it("should create 512 bit / 64 byte HMAC-SHA512 root seed from a 224 bit mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(224) + const rootSeedBuffer: Buffer = bitbox.Mnemonic.toSeed(mnemonic, "") + assert.equal(rootSeedBuffer.byteLength, 64) + }) + + it("should create 512 bit / 64 byte HMAC-SHA512 root seed from a 256 bit mnemonic", (): void => { + const mnemonic: string = bitbox.Mnemonic.generate(256) + const rootSeedBuffer: Buffer = bitbox.Mnemonic.toSeed(mnemonic, "") + assert.equal(rootSeedBuffer.byteLength, 64) + }) + }) + + describe("#wordLists", (): void => { + it("return a list of 2048 english words", (): void => { + assert.equal(bitbox.Mnemonic.wordLists().english.length, 2048) + }) + + it("return a list of 2048 japanese words", (): void => { + assert.equal(bitbox.Mnemonic.wordLists().japanese.length, 2048) + }) + + it("return a list of 2048 chinese simplified words", (): void => { + assert.equal(bitbox.Mnemonic.wordLists().chinese_simplified.length, 2048) + }) + + it("return a list of 2048 chinese traditional words", (): void => { + assert.equal(bitbox.Mnemonic.wordLists().chinese_traditional.length, 2048) + }) + + it("return a list of 2048 french words", (): void => { + assert.equal(bitbox.Mnemonic.wordLists().french.length, 2048) + }) + + it("return a list of 2048 italian words", (): void => { + assert.equal(bitbox.Mnemonic.wordLists().italian.length, 2048) + }) + + it("return a list of 2048 korean words", (): void => { + assert.equal(bitbox.Mnemonic.wordLists().korean.length, 2048) + }) + + it("return a list of 2048 spanish words", (): void => { + assert.equal(bitbox.Mnemonic.wordLists().spanish.length, 2048) + }) + }) + + describe("#toKeypairs", (): void => { + fixtures.toKeypairs.forEach((fixture: any, i: number): void => { + const keypairs: any = bitbox.Mnemonic.toKeypairs(fixture.mnemonic, 5) + keypairs.forEach((keypair: any, j: number): void => { + it(`Generate keypair from mnemonic`, (): void => { + assert.equal( + keypair.privateKeyWIF, + fixtures.toKeypairs[i].output[j].privateKeyWIF + ) + // assert.equal( + // keypair.address, + // fixtures.toKeypairs[i].output[j].address + // ) + }) + }) + + const regtestKeypairs: any = bitbox.Mnemonic.toKeypairs( + fixture.mnemonic, + 5, + true + ) + regtestKeypairs.forEach((keypair: any, j: number): void => { + it(`Generate keypair from mnemonic`, (): void => { + assert.equal( + keypair.privateKeyWIF, + fixtures.toKeypairs[i].output[j].privateKeyWIFRegTest + ) + // assert.equal( + // keypair.address, + // fixtures.toKeypairs[i].output[j].regtestAddress + // ) + }) + }) + }) + }) + + describe("#findNearestWord", (): void => { + fixtures.findNearestWord.forEach((fixture: any): void => { + const word: string = bitbox.Mnemonic.findNearestWord( + fixture.word, + bitbox.Mnemonic.wordLists()[fixture.language] + ) + it(`find word ${fixture.foundWord} near ${fixture.word} in ${ + fixture.language + }`, (): void => { + assert.equal(word, fixture.foundWord) + }) + }) + }) +}) diff --git a/test/unit/Price.ts b/test/unit/Price.ts new file mode 100644 index 00000000..093a3e1d --- /dev/null +++ b/test/unit/Price.ts @@ -0,0 +1,39 @@ +// imports +import * as chai from "chai" +import { BITBOX } from "../../lib/BITBOX" +import { Price } from "../../lib/Price" +import axios from "axios" +import * as sinon from "sinon" + +// consts +const bitbox: BITBOX = new BITBOX() +const assert: Chai.AssertStatic = chai.assert + +describe("#Price", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + describe("#PriceConstructor", (): void => { + it("should create instance of Price", (): void => { + const price: Price = new Price() + assert.equal(price instanceof Price, true) + }) + }) + + describe("#current", (): void => { + describe("#single currency", (): void => { + it("should get current price for single currency", async () => { + // Mock out data for unit test, to prevent live network call. + const data: any = 39229 + const resolved: any = new Promise(r => r({ data: { price: data } })) + sandbox.stub(axios, "get").returns(resolved) + + const result = await bitbox.Price.current("usd") + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isNumber(result) + }) + }) + }) +}) diff --git a/test/unit/RawTransactions.ts b/test/unit/RawTransactions.ts new file mode 100644 index 00000000..296623af --- /dev/null +++ b/test/unit/RawTransactions.ts @@ -0,0 +1,379 @@ +// imports +import { + DecodeRawTransactionResult, + VerboseRawTransactionResult +} from "bitcoin-com-rest" +import * as chai from "chai" +import * as util from "util" +import { BITBOX, REST_URL } from "../../lib/BITBOX" +import { RawTransactions } from "../../lib/RawTransactions" +import axios from "axios" +import * as sinon from "sinon" + +// consts +const bitbox: BITBOX = new BITBOX() +const assert: Chai.AssertStatic = chai.assert +const rtMock = require("./mocks/rawtransactions-mock") + +// Used for debugging +util.inspect.defaultOptions = { depth: 1 } + +describe("#RawTransactions", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + describe("#RawTransactionsConstructor", (): void => { + it("should create instance of RawTransactions", (): void => { + const rawtransactions: RawTransactions = new RawTransactions() + assert.equal(rawtransactions instanceof RawTransactions, true) + }) + + it("should have a restURL property", (): void => { + const rawtransactions: RawTransactions = new RawTransactions() + assert.equal(rawtransactions.restURL, REST_URL) + }) + }) + + describe("#decodeRawTransaction", (): void => { + it("should decode tx for a single hex", async (): Promise => { + // Mock the call to rest to prevent live network calls. + const resolved = new Promise(r => r({ data: rtMock.decodedTx })) + sandbox.stub(axios, "get").returns(resolved) + + const hex: string = + "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000" + + const result: + | DecodeRawTransactionResult + | DecodeRawTransactionResult[] = await bitbox.RawTransactions.decodeRawTransaction( + hex + ) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.hasAnyKeys(result, [ + "txid", + "hash", + "size", + "version", + "locktime", + "vin", + "vout" + ]) + if (!Array.isArray(result)) { + assert.isArray(result.vin) + assert.isArray(result.vout) + } + }) + + it("should decode an array of tx hexes", async (): Promise => { + // Mock the call to rest to prevent live network calls. + const testData = [rtMock.decodedTx, rtMock.decodedTx] + const resolved = new Promise(r => r({ data: testData })) + sandbox.stub(axios, "post").returns(resolved) + + const hexes: string[] = [ + "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000", + "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000" + ] + + const result: + | DecodeRawTransactionResult + | DecodeRawTransactionResult[] = await bitbox.RawTransactions.decodeRawTransaction( + hexes + ) + + assert.isArray(result) + if (Array.isArray(result)) { + assert.hasAnyKeys(result[0], [ + "txid", + "hash", + "size", + "version", + "locktime", + "vin", + "vout" + ]) + assert.isArray(result[0].vin) + assert.isArray(result[0].vout) + } + }) + + it(`should pass error from server to user`, async (): Promise => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws("error", "Input must be a string or array of strings") + + const addr: any = 12345 + + await bitbox.RawTransactions.decodeRawTransaction(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: ${util.inspect(err)}`) + assert.include( + err.message, + `Input must be a string or array of strings` + ) + } + }) + }) + + describe("#getRawTransaction", (): void => { + it("should decode a single txid, with concise output", async (): Promise< + any + > => { + // Mock the call to rest to prevent live network calls. + const resolved = new Promise(r => r({ data: rtMock.rawTx })) + sandbox.stub(axios, "get").returns(resolved) + + const txid: string = + "23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1" + const verbose: boolean = false + + const result: + | VerboseRawTransactionResult + | VerboseRawTransactionResult[] + | string + | string[] = await bitbox.RawTransactions.getRawTransaction( + txid, + verbose + ) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.isString(result) + }) + + it("should decode a single txid, with verbose output", async (): Promise< + any + > => { + // Mock the call to rest to prevent live network calls. + const resolved = new Promise(r => r({ data: rtMock.decodedTx })) + sandbox.stub(axios, "get").returns(resolved) + + const txid: string = + "23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1" + const verbose: boolean = true + + const result: + | VerboseRawTransactionResult + | VerboseRawTransactionResult[] + | string + | string[] = await bitbox.RawTransactions.getRawTransaction( + txid, + verbose + ) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.hasAnyKeys(result, [ + "hex", + "txid", + "hash", + "size", + "version", + "locktime", + "vin", + "vout", + "blockhash", + "confirmations", + "time", + "blocktime" + ]) + if (!Array.isArray(result) && result instanceof Object) { + assert.isArray(result.vin) + assert.isArray(result.vout) + } + }) + + it("should decode an array of txids, with a concise output", async (): Promise< + any + > => { + // Mock the call to rest to prevent live network calls. + const testData = [rtMock.rawTx, rtMock.rawTx] + const resolved = new Promise(r => r({ data: testData })) + sandbox.stub(axios, "post").returns(resolved) + + const txid: string[] = [ + "23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1", + "b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f" + ] + const verbose: boolean = false + + const result: + | VerboseRawTransactionResult + | VerboseRawTransactionResult[] + | string + | string[] = await bitbox.RawTransactions.getRawTransaction( + txid, + verbose + ) + + assert.isArray(result) + if (Array.isArray(result)) assert.isString(result[0]) + }) + + it("should decode an array of txids, with a verbose output", async (): Promise< + any + > => { + // Mock the call to rest to prevent live network calls. + const testData = [rtMock.decodedTx, rtMock.decodedTx] + const resolved = new Promise(r => r({ data: testData })) + sandbox.stub(axios, "post").returns(resolved) + + const txid: string[] = [ + "23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1", + "b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f" + ] + const verbose: boolean = true + + const result: + | VerboseRawTransactionResult + | VerboseRawTransactionResult[] + | string + | string[] = await bitbox.RawTransactions.getRawTransaction( + txid, + verbose + ) + + assert.isArray(result) + if (Array.isArray(result)) { + assert.hasAnyKeys(result[0], [ + "hex", + "txid", + "hash", + "size", + "version", + "locktime", + "vin", + "vout", + "blockhash", + "confirmations", + "time", + "blocktime" + ]) + // TODO uncomment this test and fix ts error + // assert.isArray(result[0].vin); + // assert.isArray(result[0].vout); + } + }) + + it(`should pass error from server to user`, async (): Promise => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws("error", "Input must be a string or array of strings") + + const txid: any = 12345 + + await bitbox.RawTransactions.getRawTransaction(txid, false) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: ${util.inspect(err)}`) + assert.include( + err.message, + `Input must be a string or array of strings` + ) + } + }) + }) + + describe("#decodeScript", () => { + it("should decode script for a single hex", async (): Promise => { + // Mock the call to rest to prevent live network calls. + const resolved = new Promise(r => r({ data: rtMock.decodedScript })) + sandbox.stub(axios, "get").returns(resolved) + + const hex: string = + "4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16" + + const result = await bitbox.RawTransactions.decodeScript(hex) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.hasAllKeys(result, ["asm", "type", "p2sh"]) + }) + + it("should decode an array of tx hexes", async () => { + // Mock the call to rest to prevent live network calls. + const testData = [rtMock.decodedScript, rtMock.decodedScript] + const resolved = new Promise(r => r({ data: testData })) + sandbox.stub(axios, "post").returns(resolved) + + const hexes = [ + "4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16", + "4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16" + ] + + const result = await bitbox.RawTransactions.decodeScript(hexes) + //console.log(`result ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.hasAnyKeys(result[0], ["asm", "type", "p2sh"]) + }) + + it(`should pass error from server to user`, async (): Promise => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws("error", "Input must be a string or array of strings") + + const hexes: any = 12345 + + await bitbox.RawTransactions.decodeScript(hexes) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: ${util.inspect(err)}`) + assert.include( + err.message, + `Input must be a string or array of strings` + ) + } + }) + }) + + /* + Testing sendRawTransaction isn't really possible with an integration test, + as the endpoint really needs an e2e test to be properly tested. The tests + below expect error messages returned from the server, but at least test + that the server is responding on those endpoints, and responds consistently. + */ + describe("sendRawTransaction", () => { + it("should send a single transaction hex", async (): Promise => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox.stub(axios, "get").throws({ error: "Missing inputs" }) + + const hex: string = + "01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000" + + await bitbox.RawTransactions.sendRawTransaction(hex) + + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: ${util.inspect(err)}`) + assert.hasAllKeys(err, ["error"]) + assert.include(err.error, "Missing inputs") + } + }) + + it("should send an array of tx hexes", async (): Promise => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox.stub(axios, "post").throws({ error: "Missing inputs" }) + + const hexes: string[] = [ + "01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000", + "01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000" + ] + + const result = await bitbox.RawTransactions.sendRawTransaction(hexes) + } catch (err) { + // console.log(`err: ${util.inspect(err)}`) + assert.hasAllKeys(err, ["error"]) + assert.include(err.error, "Missing inputs") + } + }) + }) +}) diff --git a/test/unit/Script.ts b/test/unit/Script.ts new file mode 100644 index 00000000..3da586ef --- /dev/null +++ b/test/unit/Script.ts @@ -0,0 +1,450 @@ +// imports +import * as assert from "assert"; +import { BITBOX } from "../../lib/BITBOX" +import { Script, DecodedP2PKHInput, DecodedP2MSOutput } from "../../lib/Script" +import * as bcl from "bitcoincashjs-lib" + +// consts +const bitbox: BITBOX = new BITBOX() + +// TODO: port from require to import syntax +const fixtures = require("./fixtures/Script.json") + +describe("#Script", (): void => { + describe("#ScriptConstructor", (): void => { + it("should create instance of Script", (): void => { + const script: Script = new Script() + assert.equal(script instanceof Script, true) + }) + }) + + describe("#decode", (): void => { + describe("P2PKH scriptSig", (): void => { + fixtures.decodeScriptSig.forEach((fixture: any): void => { + it(`should decode scriptSig buffer`, (): void => { + const decodedScriptSig: any[] = bitbox.Script.decode( + Buffer.from(fixture.scriptSigHex, "hex") + ) + assert.equal(typeof decodedScriptSig, "object") + }) + + it(`should decode scriptSig buffer to cash address ${ + fixture.cashAddress + }`, (): void => { + const decodedScriptSig: any[] = bitbox.Script.decode( + Buffer.from(fixture.scriptSigHex, "hex") + ) + const address: string = bitbox.HDNode.toCashAddress( + bitbox.ECPair.fromPublicKey(decodedScriptSig[1]) + ) + assert.equal(address, fixture.cashAddress) + }) + + it(`should decode scriptSig buffer to legacy address ${ + fixture.legacyAddress + }`, (): void => { + const decodedScriptSig: any[] = bitbox.Script.decode( + Buffer.from(fixture.scriptSigHex, "hex") + ) + const address: string = bitbox.HDNode.toLegacyAddress( + bitbox.ECPair.fromPublicKey(decodedScriptSig[1]) + ) + assert.equal(address, fixture.legacyAddress) + }) + }) + }) + + describe("P2PKH scriptPubKey", (): void => { + fixtures.decodeScriptPubKey.forEach((fixture: any): void => { + it(`should decode scriptSig buffer`, (): void => { + const decodedScriptPubKey: any[] = bitbox.Script.decode( + Buffer.from(fixture.scriptPubKeyHex, "hex") + ) + assert.equal(decodedScriptPubKey.length, 5) + }) + + it(`should match hashed pubKey ${fixture.pubKeyHex}`, (): void => { + const decodedScriptPubKey: any[] = bitbox.Script.decode( + Buffer.from(fixture.scriptPubKeyHex, "hex") + ) + const data: Buffer = Buffer.from(fixture.pubKeyHex, "hex") + const hash160: Buffer = bitbox.Crypto.hash160(data) + assert.equal(decodedScriptPubKey[2].toString("hex"), hash160.toString("hex")) + }) + }) + }) + }) + + describe("#encode", (): void => { + describe("P2PKH scriptSig", (): void => { + fixtures.encodeScriptSig.forEach((fixture: any): void => { + it(`should encode scriptSig chunks to buffer`, (): void => { + const arr: Buffer[] = [ + Buffer.from(fixture.scriptSigChunks[0], "hex"), + Buffer.from(fixture.scriptSigChunks[1], "hex") + ] + const encodedScriptSig: any = bitbox.Script.encode(arr) + assert.equal(typeof encodedScriptSig, "object") + }) + }) + }) + + describe("P2PKH scriptPubKey", (): void => { + fixtures.encodeScriptPubKey.forEach((fixture: any): void => { + it(`should encode scriptPubKey buffer`, (): void => { + const decodedScriptPubKey: any[] = bitbox.Script.decode( + Buffer.from(fixture.scriptPubKeyHex, "hex") + ) + const compiledScriptPubKey: any = bitbox.Script.encode(decodedScriptPubKey) + assert.equal( + compiledScriptPubKey.toString("hex"), + fixture.scriptPubKeyHex + ) + }) + }) + }) + }) + + describe("#toASM", (): void => { + describe("P2PKH scriptSig", (): void => { + fixtures.scriptSigToASM.forEach((fixture: any): void => { + it(`should encode scriptSig buffer to ${fixture.asm}`, (): void => { + const arr: Buffer[] = [ + Buffer.from(fixture.scriptSigChunks[0], "hex"), + Buffer.from(fixture.scriptSigChunks[1], "hex") + ] + const compiledScriptSig: any = bitbox.Script.encode(arr) + const asm: string = bitbox.Script.toASM(compiledScriptSig) + assert.equal(asm, fixture.asm) + }) + }) + }) + + describe("P2PKH scriptPubKey", (): void => { + fixtures.scriptPubKeyToASM.forEach((fixture: any): void => { + it(`should compile scriptPubKey buffer to ${fixture.asm}`, (): void => { + const asm: string = bitbox.Script.toASM( + Buffer.from(fixture.scriptPubKeyHex, "hex") + ) + assert.equal(asm, fixture.asm) + }) + }) + }) + }) + + describe("#fromASM", (): void => { + describe("P2PKH scriptSig", (): void => { + fixtures.scriptSigFromASM.forEach((fixture: any): void => { + it(`should decode scriptSig asm to buffer`, (): void => { + const buf: Buffer = bitbox.Script.fromASM(fixture.asm) + assert.equal(typeof buf, "object") + }) + }) + }) + + describe("P2PKH scriptPubKey", (): void => { + fixtures.scriptPubKeyFromASM.forEach((fixture: any): void => { + it(`should decode scriptPubKey asm to buffer`, (): void => { + const buf: Buffer = bitbox.Script.fromASM(fixture.asm) + assert.equal(typeof buf, "object") + }) + }) + }) + }) + + describe("#OPCodes", (): void => { + for (const opcode in fixtures.opcodes) { + it(`should have OP Code ${opcode}`, (): void => { + // @ts-ignore + assert.equal(bitbox.Script.opcodes[opcode], fixtures.opcodes[opcode]) + }) + } + }) + + describe("#classifyInput", (): void => { + fixtures.classifyInput.forEach((fixture: any): void => { + it(`should classify input type ${fixture.type}`, (): void => { + const type: string = bitbox.Script.classifyInput( + bitbox.Script.fromASM(fixture.script) + ) + assert.equal(type, fixture.type) + }) + }) + }) + + describe("#classifyOutput", (): void => { + fixtures.classifyOutput.forEach((fixture: any): void => { + it(`should classify ouput type ${fixture.type}`, (): void => { + const type: string = bitbox.Script.classifyOutput( + bitbox.Script.fromASM(fixture.script) + ) + assert.equal(type, fixture.type) + }) + }) + }) + + describe("#nullDataTemplate", (): void => { + fixtures.nullDataTemplate.forEach((fixture: any): void => { + it(`should encode nulldata output`, (): void => { + let buf: Buffer = Buffer.from(fixture.data, "ascii") + const encoded: Buffer = bitbox.Script.encodeNullDataOutput(buf) + assert.equal(encoded.toString("hex"), fixture.hex) + }) + + it(`should decode nulldata output`, (): void => { + let buf: Buffer = Buffer.from(fixture.hex, "hex") + const decoded: Buffer = bitbox.Script.decodeNullDataOutput(buf) + assert.equal(decoded.toString("ascii"), fixture.data) + }) + + it(`should confirm correctly formatted nulldata output`, (): void => { + let buf: Buffer = Buffer.from(fixture.data, "ascii") + const encoded: Buffer = bitbox.Script.encodeNullDataOutput(buf) + const valid: boolean = bitbox.Script.checkNullDataOutput(encoded) + assert.equal(valid, true) + }) + }) + }) + + describe("#pubKeyTemplate", (): void => { + describe("#pubKeyInputTemplate", (): void => { + fixtures.pubKeyInputTemplate.forEach((fixture: any): void => { + it(`should encode pubKey input`, (): void => { + const buf: Buffer = bitbox.Script.encodeP2PKInput( + Buffer.from(fixture.signature, "hex") + ) + assert.equal(buf.toString("hex"), fixture.hex) + }) + + it(`should decode pubKey input`, (): void => { + const buf: Buffer = bitbox.Script.pubKey.input.decode( + Buffer.from(fixture.hex, "hex") + ) + assert.equal(buf.toString("hex"), fixture.signature) + }) + + it(`should confirm correctly formatted pubKeyHash input`, (): void => { + const buf: Buffer = bitbox.Script.encodeP2PKInput( + Buffer.from(fixture.signature, "hex") + ) + const valid: boolean = bitbox.Script.pubKey.input.check(buf) + assert.equal(valid, true) + }) + }) + }) + + describe("#pubKeyOutputTemplate", (): void => { + fixtures.pubKeyOutputTemplate.forEach((fixture: any): void => { + it(`should encode pubKey output`, (): void => { + const buf: Buffer = Buffer.from(fixture.pubKey, "hex") + const encoded: Buffer = bitbox.Script.encodeP2PKOutput(buf) + assert.equal(encoded.toString("hex"), fixture.hex) + }) + + it(`should decode pubKey output`, (): void => { + const buf: Buffer = Buffer.from(fixture.hex, "hex") + const decoded: Buffer = bitbox.Script.decodeP2PKOutput(buf) + assert.equal(decoded.toString("hex"), fixture.pubKey) + }) + + it(`should confirm correctly formatted pubKey output`, (): void => { + const buf: Buffer = Buffer.from(fixture.pubKey, "hex") + const encoded: Buffer = bitbox.Script.encodeP2PKOutput(buf) + const valid: boolean = bitbox.Script.checkP2PKOutput(encoded) + assert.equal(valid, true) + }) + }) + }) + }) + + describe("#pubKeyHashTemplate", (): void => { + describe("#pubKeyHashInputTemplate", (): void => { + fixtures.pubKeyHashInputTemplate.forEach((fixture: any): void => { + it(`should encode pubKeyHash input`, (): void => { + const sigBuf = Buffer.from(fixture.signature, 'hex') + const pubKeyBuf = Buffer.from(fixture.pubKey, 'hex') + const encoded: Buffer = bitbox.Script.encodeP2PKHInput(sigBuf, pubKeyBuf) + assert.equal(encoded.toString("hex"), fixture.hex) + }) + + it(`should decode pubKeyHash input signature`, (): void => { + const input: Buffer = Buffer.from(fixture.hex, "hex") + const buf: DecodedP2PKHInput = bitbox.Script.decodeP2PKHInput(input) + assert.equal(buf.signature.toString("hex"), fixture.signature) + }) + + it(`should decode pubKeyHash input pubkey`, (): void => { + const input: Buffer = Buffer.from(fixture.hex, "hex") + const buf: DecodedP2PKHInput = bitbox.Script.decodeP2PKHInput(input) + assert.equal(buf.pubKey.toString("hex"), fixture.pubKey) + }) + + it(`should confirm correctly formatted pubKeyHash input`, (): void => { + const sigBuf = Buffer.from(fixture.signature, 'hex') + const pubKeyBuf = Buffer.from(fixture.pubKey, 'hex') + const encoded: Buffer = bitbox.Script.encodeP2PKHInput(sigBuf, pubKeyBuf) + const valid: boolean = bitbox.Script.checkP2PKHInput(encoded) + assert.equal(valid, true) + }) + }) + }) + + describe("#pubKeyHashOutputTemplate", (): void => { + fixtures.pubKeyHashOutputTemplate.forEach((fixture: any): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const identifier: Buffer = bitbox.HDNode.toIdentifier(node) + it(`should encode pubKeyHash output`, (): void => { + const output: Buffer = bitbox.Script.encodeP2PKHOutput(identifier) + assert.equal(output.toString("hex"), fixture.hex) + }) + + it(`should decode pubKeyHash output`, (): void => { + let output: Buffer = Buffer.from(`${fixture.hex}`, "hex") + const decoded: Buffer = bitbox.Script.pubKeyHash.output.decode(output) + assert.equal(decoded.toString("hex"), identifier.toString("hex")) + }) + + it(`should confirm correctly formatted pubKeyHash output`, (): void => { + const buf: Buffer = bitbox.Script.pubKeyHash.output.encode(identifier) + const valid: boolean = bitbox.Script.pubKeyHash.output.check(buf) + assert.equal(valid, true) + }) + }) + }) + }) + + describe("#multisigTemplate", (): void => { + describe("#multisigInputTemplate", (): void => { + fixtures.multisigInputTemplate.forEach((fixture: any): void => { + it(`should encode multisig input`, (): void => { + const signatures: Buffer[] = fixture.signatures.map((signature: any) => + Buffer.from(signature, "hex") + ) + const input: Buffer = bitbox.Script.encodeP2MSInput(signatures) + assert.equal(input.toString("hex"), fixture.hex) + }) + + it(`should decode multisig input`, (): void => { + const output: Buffer = Buffer.from(fixture.hex, "hex") + const decoded: Buffer[] = bitbox.Script.decodeP2MSInput(output) + assert.equal(decoded[0].toString("hex"), fixture.signatures[0]) + }) + + it(`should confirm correctly formatted multisig input`, (): void => { + const signatures: Buffer[] = fixture.signatures.map((signature: any) => + Buffer.from(signature, "hex") + ) + const input: Buffer = bitbox.Script.encodeP2MSInput(signatures) + const valid: boolean = bitbox.Script.checkP2MSInput(input) + assert.equal(valid, true) + }) + }) + }) + + describe("#multisigOutputTemplate", (): void => { + fixtures.multisigOutputTemplate.forEach((fixture: any): void => { + it(`should encode multisig output`, (): void => { + const pubKeys: Buffer[] = fixture.pubKeys.map((p: string) => Buffer.from(p, "hex")) + const m: number = pubKeys.length + const output: Buffer = bitbox.Script.encodeP2MSOutput(m, pubKeys) + + assert.equal(output.toString("hex"), fixture.hex) + }) + + it(`should decode multisig output`, (): void => { + const output: Buffer = Buffer.from(`${fixture.hex}`, "hex") + const decoded: DecodedP2MSOutput = bitbox.Script.decodeP2MSOutput(output) + assert.equal(decoded.m, fixture.pubKeys.length) + }) + + it(`should confirm correctly formatted multisig output`, (): void => { + const pubKeys: Buffer[] = fixture.pubKeys.map((p: any) => Buffer.from(p, "hex")) + const m: number = pubKeys.length + const output: Buffer = bitbox.Script.encodeP2MSOutput(m, pubKeys) + const valid: boolean = bitbox.Script.checkP2MSOutput(output) + assert.equal(valid, true) + }) + }) + }) + }) + + describe("#scriptHashTemplate", (): void => { + describe("#scriptHashInputTemplate", (): void => { + fixtures.scriptHashInputTemplate.forEach((fixture: any): void => { + it(`should encode scriptHash input`, (): void => { + const redeemScriptSig: Buffer = bitbox.Script.fromASM(fixture.redeemScriptSig) + const redeemScript: Buffer = bitbox.Script.fromASM(fixture.redeemScript) + const input: Buffer = bitbox.Script.encodeP2SHInput(redeemScriptSig, redeemScript) + assert.equal(input.toString("hex"), fixture.hex) + }) + + it(`should decode scriptHash input`, (): void => { + const redeemScriptSig: Buffer = bitbox.Script.fromASM(fixture.redeemScriptSig) + const redeemScript: Buffer = bitbox.Script.fromASM(fixture.redeemScript) + const input: Buffer = bitbox.Script.encodeP2SHInput(redeemScriptSig, redeemScript) + assert.deepEqual( + bitbox.Script.decodeP2SHInput(input), + { + redeemScriptSig: redeemScriptSig, + redeemScript: redeemScript + } + ) + }) + + it(`should confirm correctly formatted scriptHash input`, (): void => { + const redeemScriptSig: Buffer = bitbox.Script.fromASM(fixture.redeemScriptSig) + const redeemScript: Buffer = bitbox.Script.fromASM(fixture.redeemScript) + const input: Buffer = bitbox.Script.encodeP2SHInput(redeemScriptSig, redeemScript) + const valid: boolean = bitbox.Script.scriptHash.input.check(input) + assert.equal(valid, true) + }) + }) + }) + + describe("#scriptHashOutputTemplate", (): void => { + fixtures.scriptHashOutputTemplate.forEach((fixture: any): void => { + it(`should encode scriptHash output`, (): void => { + const redeemScript: Buffer = bitbox.Script.fromASM(fixture.output) + const scriptHash: Buffer = bitbox.Crypto.hash160(redeemScript) + const output: Buffer = bitbox.Script.encodeP2SHOutput(scriptHash) + + assert.equal(output.toString("hex"), fixture.hex) + }) + + it(`should decode scriptHash output`, (): void => { + const redeemScript: any = bitbox.Script.fromASM(fixture.output) + const scriptHash: Buffer = bitbox.Crypto.hash160(redeemScript) + const output: Buffer = bitbox.Script.encodeP2SHOutput(scriptHash) + let decoded: Buffer = bitbox.Script.decodeP2SHOutput(output) + assert.deepEqual(decoded, scriptHash) + }) + + it(`should confirm correctly formatted scriptHash output`, (): void => { + const redeemScript: any = bitbox.Script.fromASM(fixture.output) + const scriptHash: Buffer = bitbox.Crypto.hash160(redeemScript) + const buf: Buffer = bitbox.Script.encodeP2SHOutput(scriptHash) + const valid: boolean = bitbox.Script.scriptHash.output.check(buf) + assert.equal(valid, true) + }) + }) + }) + }) + + describe("#number", (): void => { + fixtures.scriptNumber.forEach((fixture: any): void => { + it(`should encode number ${fixture.decoded} as bytes ${fixture.encoded}`, (): void => { + const encoded1 = bitbox.Script.number.encode(fixture.decoded) + const encoded2 = bitbox.Script.encodeNumber(fixture.decoded) + assert.equal(encoded1.toString("hex"), fixture.encoded) + assert.equal(encoded2.toString("hex"), fixture.encoded) + }) + + it(`should decode bytes ${fixture.encoded} as number ${fixture.decoded}`, (): void => { + const decoded1 = bitbox.Script.number.decode(Buffer.from(fixture.encoded, 'hex')) + const decoded2 = bitbox.Script.decodeNumber(Buffer.from(fixture.encoded, 'hex')) + assert.equal(decoded1, fixture.decoded) + assert.equal(decoded2, fixture.decoded) + }) + }) + }) +}) diff --git a/test/unit/Transaction.ts b/test/unit/Transaction.ts new file mode 100644 index 00000000..307987ee --- /dev/null +++ b/test/unit/Transaction.ts @@ -0,0 +1,99 @@ +// imports +import * as chai from "chai" +import { TxnDetailsResult } from "bitcoin-com-rest" +import axios from "axios" +import * as sinon from "sinon" + +import { BITBOX, REST_URL } from "../../lib/BITBOX" +import { Transaction } from "../../lib/Transaction" + +// consts +const bitbox: BITBOX = new BITBOX() +const assert: Chai.AssertStatic = chai.assert +const mockData = require("./mocks/transactions-mock") + +describe("#Transaction", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + describe("#TransactionConstructor", (): void => { + it("should create instance of Transaction", (): void => { + const transaction: Transaction = new Transaction() + assert.equal(transaction instanceof Transaction, true) + }) + + it("should have a restURL property", (): void => { + const transaction: Transaction = new Transaction() + assert.equal(transaction.restURL, REST_URL) + }) + }) + + describe(`#details`, (): void => { + it(`should GET details for a given txid`, async (): Promise => { + // Mock the call to rest to prevent live network calls. + const resolved = new Promise(r => r({ data: mockData.details })) + sandbox.stub(axios, "get").returns(resolved) + + const txid: string = + "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33" + + const result: + | TxnDetailsResult + | TxnDetailsResult[] = await bitbox.Transaction.details(txid) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, [ + "txid", + "version", + "locktime", + "vin", + "vout", + "blockhash", + "blockheight", + "confirmations", + "time", + "blocktime", + "isCoinBase", + "valueOut", + "size" + ]) + }) + + it(`should GET details for an array of txids`, async () => { + // Mock the call to rest to prevent live network calls. + const testData = [mockData.details, mockData.details] + const resolved = new Promise(r => r({ data: testData })) + sandbox.stub(axios, "post").returns(resolved) + + const txids: string[] = [ + "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33", + "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33" + ] + const result: + | TxnDetailsResult + | TxnDetailsResult[] = await bitbox.Transaction.details(txids) + assert.isArray(result) + }) + + it(`should pass error from server to user`, async (): Promise => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws("error", "Input txid must be a string or array of strings.") + + const txid: any = 12345 + + await bitbox.Transaction.details(txid) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: ${util.inspect(err)}`) + assert.include( + err.message, + `Input txid must be a string or array of strings.` + ) + } + }) + }) +}) diff --git a/test/unit/TransactionBuilder.ts b/test/unit/TransactionBuilder.ts new file mode 100644 index 00000000..fd08ef26 --- /dev/null +++ b/test/unit/TransactionBuilder.ts @@ -0,0 +1,2041 @@ +// imports +import * as assert from "assert"; +import { BITBOX } from "../../lib/BITBOX" +import { TransactionBuilder } from "../../lib/TransactionBuilder" +import * as bcl from "bitcoincashjs-lib" + +// consts +const bitbox: BITBOX = new BITBOX() + +// TODO: port from require to import syntax +const fixtures = require("./fixtures/TransactionBuilder.json") + +describe("#TransactionBuilder", (): void => { + describe("#TransactionBuilderConstructor", (): void => { + it("should create instance of TransactionBuilder", (): void => { + const transactionbuilder: TransactionBuilder = new TransactionBuilder() + assert.equal(transactionbuilder instanceof TransactionBuilder, true) + }) + }) + + describe("#hashTypes", (): void => { + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("mainnet") + fixtures.hashTypes.forEach((fixture: any): void => { + it(`should match hash type`, (): void => { + assert.equal( + fixture[Object.keys(fixture)[0]], + // @ts-ignore + transactionBuilder.hashTypes[Object.keys(fixture)[0]] + ) + }) + }) + }) + + describe("#P2PK", (): void => { + describe("#toOne", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2pk.toOne.mainnet.forEach((fixture: any): void => { + it(`should create 1-to-1 P2PK transaction on mainnet`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const originalAmount: number = fixture.amount + const txid: string = fixture.txHash + const pubKey: any = bitbox.HDNode.toPublicKey(node) + const prevOutScript: Buffer = bitbox.Script.encodeP2PKOutput(pubKey) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + prevOutScript + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 3 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(prevOutScript, sendAmount) + const keyPair: bcl.ECPair = bitbox.HDNode.toKeyPair(node) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#Testnet", (): void => { + fixtures.scripts.p2pk.toOne.testnet.forEach((fixture: any): void => { + it(`should create 1-to-1 P2PK transaction on testnet`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("testnet") + const originalAmount: number = fixture.amount + const txid: string = fixture.txHash + const pubKey: Buffer = bitbox.HDNode.toPublicKey(node) + const prevOutScript: Buffer = bitbox.Script.encodeP2PKOutput(pubKey) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + prevOutScript + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 3 }, + { P2PKH: 3 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(prevOutScript, sendAmount) + const keyPair: bcl.ECPair = bitbox.HDNode.toKeyPair(node) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + }) + + describe("#toMany", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2pk.toMany.mainnet.forEach((fixture: any): void => { + it(`should create 1-to-many P2PK transaction on mainnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const node3: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[2]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const originalAmount: number = fixture.amount + const txid: string = fixture.txHash + const pubKey1: Buffer = bitbox.HDNode.toPublicKey(node1) + const pubKey2: Buffer = bitbox.HDNode.toPublicKey(node2) + const pubKey3: Buffer = bitbox.HDNode.toPublicKey(node3) + const prevOutScript1: Buffer = bitbox.Script.encodeP2PKOutput(pubKey1) + const prevOutScript2: Buffer = bitbox.Script.encodeP2PKOutput(pubKey2) + const prevOutScript3: Buffer = bitbox.Script.encodeP2PKOutput(pubKey3) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + prevOutScript1 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 3 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(prevOutScript2, Math.floor(sendAmount / 2)) + transactionBuilder.addOutput(prevOutScript3, Math.floor(sendAmount / 2)) + const keyPair: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#Testnet", (): void => { + fixtures.scripts.p2pk.toMany.testnet.forEach((fixture: any): void => { + it(`should create 1-to-many P2PK transaction on testnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const node3: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[2]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("testnet") + const originalAmount: number = fixture.amount + const txid: string = fixture.txHash + const pubKey1: Buffer = bitbox.HDNode.toPublicKey(node1) + const pubKey2: Buffer = bitbox.HDNode.toPublicKey(node2) + const pubKey3: Buffer = bitbox.HDNode.toPublicKey(node3) + const prevOutScript1: Buffer = bitbox.Script.encodeP2PKOutput(pubKey1) + const prevOutScript2: Buffer = bitbox.Script.encodeP2PKOutput(pubKey2) + const prevOutScript3: Buffer = bitbox.Script.encodeP2PKOutput(pubKey3) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + prevOutScript1 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 3 }, + { P2PKH: 3 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(prevOutScript2, Math.floor(sendAmount / 2)) + transactionBuilder.addOutput(prevOutScript3, Math.floor(sendAmount / 2)) + const keyPair: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + }) + + describe("#manyToMany", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2pk.manyToMany.mainnet.forEach((fixture: any): void => { + it(`should create many-to-many P2PK transaction on mainnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const node3: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[2]) + const node4: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[3]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const originalAmount: number = fixture.amount + const txid: string = fixture.txHash + const pubKey1: Buffer = bitbox.HDNode.toPublicKey(node1) + const pubKey2: Buffer = bitbox.HDNode.toPublicKey(node2) + const pubKey3: Buffer = bitbox.HDNode.toPublicKey(node3) + const pubKey4: Buffer = bitbox.HDNode.toPublicKey(node4) + const prevOutScript1: Buffer = bitbox.Script.encodeP2PKOutput(pubKey1) + const prevOutScript2: Buffer = bitbox.Script.encodeP2PKOutput(pubKey2) + const prevOutScript3: Buffer = bitbox.Script.encodeP2PKOutput(pubKey3) + const prevOutScript4: Buffer = bitbox.Script.encodeP2PKOutput(pubKey4) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + prevOutScript1 + ) + transactionBuilder.addInput( + txid, + 1, + transactionBuilder.DEFAULT_SEQUENCE, + prevOutScript2 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 3 }, + { P2PKH: 3 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(prevOutScript3, Math.floor(sendAmount / 2)) + transactionBuilder.addOutput(prevOutScript4, Math.floor(sendAmount / 2)) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node2) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair1, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + transactionBuilder.sign( + 1, + keyPair2, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#Testnet", (): void => { + fixtures.scripts.p2pk.manyToMany.testnet.forEach((fixture: any): void => { + it(`should create many-to-many P2PK transaction on testnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const node3: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[2]) + const node4: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[3]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("testnet") + const originalAmount: number = fixture.amount + const txid: string = fixture.txHash + const pubKey1: Buffer = bitbox.HDNode.toPublicKey(node1) + const pubKey2: Buffer = bitbox.HDNode.toPublicKey(node2) + const pubKey3: Buffer = bitbox.HDNode.toPublicKey(node3) + const pubKey4: Buffer = bitbox.HDNode.toPublicKey(node4) + const prevOutScript1: Buffer = bitbox.Script.encodeP2PKOutput(pubKey1) + const prevOutScript2: Buffer = bitbox.Script.encodeP2PKOutput(pubKey2) + const prevOutScript3: Buffer = bitbox.Script.encodeP2PKOutput(pubKey3) + const prevOutScript4: Buffer = bitbox.Script.encodeP2PKOutput(pubKey4) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + prevOutScript1 + ) + transactionBuilder.addInput( + txid, + 1, + transactionBuilder.DEFAULT_SEQUENCE, + prevOutScript2 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 3 }, + { P2PKH: 3 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(prevOutScript3, Math.floor(sendAmount / 2)) + transactionBuilder.addOutput(prevOutScript4, Math.floor(sendAmount / 2)) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node2) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair1, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + transactionBuilder.sign( + 1, + keyPair2, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + }) + + describe("#fromMany", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2pk.fromMany.mainnet.forEach((fixture: any): void => { + it(`should create many-to-1 P2PK transaction on mainnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const node3: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[2]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const originalAmount: any = fixture.amount + const txid: string = fixture.txHash + const pubKey1: Buffer = bitbox.HDNode.toPublicKey(node1) + const pubKey2: Buffer = bitbox.HDNode.toPublicKey(node2) + const pubKey3: Buffer = bitbox.HDNode.toPublicKey(node3) + const prevOutScript1: Buffer = bitbox.Script.encodeP2PKOutput(pubKey1) + const prevOutScript2: Buffer = bitbox.Script.encodeP2PKOutput(pubKey2) + const prevOutScript3: Buffer = bitbox.Script.encodeP2PKOutput(pubKey3) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + prevOutScript1 + ) + transactionBuilder.addInput( + txid, + 1, + transactionBuilder.DEFAULT_SEQUENCE, + prevOutScript2 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 3 }, + { P2PKH: 3 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(prevOutScript3, sendAmount) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node2) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair1, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + transactionBuilder.sign( + 1, + keyPair2, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#Testnet", (): void => { + fixtures.scripts.p2pk.fromMany.testnet.forEach((fixture: any): void => { + it(`should create many-to-1 P2PK transaction on testnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const node3: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[2]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("testnet") + const originalAmount: number = fixture.amount + const txid: string = fixture.txHash + const pubKey1: Buffer = bitbox.HDNode.toPublicKey(node1) + const pubKey2: Buffer = bitbox.HDNode.toPublicKey(node2) + const pubKey3: Buffer = bitbox.HDNode.toPublicKey(node3) + const prevOutScript1: Buffer = bitbox.Script.encodeP2PKOutput(pubKey1) + const prevOutScript2: Buffer = bitbox.Script.encodeP2PKOutput(pubKey2) + const prevOutScript3: Buffer = bitbox.Script.encodeP2PKOutput(pubKey3) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + prevOutScript1 + ) + transactionBuilder.addInput( + txid, + 1, + transactionBuilder.DEFAULT_SEQUENCE, + prevOutScript2 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 3 }, + { P2PKH: 3 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(prevOutScript3, sendAmount) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node2) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair1, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + transactionBuilder.sign( + 1, + keyPair2, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + }) + }) + + describe("#P2PKH", (): void => { + describe("#toOne", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2pkh.toOne.mainnet.forEach((fixture: any): void => { + it(`should create 1-to-1 P2PKH transaction on mainnet`, (): void => { + const hdnode: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const keyPair: bcl.ECPair = bitbox.HDNode.toKeyPair(hdnode) + const txHash: string = fixture.txHash + // original amount of satoshis in vin + const originalAmount: number = fixture.amount + transactionBuilder.addInput(txHash, fixture.vout) + // get byte count to calculate fee. paying 1 sat/byte + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 1 } + ) + // amount to send to receiver. It's the original amount - 1 sat/byte for tx size + const sendAmount: number = originalAmount - byteCount + // add output w/ address and amount to send + let redeemScript: undefined + transactionBuilder.addOutput(fixture.outputs[0], sendAmount) + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + + // build tx + const tx: any = transactionBuilder.build() + // output rawhex + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#Testnet", (): void => { + fixtures.scripts.p2pkh.toOne.testnet.forEach((fixture: any): void => { + it(`should create 1-to-1 P2PKH transaction on testnet`, (): void => { + const hdnode: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("testnet") + const keyPair: bcl.ECPair = bitbox.HDNode.toKeyPair(hdnode) + const txHash: string = fixture.txHash + // original amount of satoshis in vin + const originalAmount: number = fixture.amount + transactionBuilder.addInput(txHash, fixture.vout) + // get byte count to calculate fee. paying 1 sat/byte + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 1 } + ) + // amount to send to receiver. It's the original amount - 1 sat/byte for tx size + const sendAmount: number = originalAmount - byteCount * 15 + // add output w/ address and amount to send + let redeemScript: undefined + transactionBuilder.addOutput(fixture.outputs[0], sendAmount) + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + + // build tx + const tx: any = transactionBuilder.build() + // output rawhex + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#RegTest", (): void => { + fixtures.scripts.p2pkh.toOne.regtest.forEach((fixture: any): void => { + it(`should create 1-to-1 P2PKH transaction on regtest`, (): void => { + const hdnode: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("regtest") + const keyPair: bcl.ECPair = bitbox.HDNode.toKeyPair(hdnode) + const txHash: string = fixture.txHash + // original amount of satoshis in vin + const originalAmount: number = fixture.amount + transactionBuilder.addInput(txHash, fixture.vout) + // get byte count to calculate fee. paying 1 sat/byte + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 1 } + ) + // amount to send to receiver. It's the original amount - 1 sat/byte for tx size + const sendAmount: number = originalAmount - byteCount * 15 + // add output w/ address and amount to send + let redeemScript: undefined + transactionBuilder.addOutput(fixture.outputs[0], sendAmount) + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + + // build tx + const tx: any = transactionBuilder.build() + // output rawhex + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + }) + + describe("#toMany", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2pkh.toMany.mainnet.forEach((fixture: any): void => { + it(`should create 1-to-2 P2PKH transaction on mainnet`, (): void => { + const hdnode: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const keyPair: bcl.ECPair = bitbox.HDNode.toKeyPair(hdnode) + const txHash: string = fixture.txHash + // original amount of satoshis in vin + const originalAmount: number = fixture.amount + transactionBuilder.addInput(txHash, fixture.vout) + // get byte count to calculate fee. paying 1 sat/byte + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 2 } + ) + // amount to send to receiver. It's the original amount - 1 sat/byte for tx size + const sendAmount: number = originalAmount - byteCount + // add output w/ address and amount to send + transactionBuilder.addOutput( + fixture.outputs[0], + Math.floor(sendAmount / 2) + ) + transactionBuilder.addOutput( + fixture.outputs[1], + Math.floor(sendAmount / 2) + ) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + // build tx + const tx: any = transactionBuilder.build() + // output rawhex + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#Testnet", (): void => { + fixtures.scripts.p2pkh.toMany.testnet.forEach((fixture: any): void => { + // TODO pass in tesnet network config + it(`should create 1-to-2 P2PKH transaction on testnet`, (): void => { + const hdnode: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("testnet") + const keyPair: bcl.ECPair = bitbox.HDNode.toKeyPair(hdnode) + const txHash: string = fixture.txHash + // original amount of satoshis in vin + const originalAmount: number = fixture.amount + transactionBuilder.addInput(txHash, fixture.vout) + // get byte count to calculate fee. paying 1 sat/byte + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 2 } + ) + // amount to send to receiver. It's the original amount - 1 sat/byte for tx size + const sendAmount: number = originalAmount - byteCount * 15 + // add output w/ address and amount to send + transactionBuilder.addOutput( + fixture.outputs[0], + Math.floor(sendAmount / 2) + ) + transactionBuilder.addOutput( + fixture.outputs[1], + Math.floor(sendAmount / 2) + ) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + // build tx + const tx: any = transactionBuilder.build() + // output rawhex + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#RegTest", (): void => { + fixtures.scripts.p2pkh.toMany.regtest.forEach((fixture: any): void => { + // TODO pass in tesnet network config + it(`should create 1-to-2 P2PKH transaction on regtest`, (): void => { + const hdnode: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("regtest") + const keyPair: bcl.ECPair = bitbox.HDNode.toKeyPair(hdnode) + const txHash: string = fixture.txHash + // original amount of satoshis in vin + const originalAmount: number = fixture.amount + transactionBuilder.addInput(txHash, fixture.vout) + // get byte count to calculate fee. paying 1 sat/byte + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 2 } + ) + // amount to send to receiver. It's the original amount - 1 sat/byte for tx size + const sendAmount: number = originalAmount - byteCount * 15 + // add output w/ address and amount to send + transactionBuilder.addOutput( + fixture.outputs[0], + Math.floor(sendAmount / 2) + ) + transactionBuilder.addOutput( + fixture.outputs[1], + Math.floor(sendAmount / 2) + ) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + // build tx + const tx: any = transactionBuilder.build() + // output rawhex + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + }) + + describe("#manyToMany", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2pkh.manyToMany.mainnet.forEach((fixture: any): void => { + it(`should create 2-to-2 P2PKH transaction on mainnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const txHash: string = fixture.txHash + const originalAmount: number = fixture.amounts[0] + fixture.amounts[1] + transactionBuilder.addInput(txHash, 0) + transactionBuilder.addInput(txHash, 1) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 2 }, + { P2PKH: 2 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput( + fixture.outputs[0], + Math.floor(sendAmount / 2) + ) + transactionBuilder.addOutput( + fixture.outputs[1], + Math.floor(sendAmount / 2) + ) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node2) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair1, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amounts[0] + ) + transactionBuilder.sign( + 1, + keyPair2, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amounts[1] + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#Testnet", (): void => { + fixtures.scripts.p2pkh.manyToMany.testnet.forEach((fixture: any): void => { + it(`should create 2-to-2 P2PKH transaction on testnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("testnet") + const txHash: string = fixture.txHash + const originalAmount: number = fixture.amounts[0] + fixture.amounts[1] + transactionBuilder.addInput(txHash, 0) + transactionBuilder.addInput(txHash, 1) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 2 }, + { P2PKH: 2 } + ) + const sendAmount: number = originalAmount - byteCount * 15 + transactionBuilder.addOutput( + fixture.outputs[0], + Math.floor(sendAmount / 2) + ) + transactionBuilder.addOutput( + fixture.outputs[1], + Math.floor(sendAmount / 2) + ) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node2) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair1, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amounts[0] + ) + transactionBuilder.sign( + 1, + keyPair2, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amounts[1] + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#RegTest", (): void => { + fixtures.scripts.p2pkh.manyToMany.regtest.forEach((fixture: any): void => { + it(`should create 2-to-2 P2PKH transaction on regtest`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("regtest") + const txHash: string = fixture.txHash + const originalAmount: number = fixture.amounts[0] + fixture.amounts[1] + transactionBuilder.addInput(txHash, 0) + transactionBuilder.addInput(txHash, 1) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 2 }, + { P2PKH: 2 } + ) + const sendAmount: number = originalAmount - byteCount * 15 + transactionBuilder.addOutput( + fixture.outputs[0], + Math.floor(sendAmount / 2) + ) + transactionBuilder.addOutput( + fixture.outputs[1], + Math.floor(sendAmount / 2) + ) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node2) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair1, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amounts[0] + ) + transactionBuilder.sign( + 1, + keyPair2, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amounts[1] + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + }) + + describe("#fromMany", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2pkh.fromMany.mainnet.forEach((fixture: any): void => { + it(`should create 2-to-1 P2PKH transaction on mainnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const txHash: string = fixture.txHash + const originalAmount: number = fixture.amounts[0] + fixture.amounts[1] + transactionBuilder.addInput(txHash, 0) + transactionBuilder.addInput(txHash, 1) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 2 }, + { P2PKH: 1 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(fixture.outputs[0], sendAmount) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node2) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair1, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amounts[0] + ) + transactionBuilder.sign( + 1, + keyPair2, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amounts[1] + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#Testnet", (): void => { + fixtures.scripts.p2pkh.fromMany.testnet.forEach((fixture: any): void => { + it(`should create 2-to-1 P2PKH transaction on testnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("testnet") + const txHash: string = fixture.txHash + const originalAmount: number = fixture.amounts[0] + fixture.amounts[1] + transactionBuilder.addInput(txHash, 0) + transactionBuilder.addInput(txHash, 1) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 2 }, + { P2PKH: 1 } + ) + const sendAmount: number = originalAmount - byteCount * 15 + transactionBuilder.addOutput(fixture.outputs[0], sendAmount) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node2) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair1, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amounts[0] + ) + transactionBuilder.sign( + 1, + keyPair2, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amounts[1] + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#RegTest", (): void => { + fixtures.scripts.p2pkh.fromMany.regtest.forEach((fixture: any): void => { + it(`should create 2-to-1 P2PKH transaction on regtest`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("regtest") + const txHash: string = fixture.txHash + const originalAmount: number = fixture.amounts[0] + fixture.amounts[1] + transactionBuilder.addInput(txHash, 0) + transactionBuilder.addInput(txHash, 1) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 2 }, + { P2PKH: 1 } + ) + const sendAmount: number = originalAmount - byteCount * 15 + transactionBuilder.addOutput(fixture.outputs[0], sendAmount) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node2) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair1, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amounts[0] + ) + transactionBuilder.sign( + 1, + keyPair2, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amounts[1] + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + }) + }) + + describe("#op_return", (): void => { + describe("#Mainnet", (): void => { + fixtures.nulldata.mainnet.forEach((fixture: any): void => { + it(`should create transaction w/ OP_RETURN output on mainnet`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const txHash: string = fixture.txHash + const originalAmount: number = fixture.amount + transactionBuilder.addInput(txHash, 0) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 5 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(fixture.output, sendAmount) + const data = fixture.data + let buf: Buffer = Buffer.from(data, "ascii") + const encoded: Buffer = bitbox.Script.encodeNullDataOutput(buf) + transactionBuilder.addOutput(encoded, 0) + const keyPair = bitbox.HDNode.toKeyPair(node) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#Testnet", (): void => { + fixtures.nulldata.testnet.forEach((fixture: any): void => { + it(`should create transaction w/ OP_RETURN output on testnet`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("testnet") + const txHash: string = fixture.txHash + const originalAmount: number = fixture.amount + transactionBuilder.addInput(txHash, 0) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 5 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(fixture.output, sendAmount) + const data = fixture.data + let buf: Buffer = Buffer.from(data, "ascii") + const encoded: Buffer = bitbox.Script.encodeNullDataOutput(buf) + transactionBuilder.addOutput(encoded, 0) + const keyPair = bitbox.HDNode.toKeyPair(node) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#RegTest", (): void => { + fixtures.nulldata.regtest.forEach((fixture: any): void => { + it(`should create transaction w/ OP_RETURN output on regtest`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("regtest") + const txHash: string = fixture.txHash + const originalAmount: number = fixture.amount + transactionBuilder.addInput(txHash, 0) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 5 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(fixture.output, sendAmount) + const data = fixture.data + let buf: Buffer = Buffer.from(data, "ascii") + const encoded: Buffer = bitbox.Script.encodeNullDataOutput(buf) + transactionBuilder.addOutput(encoded, 0) + const keyPair = bitbox.HDNode.toKeyPair(node) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + }) + + describe("#P2MS", (): void => { + describe("#toOne", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2ms.toOne.mainnet.forEach((fixture: any): void => { + it(`should create 1-to-1 1-of-2 P2MS transaction on mainnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const node3: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[2]) + const node4: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[3]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const txid: string = fixture.txHash + const originalAmount: number = fixture.amount + const pubKey1: Buffer = bitbox.HDNode.toPublicKey(node1) + const pubKey2: Buffer = bitbox.HDNode.toPublicKey(node2) + const buf1: Buffer = bitbox.Script.encodeP2MSOutput(1, [ + pubKey1, + pubKey2 + ]) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + buf1 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 3 }, + { P2PKH: 3 } + ) + const pubKey3: Buffer = bitbox.HDNode.toPublicKey(node3) + const pubKey4: Buffer = bitbox.HDNode.toPublicKey(node4) + const buf2: Buffer = bitbox.Script.encodeP2MSOutput(1, [ + pubKey3, + pubKey4 + ]) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(buf2, sendAmount) + let redeemScript: undefined + const keyPair = bitbox.HDNode.toKeyPair(node1) + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + // describe('#Testnet', () => { + // fixtures.scripts.p2ms.toOne.testnet.forEach((fixture) => { + // it(`should create 1-to-1 P2MS transaction on testnet`, () => { + // let hdnode = bitbox.HDNode.fromXPriv(fixture.xpriv, 'testnet'); + // let transactionBuilder = new bitbox.TransactionBuilder('testnet'); + // let keyPair = bitbox.HDNode.toKeyPair(hdnode); + // let txHash = fixture.txHash; + // // original amount of satoshis in vin + // let originalAmount = fixture.amount; + // transactionBuilder.addInput(txHash, fixture.vout); + // // get byte count to calculate fee. paying 1 sat/byte + // let byteCount = bitbox.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 1 }); + // // amount to send to receiver. It's the original amount - 1 sat/byte for tx size + // let sendAmount = originalAmount - (byteCount * 15); + // // add output w/ address and amount to send + // let redeemScript + // transactionBuilder.addOutput(fixture.outputs[0], sendAmount); + // transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); + // + // // build tx + // let tx = transactionBuilder.build(); + // // output rawhex + // let hex = tx.toHex(); + // assert.equal(hex, fixture.hex); + // }); + // }); + // }); + }) + + describe("#toMany", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2ms.toMany.mainnet.forEach((fixture: any): void => { + it(`should create 1-to-2 P2MS transaction on mainnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const node3: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[2]) + const node4: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[3]) + const node5: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[4]) + const node6: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[5]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const txid: string = fixture.txHash + const originalAmount: number = fixture.amount + const pubKey1: Buffer = bitbox.HDNode.toPublicKey(node1) + const pubKey2: Buffer = bitbox.HDNode.toPublicKey(node2) + const buf1: Buffer = bitbox.Script.encodeP2MSOutput(1, [ + pubKey1, + pubKey2 + ]) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + buf1 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 3 }, + { P2PKH: 3 } + ) + const sendAmount: number = originalAmount - byteCount + const pubKey3: Buffer = bitbox.HDNode.toPublicKey(node3) + const pubKey4: Buffer = bitbox.HDNode.toPublicKey(node4) + const buf2: Buffer = bitbox.Script.encodeP2MSOutput(1, [ + pubKey3, + pubKey4 + ]) + transactionBuilder.addOutput(buf2, Math.floor(sendAmount / 2)) + const pubKey5: Buffer = bitbox.HDNode.toPublicKey(node5) + const pubKey6: Buffer = bitbox.HDNode.toPublicKey(node6) + const buf3: Buffer = bitbox.Script.encodeP2MSOutput(1, [ + pubKey5, + pubKey6 + ]) + transactionBuilder.addOutput(buf3, Math.floor(sendAmount / 2)) + let redeemScript: undefined + const keyPair = bitbox.HDNode.toKeyPair(node1) + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + // describe('#Testnet', () => { + // fixtures.scripts.p2ms.toMany.testnet.forEach((fixture) => { + // // TODO pass in tesnet network config + // it(`should create 1-to-2 P2MS transaction on testnet`, () => { + // let hdnode = bitbox.HDNode.fromXPriv(fixture.xpriv); + // let transactionBuilder = new bitbox.TransactionBuilder('testnet'); + // let keyPair = bitbox.HDNode.toKeyPair(hdnode); + // let txHash = fixture.txHash; + // // original amount of satoshis in vin + // let originalAmount = fixture.amount; + // transactionBuilder.addInput(txHash, fixture.vout); + // // get byte count to calculate fee. paying 1 sat/byte + // let byteCount = bitbox.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 2 }); + // // amount to send to receiver. It's the original amount - 1 sat/byte for tx size + // let sendAmount = originalAmount - (byteCount * 15); + // // add output w/ address and amount to send + // transactionBuilder.addOutput(fixture.outputs[0], Math.floor(sendAmount / 2)); + // transactionBuilder.addOutput(fixture.outputs[1], Math.floor(sendAmount / 2)); + // let redeemScript + // transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); + // // build tx + // let tx = transactionBuilder.build(); + // // output rawhex + // let hex = tx.toHex(); + // assert.equal(hex, fixture.hex); + // }); + // }); + // }); + }) + + describe("#manyToMany", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2ms.manyToMany.mainnet.forEach((fixture: any): void => { + it(`should create 2-to-2 P2MS transaction on mainnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const node3: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[2]) + const node4: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[3]) + const node5: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[4]) + const node6: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[5]) + const node7: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[6]) + const node8: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[7]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const txid: string = fixture.txHash + const originalAmount: number = fixture.amount + const pubKey1: Buffer = bitbox.HDNode.toPublicKey(node1) + const pubKey2: Buffer = bitbox.HDNode.toPublicKey(node2) + const buf1: Buffer = bitbox.Script.encodeP2MSOutput(1, [ + pubKey1, + pubKey2 + ]) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + buf1 + ) + const pubKey3: Buffer = bitbox.HDNode.toPublicKey(node3) + const pubKey4: Buffer = bitbox.HDNode.toPublicKey(node4) + const buf2: Buffer = bitbox.Script.encodeP2MSOutput(1, [ + pubKey3, + pubKey4 + ]) + transactionBuilder.addInput( + txid, + 1, + transactionBuilder.DEFAULT_SEQUENCE, + buf2 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 3 }, + { P2PKH: 3 } + ) + const sendAmount: number = originalAmount - byteCount + const pubKey5: Buffer = bitbox.HDNode.toPublicKey(node5) + const pubKey6: Buffer = bitbox.HDNode.toPublicKey(node6) + const buf3: Buffer = bitbox.Script.encodeP2MSOutput(1, [ + pubKey5, + pubKey6 + ]) + transactionBuilder.addOutput(buf3, Math.floor(sendAmount / 2)) + const pubKey7: Buffer = bitbox.HDNode.toPublicKey(node7) + const pubKey8: Buffer = bitbox.HDNode.toPublicKey(node8) + const buf4: Buffer = bitbox.Script.encodeP2MSOutput(1, [ + pubKey7, + pubKey8 + ]) + transactionBuilder.addOutput(buf4, Math.floor(sendAmount / 2)) + let redeemScript: undefined + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node3) + transactionBuilder.sign( + 0, + keyPair1, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + transactionBuilder.sign( + 1, + keyPair2, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + // describe('#Testnet', () => { + // fixtures.scripts.p2ms.manyToMany.testnet.forEach((fixture) => { + // it(`should create 2-to-2 P2MS transaction on testnet`, () => { + // let node1 = bitbox.HDNode.fromXPriv(fixture.xprivs[0]); + // let node2 = bitbox.HDNode.fromXPriv(fixture.xprivs[1]); + // let transactionBuilder = new bitbox.TransactionBuilder('testnet'); + // let txHash = fixture.txHash; + // let originalAmount = fixture.amounts[0] + fixture.amounts[1]; + // transactionBuilder.addInput(txHash, 0); + // transactionBuilder.addInput(txHash, 1); + // let byteCount = bitbox.BitcoinCash.getByteCount({ P2PKH: 2 }, { P2PKH: 2 }); + // let sendAmount = originalAmount - (byteCount * 15); + // transactionBuilder.addOutput(fixture.outputs[0], Math.floor(sendAmount / 2)); + // transactionBuilder.addOutput(fixture.outputs[1], Math.floor(sendAmount / 2)); + // let keyPair1 = bitbox.HDNode.toKeyPair(node1); + // let keyPair2 = bitbox.HDNode.toKeyPair(node2); + // let redeemScript; + // transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[0]); + // transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[1]); + // let tx = transactionBuilder.build(); + // let hex = tx.toHex(); + // assert.equal(hex, fixture.hex); + // }); + // }); + // }); + }) + + describe("#fromMany", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2ms.fromMany.mainnet.forEach((fixture: any): void => { + it(`should create 2-to-1 P2MS transaction on mainnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const node3: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[2]) + const node4: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[3]) + const node5: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[4]) + const node6: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[5]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const txid: string = fixture.txHash + const originalAmount: number = fixture.amount + const pubKey1: Buffer = bitbox.HDNode.toPublicKey(node1) + const pubKey2: Buffer = bitbox.HDNode.toPublicKey(node2) + const buf1: Buffer = bitbox.Script.encodeP2MSOutput(1, [ + pubKey1, + pubKey2 + ]) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + buf1 + ) + const pubKey3: Buffer = bitbox.HDNode.toPublicKey(node3) + const pubKey4: Buffer = bitbox.HDNode.toPublicKey(node4) + const buf2: Buffer = bitbox.Script.encodeP2MSOutput(1, [ + pubKey3, + pubKey4 + ]) + transactionBuilder.addInput( + txid, + 1, + transactionBuilder.DEFAULT_SEQUENCE, + buf2 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 3 }, + { P2PKH: 3 } + ) + const sendAmount: number = originalAmount - byteCount + const pubKey5: Buffer = bitbox.HDNode.toPublicKey(node5) + const pubKey6: Buffer = bitbox.HDNode.toPublicKey(node6) + const buf3: Buffer = bitbox.Script.encodeP2MSOutput(1, [ + pubKey5, + pubKey6 + ]) + transactionBuilder.addOutput(buf3, sendAmount) + let redeemScript: undefined + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node3) + transactionBuilder.sign( + 0, + keyPair1, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + transactionBuilder.sign( + 1, + keyPair2, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + // describe('#Testnet', () => { + // fixtures.scripts.p2ms.fromMany.testnet.forEach((fixture) => { + // it(`should create 2-to-1 P2MS transaction on testnet`, () => { + // let node1 = bitbox.HDNode.fromXPriv(fixture.xprivs[0]); + // let node2 = bitbox.HDNode.fromXPriv(fixture.xprivs[1]); + // let transactionBuilder = new bitbox.TransactionBuilder('testnet'); + // let txHash = fixture.txHash; + // let originalAmount = fixture.amounts[0] + fixture.amounts[1]; + // transactionBuilder.addInput(txHash, 0); + // transactionBuilder.addInput(txHash, 1); + // let byteCount = bitbox.BitcoinCash.getByteCount({ P2PKH: 2 }, { P2PKH: 1 }); + // let sendAmount = originalAmount - (byteCount * 15); + // transactionBuilder.addOutput(fixture.outputs[0], sendAmount); + // let keyPair1 = bitbox.HDNode.toKeyPair(node1); + // let keyPair2 = bitbox.HDNode.toKeyPair(node2); + // let redeemScript; + // transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[0]); + // transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[1]); + // let tx = transactionBuilder.build(); + // let hex = tx.toHex(); + // assert.equal(hex, fixture.hex); + // }); + // }); + // }); + }) + }) + + describe("#P2SH", (): void => { + describe("#toOne", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2sh.toOne.mainnet.forEach((fixture: any): void => { + it(`should create 1-to-1 P2SH transaction on mainnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const txid: string = fixture.txHash + const originalAmount: number = fixture.amount + const identifier1: Buffer = bitbox.HDNode.toIdentifier(node1) + const buf1: any = bitbox.Script.encode([ + bitbox.Script.opcodes.OP_DUP, + bitbox.Script.opcodes.OP_HASH160, + identifier1, + bitbox.Script.opcodes.OP_EQUALVERIFY, + bitbox.Script.opcodes.OP_CHECKSIG + ]) + const scriptHash1: any = bitbox.Crypto.hash160(buf1) + const data1: Buffer = bitbox.Script.encodeP2SHOutput(scriptHash1) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + data1 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 2 }, + { P2PKH: 1 } + ) + const sendAmount: number = originalAmount - byteCount + const identifier2 = bitbox.HDNode.toIdentifier(node2) + const buf2 = bitbox.Script.encode([ + bitbox.Script.opcodes.OP_DUP, + bitbox.Script.opcodes.OP_HASH160, + identifier2, + bitbox.Script.opcodes.OP_EQUALVERIFY, + bitbox.Script.opcodes.OP_CHECKSIG + ]) + + const scriptHash2 = bitbox.Crypto.hash160(buf2) + const data2: Buffer = bitbox.Script.encodeP2SHOutput(scriptHash2) + transactionBuilder.addOutput(data2, sendAmount) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + transactionBuilder.sign( + 0, + keyPair1, + buf1, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + // describe('#Testnet', () => { + // fixtures.scripts.p2sh.toOne.testnet.forEach((fixture) => { + // it(`should create 1-to-1 P2SH transaction on testnet`, () => { + // let hdnode = bitbox.HDNode.fromXPriv(fixture.xpriv, 'testnet'); + // let transactionBuilder = new bitbox.TransactionBuilder('testnet'); + // let keyPair = bitbox.HDNode.toKeyPair(hdnode); + // let txHash = fixture.txHash; + // // original amount of satoshis in vin + // let originalAmount = fixture.amount; + // transactionBuilder.addInput(txHash, fixture.vout); + // // get byte count to calculate fee. paying 1 sat/byte + // let byteCount = bitbox.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 1 }); + // // amount to send to receiver. It's the original amount - 1 sat/byte for tx size + // let sendAmount = originalAmount - (byteCount * 15); + // // add output w/ address and amount to send + // let redeemScript + // transactionBuilder.addOutput(fixture.outputs[0], sendAmount); + // transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); + // + // // build tx + // let tx = transactionBuilder.build(); + // // output rawhex + // let hex = tx.toHex(); + // assert.equal(hex, fixture.hex); + // }); + // }); + // }); + }) + + describe("#toMany", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2sh.toMany.mainnet.forEach((fixture: any): void => { + it(`should create 1-to-2 P2SH transaction on mainnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const node3: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[2]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const txid: string = fixture.txHash + const originalAmount: number = fixture.amount + const identifier1: Buffer = bitbox.HDNode.toIdentifier(node1) + const buf1: any = bitbox.Script.encode([ + bitbox.Script.opcodes.OP_DUP, + bitbox.Script.opcodes.OP_HASH160, + identifier1, + bitbox.Script.opcodes.OP_EQUALVERIFY, + bitbox.Script.opcodes.OP_CHECKSIG + ]) + const scriptHash1: Buffer = bitbox.Crypto.hash160(buf1) + const data1: Buffer = bitbox.Script.encodeP2SHOutput(scriptHash1) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + data1 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 3 }, + { P2PKH: 2 } + ) + const sendAmount: number = originalAmount - byteCount + const identifier2: Buffer = bitbox.HDNode.toIdentifier(node2) + const buf2: Buffer = bitbox.Script.encode([ + bitbox.Script.opcodes.OP_DUP, + bitbox.Script.opcodes.OP_HASH160, + identifier2, + bitbox.Script.opcodes.OP_EQUALVERIFY, + bitbox.Script.opcodes.OP_CHECKSIG + ]) + const scriptHash2: Buffer = bitbox.Crypto.hash160(buf2) + const data2: Buffer = bitbox.Script.encodeP2SHOutput(scriptHash2) + transactionBuilder.addOutput(data2, Math.floor(sendAmount / 2)) + const identifier3: Buffer = bitbox.HDNode.toIdentifier(node3) + const buf3: Buffer = bitbox.Script.encode([ + bitbox.Script.opcodes.OP_DUP, + bitbox.Script.opcodes.OP_HASH160, + identifier3, + bitbox.Script.opcodes.OP_EQUALVERIFY, + bitbox.Script.opcodes.OP_CHECKSIG + ]) + const scriptHash3: Buffer = bitbox.Crypto.hash160(buf3) + const data3: Buffer = bitbox.Script.encodeP2SHOutput(scriptHash3) + transactionBuilder.addOutput(data3, Math.floor(sendAmount / 2)) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + transactionBuilder.sign( + 0, + keyPair1, + buf1, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + // describe('#Testnet', () => { + // fixtures.scripts.p2sh.toMany.testnet.forEach((fixture) => { + // // TODO pass in tesnet network config + // it(`should create 1-to-2 P2SH transaction on testnet`, () => { + // let hdnode = bitbox.HDNode.fromXPriv(fixture.xpriv); + // let transactionBuilder = new bitbox.TransactionBuilder('testnet'); + // let keyPair = bitbox.HDNode.toKeyPair(hdnode); + // let txHash = fixture.txHash; + // // original amount of satoshis in vin + // let originalAmount = fixture.amount; + // transactionBuilder.addInput(txHash, fixture.vout); + // // get byte count to calculate fee. paying 1 sat/byte + // let byteCount = bitbox.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 2 }); + // // amount to send to receiver. It's the original amount - 1 sat/byte for tx size + // let sendAmount = originalAmount - (byteCount * 15); + // // add output w/ address and amount to send + // transactionBuilder.addOutput(fixture.outputs[0], Math.floor(sendAmount / 2)); + // transactionBuilder.addOutput(fixture.outputs[1], Math.floor(sendAmount / 2)); + // let redeemScript + // transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount); + // // build tx + // let tx = transactionBuilder.build(); + // // output rawhex + // let hex = tx.toHex(); + // assert.equal(hex, fixture.hex); + // }); + // }); + // }); + }) + + describe("#manyToMany", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2sh.manyToMany.mainnet.forEach((fixture: any): void => { + it(`should create 2-to-2 P2SH transaction on mainnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const node3: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[2]) + const node4: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[3]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const txid: string = fixture.txHash + const originalAmount: number = fixture.amount + const identifier1: Buffer = bitbox.HDNode.toIdentifier(node1) + const buf1: Buffer = bitbox.Script.encode([ + bitbox.Script.opcodes.OP_DUP, + bitbox.Script.opcodes.OP_HASH160, + identifier1, + bitbox.Script.opcodes.OP_EQUALVERIFY, + bitbox.Script.opcodes.OP_CHECKSIG + ]) + const scriptHash1: Buffer = bitbox.Crypto.hash160(buf1) + const data1: Buffer = bitbox.Script.encodeP2SHOutput(scriptHash1) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + data1 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 5 }, + { P2PKH: 5 } + ) + const sendAmount: number = originalAmount - byteCount + const identifier2: Buffer = bitbox.HDNode.toIdentifier(node2) + const buf2: Buffer = bitbox.Script.encode([ + bitbox.Script.opcodes.OP_DUP, + bitbox.Script.opcodes.OP_HASH160, + identifier2, + bitbox.Script.opcodes.OP_EQUALVERIFY, + bitbox.Script.opcodes.OP_CHECKSIG + ]) + const scriptHash2: Buffer = bitbox.Crypto.hash160(buf2) + const data2: Buffer = bitbox.Script.encodeP2SHOutput(scriptHash2) + transactionBuilder.addInput( + txid, + 1, + transactionBuilder.DEFAULT_SEQUENCE, + data2 + ) + const identifier3: Buffer = bitbox.HDNode.toIdentifier(node3) + const buf3: Buffer = bitbox.Script.encode([ + bitbox.Script.opcodes.OP_DUP, + bitbox.Script.opcodes.OP_HASH160, + identifier3, + bitbox.Script.opcodes.OP_EQUALVERIFY, + bitbox.Script.opcodes.OP_CHECKSIG + ]) + const scriptHash3: Buffer = bitbox.Crypto.hash160(buf3) + const data3: Buffer = bitbox.Script.encodeP2SHOutput(scriptHash3) + transactionBuilder.addOutput(data3, Math.floor(sendAmount / 2)) + const identifier4: Buffer = bitbox.HDNode.toIdentifier(node4) + const buf4: Buffer = bitbox.Script.encode([ + bitbox.Script.opcodes.OP_DUP, + bitbox.Script.opcodes.OP_HASH160, + identifier4, + bitbox.Script.opcodes.OP_EQUALVERIFY, + bitbox.Script.opcodes.OP_CHECKSIG + ]) + const scriptHash4: Buffer = bitbox.Crypto.hash160(buf4) + const data4: Buffer = bitbox.Script.encodeP2SHOutput(scriptHash4) + transactionBuilder.addOutput(data4, Math.floor(sendAmount / 2)) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node2) + transactionBuilder.sign( + 0, + keyPair1, + buf1, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + transactionBuilder.sign( + 1, + keyPair2, + buf2, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + // describe('#Testnet', () => { + // fixtures.scripts.p2sh.manyToMany.testnet.forEach((fixture) => { + // it(`should create 2-to-2 P2SH transaction on testnet`, () => { + // let node1 = bitbox.HDNode.fromXPriv(fixture.xprivs[0]); + // let node2 = bitbox.HDNode.fromXPriv(fixture.xprivs[1]); + // let transactionBuilder = new bitbox.TransactionBuilder('testnet'); + // let txHash = fixture.txHash; + // let originalAmount = fixture.amounts[0] + fixture.amounts[1]; + // transactionBuilder.addInput(txHash, 0); + // transactionBuilder.addInput(txHash, 1); + // let byteCount = bitbox.BitcoinCash.getByteCount({ P2PKH: 2 }, { P2PKH: 2 }); + // let sendAmount = originalAmount - (byteCount * 15); + // transactionBuilder.addOutput(fixture.outputs[0], Math.floor(sendAmount / 2)); + // transactionBuilder.addOutput(fixture.outputs[1], Math.floor(sendAmount / 2)); + // let keyPair1 = bitbox.HDNode.toKeyPair(node1); + // let keyPair2 = bitbox.HDNode.toKeyPair(node2); + // let redeemScript; + // transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[0]); + // transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[1]); + // let tx = transactionBuilder.build(); + // let hex = tx.toHex(); + // assert.equal(hex, fixture.hex); + // }); + // }); + // }); + }) + + describe("#fromMany", (): void => { + describe("#Mainnet", (): void => { + fixtures.scripts.p2sh.fromMany.mainnet.forEach((fixture: any): void => { + it(`should create 2-to-1 P2SH transaction on mainnet`, (): void => { + const node1: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[0]) + const node2: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[1]) + const node3: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xprivs[2]) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const txid: string = fixture.txHash + const originalAmount: number = fixture.amount + const identifier1: Buffer = bitbox.HDNode.toIdentifier(node1) + const buf1: Buffer = bitbox.Script.encode([ + bitbox.Script.opcodes.OP_DUP, + bitbox.Script.opcodes.OP_HASH160, + identifier1, + bitbox.Script.opcodes.OP_EQUALVERIFY, + bitbox.Script.opcodes.OP_CHECKSIG + ]) + const scriptHash1: Buffer = bitbox.Crypto.hash160(buf1) + const data1 = bitbox.Script.scriptHash.output.encode(scriptHash1) + transactionBuilder.addInput( + txid, + 0, + transactionBuilder.DEFAULT_SEQUENCE, + data1 + ) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 3 }, + { P2PKH: 2 } + ) + const sendAmount: number = originalAmount - byteCount + const identifier2: Buffer = bitbox.HDNode.toIdentifier(node2) + const buf2: Buffer = bitbox.Script.encode([ + bitbox.Script.opcodes.OP_DUP, + bitbox.Script.opcodes.OP_HASH160, + identifier2, + bitbox.Script.opcodes.OP_EQUALVERIFY, + bitbox.Script.opcodes.OP_CHECKSIG + ]) + const scriptHash2: Buffer = bitbox.Crypto.hash160(buf2) + const data2 = bitbox.Script.scriptHash.output.encode(scriptHash2) + transactionBuilder.addInput( + txid, + 1, + transactionBuilder.DEFAULT_SEQUENCE, + data2 + ) + const identifier3: Buffer = bitbox.HDNode.toIdentifier(node3) + const buf3: Buffer = bitbox.Script.encode([ + bitbox.Script.opcodes.OP_DUP, + bitbox.Script.opcodes.OP_HASH160, + identifier3, + bitbox.Script.opcodes.OP_EQUALVERIFY, + bitbox.Script.opcodes.OP_CHECKSIG + ]) + const scriptHash3: Buffer = bitbox.Crypto.hash160(buf3) + const data3 = bitbox.Script.scriptHash.output.encode(scriptHash3) + transactionBuilder.addOutput(data3, sendAmount) + const keyPair1: bcl.ECPair = bitbox.HDNode.toKeyPair(node1) + const keyPair2: bcl.ECPair = bitbox.HDNode.toKeyPair(node2) + transactionBuilder.sign( + 0, + keyPair1, + buf1, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + transactionBuilder.sign( + 1, + keyPair2, + buf2, + transactionBuilder.hashTypes.SIGHASH_ALL, + originalAmount / 2 + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + // describe('#Testnet', () => { + // fixtures.scripts.p2sh.fromMany.testnet.forEach((fixture) => { + // it(`should create 2-to-1 P2SH transaction on testnet`, () => { + // let node1 = bitbox.HDNode.fromXPriv(fixture.xprivs[0]); + // let node2 = bitbox.HDNode.fromXPriv(fixture.xprivs[1]); + // let transactionBuilder = new bitbox.TransactionBuilder('testnet'); + // let txHash = fixture.txHash; + // let originalAmount = fixture.amounts[0] + fixture.amounts[1]; + // transactionBuilder.addInput(txHash, 0); + // transactionBuilder.addInput(txHash, 1); + // let byteCount = bitbox.BitcoinCash.getByteCount({ P2PKH: 2 }, { P2PKH: 1 }); + // let sendAmount = originalAmount - (byteCount * 15); + // transactionBuilder.addOutput(fixture.outputs[0], sendAmount); + // let keyPair1 = bitbox.HDNode.toKeyPair(node1); + // let keyPair2 = bitbox.HDNode.toKeyPair(node2); + // let redeemScript; + // transactionBuilder.sign(0, keyPair1, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[0]); + // transactionBuilder.sign(1, keyPair2, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, fixture.amounts[1]); + // let tx = transactionBuilder.build(); + // let hex = tx.toHex(); + // assert.equal(hex, fixture.hex); + // }); + // }); + // }); + }) + }) + + describe("#op_return", (): void => { + describe("#Mainnet", (): void => { + fixtures.nulldata.mainnet.forEach((fixture: any): void => { + it(`should create transaction w/ OP_RETURN output on mainnet`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const txHash: string = fixture.txHash + const originalAmount: number = fixture.amount + transactionBuilder.addInput(txHash, 0) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 5 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(fixture.output, sendAmount) + const data = fixture.data + let buf: Buffer = Buffer.from(data, "ascii") + const encoded: Buffer = bitbox.Script.encodeNullDataOutput(buf) + transactionBuilder.addOutput(encoded, 0) + const keyPair: bcl.ECPair = bitbox.HDNode.toKeyPair(node) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#Testnet", (): void => { + fixtures.nulldata.testnet.forEach((fixture: any): void => { + it(`should create transaction w/ OP_RETURN output on testnet`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("testnet") + const txHash: string = fixture.txHash + const originalAmount: number = fixture.amount + transactionBuilder.addInput(txHash, 0) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 5 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(fixture.output, sendAmount) + const data = fixture.data + let buf: Buffer = Buffer.from(data, "ascii") + const encoded: Buffer = bitbox.Script.encodeNullDataOutput(buf) + transactionBuilder.addOutput(encoded, 0) + const keyPair = bitbox.HDNode.toKeyPair(node) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + + describe("#RegTest", (): void => { + fixtures.nulldata.regtest.forEach((fixture: any): void => { + it(`should create transaction w/ OP_RETURN output on regtest`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder("regtest") + const txHash: string = fixture.txHash + const originalAmount: number = fixture.amount + transactionBuilder.addInput(txHash, 0) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 5 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(fixture.output, sendAmount) + const data = fixture.data + let buf: Buffer = Buffer.from(data, "ascii") + const encoded: Buffer = bitbox.Script.encodeNullDataOutput(buf) + transactionBuilder.addOutput(encoded, 0) + const keyPair = bitbox.HDNode.toKeyPair(node) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + }) + + describe("#bip66", (): void => { + fixtures.bip66.forEach((fixture: any): void => { + it(`should bip66 encode as ${fixture.DER}`, (): void => { + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const r: Buffer = Buffer.from(fixture.r, "hex") + const s: Buffer = Buffer.from(fixture.s, "hex") + const DER: Buffer = transactionBuilder.bip66.encode(r, s) + assert.equal(DER.toString("hex"), fixture.DER) + }) + }) + + fixtures.bip66.forEach((fixture: any): void => { + it(`should bip66 decode ${fixture.DER}`, (): void => { + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const buffer: Buffer = Buffer.from(fixture.DER, "hex") + const signature: any = transactionBuilder.bip66.decode(buffer) + assert.equal(signature.r.toString("hex"), fixture.r) + assert.equal(signature.s.toString("hex"), fixture.s) + }) + }) + + fixtures.bip66.forEach((fixture: any): void => { + it(`should bip66 check ${fixture.DER}`, (): void => { + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const buffer: Buffer = Buffer.from(fixture.DER, "hex") + assert.equal(transactionBuilder.bip66.check(buffer), true) + }) + }) + }) + + describe("#bip68", (): void => { + fixtures.bip68.encode.forEach((fixture: any): void => { + it(`should bip68 encode as ${fixture.result}`, (): void => { + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const obj: any = {} + obj[fixture.type] = fixture.value + const encode: any = transactionBuilder.bip68.encode(obj) + assert.equal(encode, fixture.result) + }) + }) + + fixtures.bip68.decode.forEach((fixture: any): void => { + it(`should bip68 decode ${fixture.result}`, (): void => { + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + const decode: any = transactionBuilder.bip68.decode(fixture.result) + assert.equal(Object.keys(decode)[0], fixture.type) + assert.deepEqual(decode[Object.keys(decode)[0]], fixture.value) + }) + }) + }) + + describe("#LockTime", (): void => { + describe("#Mainnet", (): void => { + fixtures.locktime.mainnet.forEach((fixture: any): void => { + it(`should create transaction with nLockTime on mainnet`, (): void => { + const node: bcl.HDNode = bitbox.HDNode.fromXPriv(fixture.xpriv) + const transactionBuilder: TransactionBuilder = new bitbox.TransactionBuilder() + + const txHash: string = fixture.txHash + const originalAmount: number = fixture.amount + transactionBuilder.addInput(txHash, 0, 1) + const byteCount: number = bitbox.BitcoinCash.getByteCount( + { P2PKH: 1 }, + { P2PKH: 1 } + ) + const sendAmount: number = originalAmount - byteCount + transactionBuilder.addOutput(fixture.output, sendAmount) + const lockTime = fixture.lockTime + transactionBuilder.setLockTime(lockTime) + const keyPair = bitbox.HDNode.toKeyPair(node) + let redeemScript: undefined + transactionBuilder.sign( + 0, + keyPair, + redeemScript, + transactionBuilder.hashTypes.SIGHASH_ALL, + fixture.amount + ) + const tx: any = transactionBuilder.build() + const hex: string = tx.toHex() + assert.equal(hex, fixture.hex) + }) + }) + }) + }) +}) diff --git a/test/unit/Util.ts b/test/unit/Util.ts new file mode 100644 index 00000000..e2fbc3c1 --- /dev/null +++ b/test/unit/Util.ts @@ -0,0 +1,126 @@ +// imports +import * as chai from "chai" +import { BITBOX, REST_URL } from "../../lib/BITBOX" +import { Util } from "../../lib/Util" +import * as util from "util" +import { AddressValidateResult } from "bitcoin-com-rest" +import axios from "axios" +import * as sinon from "sinon" + +// conts +const bitbox: BITBOX = new BITBOX() +const assert: Chai.AssertStatic = chai.assert +const mockData = require("./mocks/util-mock") + +util.inspect.defaultOptions = { + showHidden: true, + colors: true, + depth: 3 +} + +describe("#Util", (): void => { + let sandbox: any + beforeEach(() => (sandbox = sinon.sandbox.create())) + afterEach(() => sandbox.restore()) + + describe("#UtilConstructor", (): void => { + it("should create instance of Util", (): void => { + const util: Util = new Util() + assert.equal(util instanceof Util, true) + }) + + it("should have a restURL property", (): void => { + const util: Util = new Util() + assert.equal(util.restURL, REST_URL) + }) + }) + + describe(`#validateAddress`, (): void => { + it(`should return false for testnet addr on mainnet`, async () => { + // Mock the call to rest to prevent live network calls. + const resolved = new Promise(r => r({ data: mockData.invalid })) + sandbox.stub(axios, "get").returns(resolved) + + const address: string = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y` + + const result: + | AddressValidateResult + | AddressValidateResult[] = await bitbox.Util.validateAddress(address) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.hasAllKeys(result, ["isvalid"]) + if (!Array.isArray(result)) assert.equal(result.isvalid, false) + }) + + it(`should validate valid address`, async () => { + // Mock the call to rest to prevent live network calls. + const resolved = new Promise(r => r({ data: mockData.valid })) + sandbox.stub(axios, "get").returns(resolved) + + const address: string = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z` + + const result: + | AddressValidateResult + | AddressValidateResult[] = await bitbox.Util.validateAddress(address) + //console.log(`result: ${JSON.stringify(result,null,2)}`) + + assert.hasAllKeys(result, [ + "isvalid", + "address", + "scriptPubKey", + "ismine", + "iswatchonly", + "isscript" + ]) + if (!Array.isArray(result)) assert.equal(result.isvalid, true) + }) + + it(`should validate an array of addresses`, async () => { + // Mock the call to rest to prevent live network calls. + const testData = [mockData.valid, mockData.valid] + const resolved = new Promise(r => r({ data: testData })) + sandbox.stub(axios, "post").returns(resolved) + + const address: string[] = [ + `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`, + `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z` + ] + + const result: + | AddressValidateResult + | AddressValidateResult[] = await bitbox.Util.validateAddress(address) + + assert.isArray(result) + if (Array.isArray(result)) { + assert.hasAllKeys(result[0], [ + "isvalid", + "address", + "scriptPubKey", + "ismine", + "iswatchonly", + "isscript" + ]) + } + }) + + it(`should pass error from server to user`, async () => { + try { + // Mock out data for unit test, to prevent live network call. + sandbox + .stub(axios, "get") + .throws("error", "Input must be a string or array of strings.") + + const address: any = 15432 + + await bitbox.Util.validateAddress(address) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: ${util.inspect(err)}`) + assert.include( + err.message, + `Input must be a string or array of strings.` + ) + } + }) + }) +}) diff --git a/test/unit/fixtures/Address.json b/test/unit/fixtures/Address.json new file mode 100644 index 00000000..1d3a53e3 --- /dev/null +++ b/test/unit/fixtures/Address.json @@ -0,0 +1,292 @@ +{ + "legacyMainnetP2PKH": [ + "18xHZ8g2feo4ceejGpvzHkvXT79fi2ZdTG", + "1K7Qb1dWkiYwPrZhLws3uUKhxKEU7dRnbQ", + "1Au7gWXS2zAgFSdWwT5QnTNeasye16kxoG", + "174uecjfRgh1XkVBYFzZymkV1JwmFQ91s9", + "1KLXUPMdq4vaU3VoQzSvLUx2mub5qzFkTc", + "12AqNsGTyL6RDR8SDEtW9EyfYruFNZ9Sjs", + "1P3Lq89iP27S76ZMKonty4mpJMDHp3a9NE", + "14A8F8jHiipwnKLd2JEWqPvbGiS6FA7VoG", + "1KgRZzxLUvZqL8EuufmdxqSjh3tgURwD6d", + "1GMApiWJoTfQ21jbtVX3Qz8YtnGUuZAJtS" + ], + "legacyMainnetP2SH": [ + "3DA6RBcFgLwLTpnF6BRAee8w6a9H6JQLCm", + "3AbtU1JSaiQijyGT21stxpBRZj1hixWcGB", + "3KfgmLeczB525pV2tJLQ6RM5qFMLaB2Kn1", + "3Bsr5dvAJ2Q8CpHxJSZkNdgD12Tkb9TaR7", + "3J78iYD4i4ht8Btp8pyRx71jg5yrRTkQaM", + "3EGxduodZm6a9FLN1jdVxN8pT5orCmFdUK", + "3DWvzGWYJCY19Gc4LcN8noHGpxdjRbJeYe", + "3Aw9ePtWrH8EEJoF5HW8swW9VXxpF4dP54", + "3QTQE5rt7TZg7hXZ4DsTQ6mUUZCbFY2RiL", + "3EoWFm3GcTzDFBQ9KGVevhH1nuSxa14eFM" + ], + "legacyTestnetP2PKH": [ + "mhTg9sgNgvAGfmJs192oUzQWqAXHH5nqLE", + "mmpjQ24UyGGfJ39k44prH6W2A7y1qVaQti", + "muEnSveRwu8cEJSvXzDTJZQWrr7y9i331i", + "n3jZn7rb3Bjepap4TWo8pyqcwuxAw439HW", + "mqHUen3SUNjQkAPjMxZfSnuyd8cmcbL6fq", + "n4g3swxSebC9cDHXTjYQcx3tRAe4EPrZrZ", + "n2yNUahmfBFLLzrpcXpMh8Votw7zbKVHtX", + "mqYM6bu8Vw6xFTTPhbtxWPPmFN8BwpVQeE", + "mrVbyCMyB3vhDya4rYSxdM8qivEGfn7JSP", + "mnqGaf1SbPFh1tdXdeXd7pWhJUY2ite6SY" + ], + "legacyTestnetP2SH": [ + "2N7euSnwuJP93QmK5TD4AkWmaTfBbBLrxUs", + "2MuvMYTdyvuQVtTkZiETcMpYZTNKR91ZeHs", + "2NEk4XyMUvbfj8ZuwwnpWtjfCy6asbkNa5P", + "2MtEpQua9z1GKUFXPNb8ByyjvfUHBZ2LStE", + "2N5srSeydgwfaDK8Bpve8ztEe6aUbY98pyV", + "2NFkziu5KqJUYkgAa1AeJiKrgc7sETJGt1Q", + "2N9EHTPiA2TsUuucZrNpCDcPVPTaV99cy6B", + "2N8terd3UrDpDT94T8GsERU7NuXnXS8k2JF", + "2N8terd3UrDpDT94T8GsERU7NuXnXS8k2JF", + "2N21KeVfnAF93Q1ETQsaukKoZgnjVQjoDti" + ], + "cashaddrMainnetP2PKH": [ + "bitcoincash:qptnmya5wkly7xf97wm5ak23yqdsz3l2cyj7k9vyyh", + "bitcoincash:qrr2suh9yjsrkl2qp3p967uhfg6u0r6xxsn9h5vuvr", + "bitcoincash:qpkfg4kck99wksyss6nvaqtafeahfnyrpsj0ed372t", + "bitcoincash:qppgmuuwy07g0x39sx2z0x2u8e34tvfdxvy0c2jvx7", + "bitcoincash:qryj8x4s7vfsc864jm0xaak9qfe8qgk245y9ska57l", + "bitcoincash:qqxdgs9x9rx4v7g4ea5kxyprj2k9wnv695578lwmt8", + "bitcoincash:qrcugfh4prxzl8qzqazyth7ytuc6k4qqcg50etp609", + "bitcoincash:qq32y2h0ljtyyv4xkk07gtyrclv2xwq5sq3pqrzjes", + "bitcoincash:qrxwdlhfx5f4xsfnl0g887e5ccs5puy8sgj0z0md6k", + "bitcoincash:qz595e7jwa3q4vw26whn6zcz6x074669lgnnvjkz5m" + ], + "cashaddrMainnetP2SH": [ + "bitcoincash:pp7ushdxf5we8mcpaa3wqgsuqt639cu59ur5xu5fug", + "bitcoincash:ppsup5akyvql5w46q9eszd9fxpx970acpyqkw79vq2", + "bitcoincash:prznrkhnf6zqsap6l664ayzu2xue67ue4gv686sjyu", + "bitcoincash:pphmm80pznl6pnkmzakz3ahafydmvhwzcslea4v5mz", + "bitcoincash:pz6pr25g6mulp0kes9xnmsda0u4rf442ase2un89pl", + "bitcoincash:pz9qe6ys8x0l98zegf0a9rae4zenk95yp5dv5xjnk5", + "bitcoincash:pzqmjwk8929jtqt7ac7szjuawtswmxhtu5xxm64upf", + "bitcoincash:ppjk2e4nz47n50hpg8z6nt5hfjeajy4cyyp0p2tvnp", + "bitcoincash:prum0t7tqczlyaw2d30tmpj3je9q2xlzwcqk9wx83u", + "bitcoincash:pz8a837lttkvjksg0jjmmulqvfkgpqrcdgufy8ns5s" + ], + "cashaddrTestnetP2PKH": [ + "bchtest:qq24rpar9qas3vc9r8d4p0prhwaf7jmx2u22nzt946", + "bchtest:qpzj67wmlsq8uttddddapjjawyusureca59ug9cak8", + "bchtest:qztg9c4u3ldhg68mqgzrple6ae92hwnfe5m6kyejfd", + "bchtest:qrem2cg43ksmvlampheur8gfgdhhk57mygy26y7f2e", + "bchtest:qp4jf3n740kffkladul96xnq5dtrflg4x5w5rfy22r", + "bchtest:qrlqxnzuu6hvvg9qer0m093ywkjnu7wm7ypj7unqzc", + "bchtest:qr44nfr9egxt7h7lxdktf9kajds9fwdxxcved7827j", + "bchtest:qpklfd26u70ta4j7p4twxv2k5apx95p0qqgm8cf2sd", + "bchtest:qpuxsqzgq3j0a58tnmwpgcrwwyrkenalevaeknklfg", + "bchtest:qpgrlg0yqmdf4y8q980e57tx6v7vrvds2ug89n8w8q" + ], + "cashaddrTestnetP2SH": [ + "bchtest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqh2hmtpyr", + "bchtest:pqw4d37dy7ctnn589q4wwd3r4rj5tuy8vsyf9d9uhw", + "bchtest:pr4ua5qk33wp24vktxmjjhldwkuk58tdwsglmfwhp2", + "bchtest:pq9wgu3tcyudczuuvuntay9y66e39n5jes3ph5qsan", + "bchtest:pz9ga635kme08cpkvgfraqhktjg75dc8wgm0kvuzy0", + "bchtest:prm0gtpad38nllydatnly0s5843rpg825cet8n9axd", + "bchtest:pzh4gldj5ts484zmamz2utlm9jzky4lfj5juylxakr", + "bchtest:pz4euzfcklwvagv4dlqyg4uakjsnjd2euqgg69slyv", + "bchtest:pz4euzfcklwvagv4dlqyg4uakjsnjd2euqgg69slyv", + "bchtest:ppspszzx57drysgystphkzj6nhcx3qzn9cvagkwq0a" + ], + "cashaddrRegTestP2PKH": [ + "bchreg:qq24rpar9qas3vc9r8d4p0prhwaf7jmx2usk9rgkku", + "bchreg:qpzj67wmlsq8uttddddapjjawyusureca5lq7ymw4p", + "bchreg:qztg9c4u3ldhg68mqgzrple6ae92hwnfe5pxq96p2t", + "bchreg:qrem2cg43ksmvlampheur8gfgdhhk57myg7kv9a6fl", + "bchreg:qp4jf3n740kffkladul96xnq5dtrflg4x55g4g8ef9", + "bchreg:qrlqxnzuu6hvvg9qer0m093ywkjnu7wm7ymwgasnp7", + "bchreg:qr44nfr9egxt7h7lxdktf9kajds9fwdxxck9mlyea5", + "bchreg:qpklfd26u70ta4j7p4twxv2k5apx95p0qqj83e2ent", + "bchreg:qpuxsqzgq3j0a58tnmwpgcrwwyrkenalev89qj4v2w", + "bchreg:qpgrlg0yqmdf4y8q980e57tx6v7vrvds2ujmnjyayx" + ], + "hash160MainnetP2PKH": [ + "573d93b475be4f1925f3b74ed951201b0147eac1", + "c6a872e524a03b7d400c425d7b974a35c78f4634", + "6c9456d8b14aeb409086a6ce817d4e7b74cc830c", + "428df38e23fc879a25819427995c3e6355b12d33", + "c9239ab0f3130c1f5596de6ef6c502727022caad", + "0cd440a628cd567915cf6963102392ac574d9a2d", + "f1c426f508cc2f9c02074445dfc45f31ab5400c2", + "22a22aeffc964232a6b59fe42c83c7d8a3381480", + "cce6fee93513534133fbd073fb34c62140f08782", + "a85a67d277620ab1cad3af3d0b02d19feaeb45fa" + ], + "hash160MainnetP2SH": [ + "7dc85da64d1d93ef01ef62e0221c02f512e3942f", + "61c0d3b62301fa3aba01730134a9304c5f3fb809", + "c531daf34e8408743afeb55e905c51b99d7b99aa", + "6fbd9de114ffa0cedb176c28f6fd491bb65dc2c4", + "b411aa88d6f9f0bed9814d3dc1bd7f2a34d6aaec", + "8a0ce890399ff29c59425fd28fb9a8b33b16840d", + "81b93ac72a8b25817eee3d014b9d72e0ed9aebe5", + "656566b3157d3a3ee141c5a9ae974cb3d912b821", + "f9b7afcb0605f275ca6c5ebd8651964a051be276", + "8fd3c7df5aecc95a087ca5bdf3e0626c8080786a" + ], + "hash160TestnetP2PKH": [ + "155187a3283b08b30519db50bc23bbba9f4b6657", + "452d79dbfc007e2d6d6b5bd0ca5d71390e0f38ed", + "9682e2bc8fdb7468fb020430ff3aee4aabba69cd", + "f3b561158da1b67fbb0df3c19d09436f7b53db22", + "6b24c67eabec94dbfd6f3e5d1a60a35634fd1535", + "fe034c5ce6aec620a0c8dfb7962475a53e79dbf1", + "eb59a465ca0cbf5fdf336cb496dd936054b9a636", + "6df4b55ae79ebed65e0d56e33156a74262d02f00", + "786800480464fed0eb9edc14606e71076ccfbfcb", + "503fa1e406da9a90e029df9a7966d33cc1b1b057" + ], + "hash160TestnetP2SH": [ + "9e0c43e304fd71d6b78404efd7eea0f5c6d91a10", + "1d56c7cd27b0b9ce87282ae73623a8e545f08764", + "ebced0168c5c15559659b7295fed75b96a1d6d74", + "0ae4722bc138dc0b9c6726be90a4d6b312ce92cc", + "8a8eea34b6f2f3e03662123e82f65c91ea370772", + "f6f42c3d6c4f3ffc8deae7f23e143d6230a0eaa6", + "af547db2a2e153d45beec4ae2ffb2c856257e995", + "ab9e0938b7dccea1956fc044579db4a1393559e0", + "ab9e0938b7dccea1956fc044579db4a1393559e0", + "60180846a79a32410482c37b0a5a9df06880532e" + ], + "mainnetXPub": [ + { + "xpub": "xpub6CVcpZVmPNjuniVYu1mLnLjDBfxWpx7LS25uxwRm5BLbXMCJmRaQgAxuqZDoYDeidJUh5QUatLJPWpeCkEK648hExyKFezqxJz4CMfEoYAc", + "addresses": [ + "bitcoincash:qp3c2e0ehq5lqgnf2v8kqk0qemkatnknmga3mwqkms", + "bitcoincash:qznkqj05zsx8uszyjfdyvfn55ecwltfsrq93jhwchv", + "bitcoincash:qpkvr2gs84g6nltzcs9d9ef7qerh7qqenca2zddlpz", + "bitcoincash:qpuchd6als5yc3fs55aktwylr20u0antyu5f99jt8k", + "bitcoincash:qq670p9knuarh75ae7er4c246w909nd0z5gx6h60vv" + ] + }, + { + "xpub": "xpub6CVcpZVmPNjuqYFnvSYoD9hE89PKmsWewFWGKeaCcVNSfDTgQgMuhm8Q2zreBsNQVMSJrBmQ3C95fi3SiRXYRQckQJMZuPXTJm9TcQejW13", + "addresses": [ + "bitcoincash:qqhkcs5fnchh99p68mcszcz68cecef5jfyeugnyysl", + "bitcoincash:qqxj4w8lgctdhpvl9um9w7tvgmc9se3ttcfkdfcv5e", + "bitcoincash:qp30m7fu27vljfqvqq26kwn8f4zp4g7wngqdzn40xh", + "bitcoincash:qrvtu7nw8x5343c9jgc5a58zw5vw3susful9x9yhrv", + "bitcoincash:qrjcyuxunxzt2w35ney2hzrvgynrcqg5qqj9366m6a" + ] + }, + { + "xpub": "xpub6CVcpZVmPNjuu1zjt9joxDzDrP9UNs6GVS5K1jSopnq76RBZswLsxy75qvJTVcSS6V9Y4Df6L7GDsbns99WrLrfmBNwocEdQm5CXFGExAgq", + "addresses": [ + "bitcoincash:qp3d5t96fdvjkurpt2h0t8nw5u4hr294q5q4dw6g9r", + "bitcoincash:qpusevag7l73543hs2lw69aqx4kzlsxamyg785mnsa", + "bitcoincash:qp48wzx62956wqux569mhm7dzyykya35aghd0y6qxf", + "bitcoincash:qqxd6u4lap7s9zcm8jdkd44uakyghcw8hqawurftc6", + "bitcoincash:qrn4gf9ufqp3ze4refp6yqh60s47crcwksqp20txs7" + ] + } + ], + "testnetXPub": [ + { + "xpub": "tpubDCrnMSKwDMAbxg82yqDt97peMvftCXk3EfBb9WgZh27mPbHGkysU3TW7qX5AwydmnVQfaGeNhUR6okQ3dS5AJTP9gEP7jk2Wcj6Xntc6gNh", + "addresses": [ + "bchtest:qrth8470sc9scek9u0jj2d0349t62gxzdstw2jukl8", + "bchtest:qpm56zc5re0nhms96r7p985aajthp0vxvg6e4ux3kc", + "bchtest:qqtu3tf6yyd73ejhk3a2ylqynpl3mzzhwuzt299jfd", + "bchtest:qzd7dvlnfukggjqsf5ju0qqwwltakfumjsck33js6m", + "bchtest:qq322ataqeas4n0pdn4gz2sdereh5ae43ylk4qdvus" + ] + }, + { + "xpub": "tpubDCrnMSKwDMAbzuN7eQDcFh9c6BsUvHHiL7j1AE9f9mE2ertgK6DwAZ6xmqtM3G5ifPkVynnjhMMMS87R1x4DTPrCbp4VjBttqMc4KmQEMRv", + "addresses": [ + "bchtest:qq2lnfskh8herq7hhj067uzfmhg2cf6arvc8eld50k", + "bchtest:qrjqt3vw8us9nc4d3h8j5fn6cxa0h5485ydd5zhq8y", + "bchtest:qze485w97jjhpucgk9dmh7h4fx56z8tmvgv4c3esmm", + "bchtest:qp6dvdwfu02z6d8cp6uqkpnjde66m89t9cexm00fmd", + "bchtest:qz266xueu99z6mh8af66gwnsv48jxva6aslmju2wat" + ] + }, + { + "xpub": "tpubDCrnMSKwDMAc4zKRDfxDqmzzxwLd85MFYF3cHzmdGDchnS7Sz2UiHD6HqaJR5Lefq6BhApPvGsdp3smjE1KRNkWHZ4wWogt7UYrgVznGfs1", + "addresses": [ + "bchtest:qqzkac72c0dygl92ru74zmwkkhdq7sc845n43ulmlw", + "bchtest:qzsm0ymr035a5eg0r8k4hxvyaxqyd0e8msd7f79v2z", + "bchtest:qqg6yea05gkqyxwdce6k5sjun8k9drgzn54d63cq5n", + "bchtest:qrfumvznl5ck903vq3sp3gfsrjt22tqa85lxzjv4p9", + "bchtest:qrd88na4869phkr0h44kzfakwc52w2jwmqjl6vlynn" + ] + } + ], + "p2shMainnet": [ + "bitcoincash:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqncnufkrl" + ], + "p2shTestnet": [ + "bchtest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqh2hmtpyr" + ], + "mainnetXPriv": [ + { + "xpriv": "xprvA2WwD9mk1Qd3rMjQ4ZRHvCWCj47jbXjY9Nf7npNRBmGUJngpRAvJzNpNgt7h2dDQ5huG7yFwYfz4PFJDPzkqfvBNPHnaio4yAbbUuv3EBnL", + "addresses": [ + "bitcoincash:qpmcs78tpfvfphhedcczydaddu5wmcx0xvrwf3fjph", + "bitcoincash:qppfr7fu4dzxguen85rjwa6ress3sl839qyudganxj", + "bitcoincash:qpuaaaseccxyjj04d2l3qv4vd2wxj6gtwvnfe3ckh8", + "bitcoincash:qp46n7a53jvkarp9ps595fjv8czfd045v5zk4xhspm", + "bitcoincash:qprjdqx7cnrac4uemp2fza08k875wsgzfcapk76n9n" + ] + }, + { + "xpriv": "xprvA2WwD9mk1Qd3uh37mpp8ARSm16SfFBBW8dkns7P16YHocvSPm3EY99LFRLo8YvVUuRmEY72a28SnjAtA4TrvQNVt9dmaHFGkHgddoxKKFvC", + "addresses": [ + "bitcoincash:qr5p7wn3yg3hm05r9l7hp5el9ydxpy2ta53eyypyth", + "bitcoincash:qqjr8tr6he0p5aktut3ltzc0z9j05umqnge98c4a9x", + "bitcoincash:qpuka8vzq8p6ejmv4a6z4thcge39p8f92gdakccmhh", + "bitcoincash:qr9nxah3jum93yxyhysrm97822vtlyvkrsw6ayp0fu", + "bitcoincash:qre22kwsrm0z8gzm4hh48nqgcsrd7ygf3sv8wwesmv" + ] + }, + { + "xpriv": "xprvA2WwD9mk1Qd3vbDhZ2wDcNeytiPVBQZSAANwH1NmKwmD29bEXXLPwREDPzzfp7ctAArHLMUr2U97L8gF9NjpaSQj4y2u58x2VBwzYjWo1Z9", + "addresses": [ + "bitcoincash:qquypq4yd8y77jn5dvffdxjy4zpjvpeewsm6p9ly6f", + "bitcoincash:qqy9pdfekyajmhh6hj0lw2fstefkf3ta6gm6g88tnu", + "bitcoincash:qqy37k7emj48yj2zpttcnsj2lkr0un0d5y92s2je0d", + "bitcoincash:qrn3vr8sckvj3vz9gawd0tjv04xp9h7fs5ewngp03q", + "bitcoincash:qq5r94w8kjnk8d84knyg2xa5qrddxy7myqe0gg6gsf" + ] + } + ], + "testnetXPriv": [ + { + "xpriv": "tprv8jBszV65QgT8TAxvj8Go5r8C3BXwq3mYUvaEfEnsfjkx6PRuQYG4W8Bpc4HM2zbiT9S384shi2Zrr6qxXD6nUySxuvztP9o25hLuMcDvMYD", + "addresses": [ + "bchtest:qpmcs78tpfvfphhedcczydaddu5wmcx0xv8udkt9xt", + "bchtest:qppfr7fu4dzxguen85rjwa6ress3sl839qqwf0lypw", + "bchtest:qpuaaaseccxyjj04d2l3qv4vd2wxj6gtwvhmak6psm", + "bchtest:qp46n7a53jvkarp9ps595fjv8czfd045v5xy3p48x8", + "bchtest:qprjdqx7cnrac4uemp2fza08k875wsgzfcenjecyz0" + ] + }, + { + "xpriv": "tprv8jBszV65QgT8WWGeSPfdL54kKDrsUhDWUBfujXoTaWnHQXBUkQaHethhLWxnZHsoGsJ1YCeLBV2bC2RuBgCsDRmUgGyswbzoCnP4Fe3yuLv", + "addresses": [ + "bchtest:qr5p7wn3yg3hm05r9l7hp5el9ydxpy2ta54tqrrnvt", + "bchtest:qqjr8tr6he0p5aktut3ltzc0z9j05umqngahrlh2z6", + "bchtest:qpuka8vzq8p6ejmv4a6z4thcge39p8f92gf0jl6vst", + "bchtest:qr9nxah3jum93yxyhysrm97822vtlyvkrs2gerrcwq", + "bchtest:qre22kwsrm0z8gzm4hh48nqgcsrd7ygf3sg42fm8us" + ] + }, + { + "xpriv": "tprv8jBszV65QgT8XQTEDbnin2GyCqohQvbSViJ49RoDovFgokLKWtg9TAbfKBAKpV1CXcP4LT6cBpiunzDzGb5mPVgKbcFCjVg5QHhQzPRPmLb", + "addresses": [ + "bchtest:qquypq4yd8y77jn5dvffdxjy4zpjvpeewslg9zana4", + "bchtest:qqy9pdfekyajmhh6hj0lw2fstefkf3ta6glgvq9u5q", + "bchtest:qqy37k7emj48yj2zpttcnsj2lkr0un0d5ypc5dswg3", + "bchtest:qrn3vr8sckvj3vz9gawd0tjv04xp9h7fs5auh0rcku", + "bchtest:qq5r94w8kjnk8d84knyg2xa5qrddxy7myqaav0clh4" + ] + } + ] +} \ No newline at end of file diff --git a/test/fixtures/BitcoinCash.json b/test/unit/fixtures/BitcoinCash.json similarity index 84% rename from test/fixtures/BitcoinCash.json rename to test/unit/fixtures/BitcoinCash.json index b9705c90..d53c6f3c 100644 --- a/test/fixtures/BitcoinCash.json +++ b/test/unit/fixtures/BitcoinCash.json @@ -60,36 +60,36 @@ [0.00065432, 65432] ] }, - "toBits": { + "satsToBits": { "bch": [ - [42.423234, 42423.2340], - [1, 1000.0000], - [3.14, 3140.0000], - [9876, 9876000.0000], - [0.000123, 0.1230] + [42.423234, 42423234], + [1, 1000000], + [3.14, 3140000], + [9876, 9876000000], + [0.000123, 123] ], "strings": [ - ["42.423234", "42423.2340"], - ["1", "1000.0000"], - ["3.14", "3140.0000"], - ["9876", "9876000.0000"], - ["0.000123", "0.1230"] + ["42.423234", "42423234"], + ["1", "1000000"], + ["3.14", "3140000"], + ["9876", "9876000000"], + ["0.000123", "123"] ] }, - "fromBits": { + "satsFromBits": { "bch": [ - [42.423234, 42423.2340], - [1, 1000.0000], - [3.14, 3140.0000], - [9876, 9876000.0000], - [0.000123, 0.1230] + [4242324, 42423.2340], + [100000, 1000.0000], + [314000, 3140.0000], + [987600000, 9876000.0000], + [12.3, 0.1230] ], "strings": [ - ["42.423234", "42423.2340"], - ["1", "1000.0000"], - ["3.14", "3140.0000"], - ["9876", "9876000.0000"], - ["0.000123", "0.1230"] + ["4242324", "42423.2340"], + ["100000", "1000.0000"], + ["314000", "3140.0000"], + ["987600000", "9876000.0000"], + ["12.3", "0.1230"] ] } }, @@ -297,6 +297,56 @@ }, "url": "bitcoincash:qphgz6ut3uu9xu8sly2zj7n5jkg5eyes5vjv3juf0x?amount=20.3&label=Foobar" } + ], + "valid_regtest": [ + { + "address": "1C6hRmfzvWst5WA7bFRCVAqHt5gE2g7Qar", + "options": { + "amount": 12.5, + "label": "coinbase donation", + "message": "and ya don't stop" + }, + "url": "bchreg:qpum6dwnqmmysdggrprse8ccjq7ldcrfqg94ewelh7?amount=12.5&label=coinbase%20donation&message=and%20ya%20don%27t%20stop" + }, + { + "address": "1Azo2JBz2JswboeY9xSMcp14BAfhjnD9SK", + "options": { + "label": "Foobar" + }, + "url": "bchreg:qpk6wsngptx0y2pd7hadar5m0gq629l80y59284j0h?label=Foobar" + }, + { + "address": "bchreg:qrdsfshx7yzfjl9sfj2khuja5crcu4vaxqa9cxhxs2", + "options": { + "amount": 1, + "label": "test" + }, + "url": "bchreg:qrdsfshx7yzfjl9sfj2khuja5crcu4vaxqa9cxhxs2?amount=1&label=test" + }, + { + "address": "bchreg:qzc5fxdm6lnwzgeju4jaemngtxkkkgt78uxag2hkxw", + "options": { + "amount": 3, + "label": "hhhhhhh" + }, + "url": "bchreg:qzc5fxdm6lnwzgeju4jaemngtxkkkgt78uxag2hkxw?amount=3&label=hhhhhhh" + }, + { + "address": "qzw6tfrh8p0jh834uf9rhg77pjg5rgnt3qsptj5ctt", + "options": { + "amount": 23, + "label": "no prefix" + }, + "url": "bchreg:qzw6tfrh8p0jh834uf9rhg77pjg5rgnt3qsptj5ctt?amount=23&label=no%20prefix" + }, + { + "address": "qphgz6ut3uu9xu8sly2zj7n5jkg5eyes5vvzr5adtu", + "options": { + "amount": 20.3, + "label": "Foobar" + }, + "url": "bchreg:qphgz6ut3uu9xu8sly2zj7n5jkg5eyes5vvzr5adtu?amount=20.3&label=Foobar" + } ] }, "getByteCount": [ @@ -352,11 +402,6 @@ "bip38": { "encrypt": { "mainnet": [ - { - "wif": "5KN7MzqK5wt2TP1fQCYyHBtDrXdJuXbUzm4A9rKAteGu3Qi5CVR", - "password": "TestingOneTwoThree", - "encryptedKey": "6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg" - }, { "wif": "L1XHKhaBAfkr2FJQn3pTfCMxz652WYfmvKj8xDCHCEDV9tWGcbYj", "password": "1EBPIyj55eR8bVUov9", @@ -369,11 +414,6 @@ } ], "testnet": [ - { - "wif": "cRQeGr3Wv91dUF94zy2EEP7rgwVsqNnZa3MtM7Civxdk74gNEPNn", - "password": "TestingOneTwoThree", - "encryptedKey": "6PYXFe1CdGMuVrLCvTo47JUpqcp7sEK7QxE9m4zHHkzUbgqVXVuTUAJh9T" - }, { "wif": "cSx7KzdH9EcvDEireu2WYpGnXdFYpta7sJUNt5kVCJgA7kcAU8Gm", "password": "1EBPIyj55eR8bVUov9", @@ -388,11 +428,6 @@ }, "decrypt": { "mainnet": [ - { - "wif": "5KN7MzqK5wt2TP1fQCYyHBtDrXdJuXbUzm4A9rKAteGu3Qi5CVR", - "password": "TestingOneTwoThree", - "encryptedKey": "6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg" - }, { "wif": "L1XHKhaBAfkr2FJQn3pTfCMxz652WYfmvKj8xDCHCEDV9tWGcbYj", "password": "1EBPIyj55eR8bVUov9", @@ -405,11 +440,6 @@ } ], "testnet": [ - { - "wif": "cRQeGr3Wv91dUF94zy2EEP7rgwVsqNnZa3MtM7Civxdk74gNEPNn", - "password": "TestingOneTwoThree", - "encryptedKey": "6PYXFe1CdGMuVrLCvTo47JUpqcp7sEK7QxE9m4zHHkzUbgqVXVuTUAJh9T" - }, { "wif": "cSx7KzdH9EcvDEireu2WYpGnXdFYpta7sJUNt5kVCJgA7kcAU8Gm", "password": "1EBPIyj55eR8bVUov9", diff --git a/test/fixtures/Blockchain.json b/test/unit/fixtures/Blockchain.json similarity index 100% rename from test/fixtures/Blockchain.json rename to test/unit/fixtures/Blockchain.json diff --git a/test/fixtures/Crypto.json b/test/unit/fixtures/Crypto.json similarity index 81% rename from test/fixtures/Crypto.json rename to test/unit/fixtures/Crypto.json index 11316bb3..0e47ad7a 100644 --- a/test/fixtures/Crypto.json +++ b/test/unit/fixtures/Crypto.json @@ -1,4 +1,26 @@ { + "sha1": [ + { + "hash": "c0357a32ed1f6a03be92dd094476f7f1a2e214ec", + "hex": "0101010101010101" + }, + { + "hash": "98eeed798ee958d1653edf2d857d4aeaba971932", + "hex": "031ad329b3117e1d1e2974406868e575d48cff88e8128ba0eedb10da053785033b" + }, + { + "hash": "26b0780a683a1e098e9cb8cfa1b0924228250097", + "hex": "03123464075c7a5fa6b8680afa2c962a02e7bf071c6b2395b0ac711d462cac9354" + }, + { + "hash": "a7f2850b1724e2c17d005d8fa54c9b35780fa579", + "hex": "03ea9277ebf3d6edd26847fb109494def7d458f05e6e4fba381c094ce703c62248" + }, + { + "hash": "c8678dc140c8d611cf96f0d500b05d8254544a33", + "hex": "020379254cc10ef94976192ab42cab25f65ba4438e4b2b4610debd145d2bdb8d53" + } + ], "sha256": [ { "hash": "04abc8821a06e5a30937967d11ad10221cb5ac3b5273e434f1284ee87129a061", diff --git a/test/fixtures/ECPair.json b/test/unit/fixtures/ECPair.json similarity index 67% rename from test/fixtures/ECPair.json rename to test/unit/fixtures/ECPair.json index 36539cb9..757a2e35 100644 --- a/test/fixtures/ECPair.json +++ b/test/unit/fixtures/ECPair.json @@ -3,27 +3,32 @@ { "privateKeyWIF": "L5PKiCuwwgmVN1GQNg8CdR6Rmg7tg1Npw7GyL5ULRPZ5EVPhtSrz", "legacy": "1P23VhvFLH18qP7YRCPDWPwA9TCJjmp9B5", - "cashAddr": "bitcoincash:qrcc23q0w7wgld690kduxvhetu0am523c5ufq5pes4" + "cashAddr": "bitcoincash:qrcc23q0w7wgld690kduxvhetu0am523c5ufq5pes4", + "regtestAddr": "bchreg:qrcc23q0w7wgld690kduxvhetu0am523c5z8jjqa50" }, { "privateKeyWIF": "L1SD3NYLMcoqpUzn2hwJ7c1Vb4pPiqMToSMyGMTcbcvRBDh9U9SP", "legacy": "14tqru6iL3KX2m4nKg36tfLFe13J1d1uwu", - "cashAddr": "bitcoincash:qq4tvcxq5z35pkfj65a2elyy8xpn0r55r59r5he7nz" + "cashAddr": "bitcoincash:qq4tvcxq5z35pkfj65a2elyy8xpn0r55r59r5he7nz", + "regtestAddr": "bchreg:qq4tvcxq5z35pkfj65a2elyy8xpn0r55r5mdx3c6hc" }, { "privateKeyWIF": "L57L3Xtu3j1Z2B2RuQzc59JLQXJQ86TH8To1hM348URbC2iCZqLe", "legacy": "135cNoFyxcwJ88BQsJd7c6qKfSBgRK7cCT", - "cashAddr": "bitcoincash:qqtv7uskar0nd8hyflesg7wq4uuqwdmtyg4hsx9kge" + "cashAddr": "bitcoincash:qqtv7uskar0nd8hyflesg7wq4uuqwdmtyg4hsx9kge", + "regtestAddr": "bchreg:qqtv7uskar0nd8hyflesg7wq4uuqwdmtygtezqyjvr" }, { "privateKeyWIF": "KzTm29RBrSgUbMyeJL9sCNUnc7LQEuDeT6Upq1iUwx78qWRdRzyW", "legacy": "1NbRysVu1cy8A8mjrLh4z649HqG6DrX9Z", - "cashAddr": "bitcoincash:qqzp270mhkglttfaysmt985aykwjhndw0ulmgr5g5d" + "cashAddr": "bitcoincash:qqzp270mhkglttfaysmt985aykwjhndw0ulmgr5g5d", + "regtestAddr": "bchreg:qqzp270mhkglttfaysmt985aykwjhndw0up4694vsh" }, { "privateKeyWIF": "L4BwXDmjzEyzKHbAfGruhieUDPs8KTx7DMgqPk4aF9GefzgqPENV", "legacy": "1FoZGWj8rgrimR7W383LNSLUfdPCjKAXLK", - "cashAddr": "bitcoincash:qz39l492msv9zz838t8ltx2w4zmycnqhwck4fnnyym" + "cashAddr": "bitcoincash:qz39l492msv9zz838t8ltx2w4zmycnqhwck4fnnyym", + "regtestAddr": "bchreg:qz39l492msv9zz838t8ltx2w4zmycnqhwcgmm4jqqp" } ], "toWIF": [ @@ -47,34 +52,39 @@ { "pubkeyHex": "02fb721b92025e775b1b84774e65d568d24645cb633275f5c26f5c3101b214a8fb", "legacy": "1SeP7kmdWTwjFmWiRMpqtSkDpW39zrVLK", - "cashAddr": "bitcoincash:qqzdnxncgm3v247u5v0gqnglr2vpdhe0hu4wl0rmwt" + "cashAddr": "bitcoincash:qqzdnxncgm3v247u5v0gqnglr2vpdhe0hu4wl0rmwt", + "regtestAddr": "bchreg:qqzdnxncgm3v247u5v0gqnglr2vpdhe0hutqdfzl23" }, - { + { "pubkeyHex": "02d305772e0873fba6c1c7ff353ce374233316eb5820acd7ff3d7d9b82d514126b", "legacy": "1GpugKfjEycPRhk8A8ALPh1zAJmTQGdJPp", - "cashAddr": "bitcoincash:qzkej6g2zr9c9k83chyqh5pllzv6pkw62ckf2m82ks" + "cashAddr": "bitcoincash:qzkej6g2zr9c9k83chyqh5pllzv6pkw62ckf2m82ks", + "regtestAddr": "bchreg:qzkej6g2zr9c9k83chyqh5pllzv6pkw62cg8caxwj2" }, { "pubkeyHex": "02d305772e0873fba6c1c7ff353ce374233316eb5820acd7ff3d7d9b82d514126b", "legacy": "1GpugKfjEycPRhk8A8ALPh1zAJmTQGdJPp", - "cashAddr": "bitcoincash:qzkej6g2zr9c9k83chyqh5pllzv6pkw62ckf2m82ks" + "cashAddr": "bitcoincash:qzkej6g2zr9c9k83chyqh5pllzv6pkw62ckf2m82ks", + "regtestAddr": "bchreg:qzkej6g2zr9c9k83chyqh5pllzv6pkw62cg8caxwj2" }, { "pubkeyHex": "033c071f19057f11140f80308031fa58b6e7d8f9e889252805cae6a29c1248f843", "legacy": "15NQKRj7rAVsFL5rWMmhkAgx2K1dYoHoDW", - "cashAddr": "bitcoincash:qqh7evl4w7h6lsu7uvakvadm0z5hj535lqk098l670" + "cashAddr": "bitcoincash:qqh7evl4w7h6lsu7uvakvadm0z5hj535lqk098l670", + "regtestAddr": "bchreg:qqh7evl4w7h6lsu7uvakvadm0z5hj535lqgphp7764" }, { "pubkeyHex": "024933d7cc962415fda8249d6ee6820009fb6f0cf592385d91f8d9f39de507b7e1", "legacy": "14sq5dL1TeFdQJpj3vVMQvjrdmQoqVoM6m", - "cashAddr": "bitcoincash:qq4g2nmk64wt7a2mx85cl07n45nkh2p7lcytfgmqdl" + "cashAddr": "bitcoincash:qq4g2nmk64wt7a2mx85cl07n45nkh2p7lcytfgmqdl", + "regtestAddr": "bchreg:qq4g2nmk64wt7a2mx85cl07n45nkh2p7lc69mw6yf9" } ], "toPublicKey": [ { "pubkeyHex": "02fb721b92025e775b1b84774e65d568d24645cb633275f5c26f5c3101b214a8fb" }, - { + { "pubkeyHex": "02d305772e0873fba6c1c7ff353ce374233316eb5820acd7ff3d7d9b82d514126b" }, { @@ -112,45 +122,60 @@ "toCashAddress": [ { "privateKeyWIF": "L5PKiCuwwgmVN1GQNg8CdR6Rmg7tg1Npw7GyL5ULRPZ5EVPhtSrz", - "cashAddr": "bitcoincash:qrcc23q0w7wgld690kduxvhetu0am523c5ufq5pes4" + "cashAddr": "bitcoincash:qrcc23q0w7wgld690kduxvhetu0am523c5ufq5pes4", + "regtestAddr": "bchreg:qrcc23q0w7wgld690kduxvhetu0am523c5z8jjqa50" }, { "privateKeyWIF": "L1SD3NYLMcoqpUzn2hwJ7c1Vb4pPiqMToSMyGMTcbcvRBDh9U9SP", - "cashAddr": "bitcoincash:qq4tvcxq5z35pkfj65a2elyy8xpn0r55r59r5he7nz" + "cashAddr": "bitcoincash:qq4tvcxq5z35pkfj65a2elyy8xpn0r55r59r5he7nz", + "regtestAddr": "bchreg:qq4tvcxq5z35pkfj65a2elyy8xpn0r55r5mdx3c6hc" }, { "privateKeyWIF": "L57L3Xtu3j1Z2B2RuQzc59JLQXJQ86TH8To1hM348URbC2iCZqLe", - "cashAddr": "bitcoincash:qqtv7uskar0nd8hyflesg7wq4uuqwdmtyg4hsx9kge" + "cashAddr": "bitcoincash:qqtv7uskar0nd8hyflesg7wq4uuqwdmtyg4hsx9kge", + "regtestAddr": "bchreg:qqtv7uskar0nd8hyflesg7wq4uuqwdmtygtezqyjvr" }, { "privateKeyWIF": "KzTm29RBrSgUbMyeJL9sCNUnc7LQEuDeT6Upq1iUwx78qWRdRzyW", - "cashAddr": "bitcoincash:qqzp270mhkglttfaysmt985aykwjhndw0ulmgr5g5d" + "cashAddr": "bitcoincash:qqzp270mhkglttfaysmt985aykwjhndw0ulmgr5g5d", + "regtestAddr": "bchreg:qqzp270mhkglttfaysmt985aykwjhndw0up4694vsh" }, { "privateKeyWIF": "L4BwXDmjzEyzKHbAfGruhieUDPs8KTx7DMgqPk4aF9GefzgqPENV", - "cashAddr": "bitcoincash:qz39l492msv9zz838t8ltx2w4zmycnqhwck4fnnyym" + "cashAddr": "bitcoincash:qz39l492msv9zz838t8ltx2w4zmycnqhwck4fnnyym", + "regtestAddr": "bchreg:qz39l492msv9zz838t8ltx2w4zmycnqhwcgmm4jqqp" } ], "sign": [ { "privateKeyWIF": "L5PKiCuwwgmVN1GQNg8CdR6Rmg7tg1Npw7GyL5ULRPZ5EVPhtSrz", - "data": "EARTH" + "data": "EARTH", + "sig": "30440220446688759b77ffe7edbc5474e9c5ef4e5ff30a0e94ff00683805251a87ac5354022010f9ad79febed064f8ee08ba8828823791cc78f6015042bb32acb5e698b54e58", + "schnorrSig": "30450220184a9eea7d537fcb05dab738f2849cfee07cbc62ebc47d37456802aaa2c11ed8022100a51f6761a5faa59a5b3b758f5f4203a1f2fb3e1bd470620019feb894ac3db517" }, { "privateKeyWIF": "L1SD3NYLMcoqpUzn2hwJ7c1Vb4pPiqMToSMyGMTcbcvRBDh9U9SP", - "data": "foobar" + "data": "foobar", + "sig": "304402200ef2cc2855b22d66a11b3b5a79d9c0cf343758643083f34c5d93c714552775ec022079fa60786fd721ab0de032341f6affe1c40706a4baf4f15d4fd5355dd6c348a5", + "schnorrSig": "3045022014aa729fd5763ca0469ed580bcc7f36d85cb55b57d9fe10c2046f162a216b76f022100c25062e7fb18c45e43911fb66d17d51450813adf04d9e00be2903bf2de829fd8" }, { "privateKeyWIF": "L57L3Xtu3j1Z2B2RuQzc59JLQXJQ86TH8To1hM348URbC2iCZqLe", - "data": "12334567890" + "data": "12334567890", + "sig": "3045022100aacab383dde3afb59eb5b0b983037b1b3a85c542ec111f6d3c45b86606eb747202200454ec2396aec5b3ed88aa562c469f8716b043f7be38c0b6a50ef8d0ae9a558c", + "schnorrSig": "3045022100ed4937f067e7861fb6b2e2ec23474836b8dea041d3da4ee85751356836def65d0220744c07eca5b26f0530b331da67a6a6e3533b3f4327851336f62253da84dd1031" }, { "privateKeyWIF": "KzTm29RBrSgUbMyeJL9sCNUnc7LQEuDeT6Upq1iUwx78qWRdRzyW", - "data": "Be excellent to each other" + "data": "Be excellent to each other", + "sig": "3045022100ead14e40a8ea1ce6eac0e2a0e9f582fb40b4ba4d90066f50d5058307cdf6e8c7022071dc89d5b34dab7078fef8c52beb4ed1d1a14a68c5525441f5a64304f81706b7", + "schnorrSig": "3045022100ee0e8fc04f5cf581d35f6ee4049a695b2553bd6a884b1ef26322cf71169e7c0302203fffdc6cde5ec951896a9d4bd2b2a01f29ec13ec1f3be47464593ce6dbdf7aea" }, { "privateKeyWIF": "L4BwXDmjzEyzKHbAfGruhieUDPs8KTx7DMgqPk4aF9GefzgqPENV", - "data": "satoshi" + "data": "satoshi", + "sig": "30450221008abcfc3dcb6418455d1a9a891d07f010d7884f8051b5be8992e2074035918051022069f4013f97febc79fc63cf125d7b2a1f37453c781bc09cf7410ff934e3502108", + "schnorrSig": "3046022100a48001d46928e336b0d4f04747d21f717fd097fddb2e5bfd012a03cea9bc5eb20221009a1314e41785b58706241797bf64c6510367bafaeb1afb7460a28c8dccb617b2" } ], "verify": [ diff --git a/test/fixtures/HDNode.json b/test/unit/fixtures/HDNode.json similarity index 96% rename from test/fixtures/HDNode.json rename to test/unit/fixtures/HDNode.json index a93f769e..b6f05bc8 100644 --- a/test/fixtures/HDNode.json +++ b/test/unit/fixtures/HDNode.json @@ -237,23 +237,28 @@ "toCashAddress": [ { "mnemonic": "rare dinosaur army fat spend average design order ritual town brave spike", - "address": "bitcoincash:qze9zznaqzdne2awnlnygt0p74dkc3e4svm9ty58nx" + "address": "bitcoincash:qze9zznaqzdne2awnlnygt0p74dkc3e4svm9ty58nx", + "regtestAddress": "bchreg:qze9zznaqzdne2awnlnygt0p74dkc3e4sv9tez4rhu" }, { "mnemonic": "rabbit track ahead moral either upper tiger paper echo snow multiply trial kind two cram", - "address": "bitcoincash:qqa37fkpl3g90ydgas3t3ev0xes24du2aqfdxaz85s" + "address": "bitcoincash:qqa37fkpl3g90ydgas3t3ev0xes24du2aqfdxaz85s", + "regtestAddress": "bchreg:qqa37fkpl3g90ydgas3t3ev0xes24du2aqhr5mrrs2" }, { "mnemonic": "shadow steak gospel heart life wedding loud jar marriage during lecture stove exclude price worry story art relief", - "address": "bitcoincash:qp2yr38pjeqdtsqw9pfwjs6ng3ya4lqlpu46wkzsh5" + "address": "bitcoincash:qp2yr38pjeqdtsqw9pfwjs6ng3ya4lqlpu46wkzsh5", + "regtestAddress": "bchreg:qp2yr38pjeqdtsqw9pfwjs6ng3ya4lqlput5usr5nw" }, { "mnemonic": "supply salute they blood coyote century envelope circle baby armed comfort sport jazz clarify museum portion wolf hour donkey frog juice", - "address": "bitcoincash:qqjpuwkhepkgxylfg8tq59sqm8zwf32dxqdchcnge7" + "address": "bitcoincash:qqjpuwkhepkgxylfg8tq59sqm8zwf32dxqdchcnge7", + "regtestAddress": "bchreg:qqjpuwkhepkgxylfg8tq59sqm8zwf32dxqnk97jvay" }, { "mnemonic": "tunnel ugly degree bid merry world pupil tornado ski rent casino rent security length wet twice luxury rookie invite destroy busy leopard escape shoe", - "address": "bitcoincash:qpjh00scq3ratsytmttle5cml6yyk9stvc5lfd6pck" + "address": "bitcoincash:qpjh00scq3ratsytmttle5cml6yyk9stvc5lfd6pck", + "regtestAddress": "bchreg:qpjh00scq3ratsytmttle5cml6yyk9stvc23mtm9uv" } ], "toWIF": [ @@ -290,6 +295,7 @@ "xpriv": "xprv9ysdmq3FsEdR2byz2KdNuGNd1dY181zpe5jBpydatj49DaxVnrTGNkM4S28WgBzNSFQA5SSnT34XcqcoS6opVGebrhXAef3rGpXPPb7yHPi", "legacy": "1CtdPZHebT5QTdknNvEBjGSgACHbriUmLV", "cashaddress": "bitcoincash:qzpxe7f7zc3rwckjmtled2wfssvv5gkvw52e35pc9q", + "regtestaddress": "bchreg:qzpxe7f7zc3rwckjmtled2wfssvv5gkvw55hrjqup6", "xpub": "xpub6CrzBLa9hcBiF64T8MAPGQKMZfNVXUig1JendN3CT4b86PHeLPmWvYfYHK2NNYrEBj1GwfWqWF1xYjn6aD1Y7RYDNajKSKbSi1CW2hzeDA5", "privateKeyWIF": "L3nMAFHGojwdTajZAjEfSsqyP8TmQgqpxmhKNdwpLiNw4EBuhUcg" }, @@ -297,6 +303,7 @@ "xpriv": "xprv9ysdmq3FsEdQyzSTsENJdmQPvXWDArRWG118RzwPTGoYmwUDGoeHoBjr1hxgGrLP9XpEXg9roQhSBFrwjb934bnu8yQzdHi6MmcPUXniGrP", "legacy": "1J1nGBW8rWeV1VEETii5nKhKHT7qshuQYw", "cashaddress": "bitcoincash:qzafl67pkxgmmzfp5jj4937jv6rlfs7zxy6gurw0xh", + "regtestaddress": "bchreg:qzafl67pkxgmmzfp5jj4937jv6rlfs7zxyyxw90tzd", "xpub": "xpub6CrzBLa9hcBiCUWvyFuJzuM8UZLhaK9MdDvjEPM11cLXejoMpLxYLz4KrxjRV9cd44EacgeaWU4E3GT6HfkDwjEup3Hw9inf9opWxxCZUa6", "privateKeyWIF": "KxWMGJMHMhB4f8aTwpmqags7gNvcrc7gs76SJHaXbAc4Me2DKP3L" }, @@ -304,6 +311,7 @@ "xpriv": "xprv9ysdmq3FsEdR71JPPhVFP2DwwQCUksByZA7kg6y5qTjDvkX8GQH1WwJDc2epCeCL416qnVHJYNQvaFjkrM1CkGwaHy1w9oVAUAe4V6cYiyq", "legacy": "1CrwnAN3p4Y5h7511F49VgwUvbEq314BM9", "cashaddress": "bitcoincash:qzppkls7al33d0w2dd07776d0fu2jwvtxsnw8nyum4", + "regtestaddress": "bchreg:qzppkls7al33d0w2dd07776d0fu2jwvtxsdq449cl0", "xpub": "xpub6CrzBLa9hcBiKVNrVj2FkAAgVS2yAKupvP3MUVNhPoGCoYrGowbG4jchTLccFRbah2Kw7VNbP11G6mXYAkur47EZJcsXkvwTqCekjrpBYaS", "privateKeyWIF": "KzYUskkRuJrhDYLgP1JAywmUx3MPh2UZNQa299iZgGS9cNKytzy4" }, @@ -311,6 +319,7 @@ "xpriv": "xprv9ysdmq3FsEdR8Zka7LWxKXaW2bsS3fjmusdBq5GnnDVMSAZ2LqhsoydPr6gD4CS9Ww8vWfnKtGe1rTqbw5NBvuqJwhebogWGbmkGhV9xa69", "legacy": "1HbccrsbZjyPewX6vaHBFyuhE2NtP3BJYp", "cashaddress": "bitcoincash:qzmqmc6vq4hrdwtjrluwk9uvyj6nt4h4aqe24qxnqr", + "regtestaddress": "bchreg:qzmqmc6vq4hrdwtjrluwk9uvyj6nt4h4aq8y8x8hye", "xpub": "xpub6CrzBLa9hcBiM3q3DN3xgfXEadhvT8TdH6YndTgQLZ2LJxtAtP28MmwshM34EtFhPDLorNocunk1E2KBvBbsGVJ5NorsvxW1yDWxsuLZF8Y", "privateKeyWIF": "L54oL29DdWDiPtHDW1kr3fzTWdm2f34V1tWhrFxnJoVafadwx6aS" }, @@ -318,6 +327,7 @@ "xpriv": "xprv9ysdmq3FsEdRD3iBKzw3f8HwpR1TbZNbySfxvXFZ6ZnmiMQGPfcnfCuDoLcnGT27p8DTvsqVubj8tv6yQp5siqUoPmT4WRLpjZXauriLnZB", "legacy": "1CmRFZjxL6auhVooc9sd3d8oKwL8mKwfFQ", "cashaddress": "bitcoincash:qzqslmsyprdfzwu3hk4sa237c7lpm44kesvkl2vtnq", + "regtestaddress": "bchreg:qzqslmsyprdfzwu3hk4sa237c7lpm44kesjcdvd0h6", "xpub": "xpub6CrzBLa9hcBiRXneS2U42GEgNSqx126TLfbZiufAeuKkb9jQwCw3D1Dhec4bNzwm9JkunejrxWcviV5NmoQTkb5eMGqJrVby2L7p6Mtee75", "privateKeyWIF": "L5UtYZibxTiHYefBQNvTRHYp75V3EeoqzRdv8KwqzYBtvzewaUME" } @@ -326,26 +336,31 @@ { "legacy": "1CtdPZHebT5QTdknNvEBjGSgACHbriUmLV", "cashaddress": "bitcoincash:qzpxe7f7zc3rwckjmtled2wfssvv5gkvw52e35pc9q", + "regtestaddress": "bchreg:qzpxe7f7zc3rwckjmtled2wfssvv5gkvw55hrjqup6", "xpub": "xpub6CrzBLa9hcBiF64T8MAPGQKMZfNVXUig1JendN3CT4b86PHeLPmWvYfYHK2NNYrEBj1GwfWqWF1xYjn6aD1Y7RYDNajKSKbSi1CW2hzeDA5" }, { "legacy": "1J1nGBW8rWeV1VEETii5nKhKHT7qshuQYw", "cashaddress": "bitcoincash:qzafl67pkxgmmzfp5jj4937jv6rlfs7zxy6gurw0xh", + "regtestaddress": "bchreg:qzafl67pkxgmmzfp5jj4937jv6rlfs7zxyyxw90tzd", "xpub": "xpub6CrzBLa9hcBiCUWvyFuJzuM8UZLhaK9MdDvjEPM11cLXejoMpLxYLz4KrxjRV9cd44EacgeaWU4E3GT6HfkDwjEup3Hw9inf9opWxxCZUa6" }, { "legacy": "1CrwnAN3p4Y5h7511F49VgwUvbEq314BM9", "cashaddress": "bitcoincash:qzppkls7al33d0w2dd07776d0fu2jwvtxsnw8nyum4", + "regtestaddress": "bchreg:qzppkls7al33d0w2dd07776d0fu2jwvtxsdq449cl0", "xpub": "xpub6CrzBLa9hcBiKVNrVj2FkAAgVS2yAKupvP3MUVNhPoGCoYrGowbG4jchTLccFRbah2Kw7VNbP11G6mXYAkur47EZJcsXkvwTqCekjrpBYaS" }, { "legacy": "1HbccrsbZjyPewX6vaHBFyuhE2NtP3BJYp", "cashaddress": "bitcoincash:qzmqmc6vq4hrdwtjrluwk9uvyj6nt4h4aqe24qxnqr", + "regtestaddress": "bchreg:qzmqmc6vq4hrdwtjrluwk9uvyj6nt4h4aq8y8x8hye", "xpub": "xpub6CrzBLa9hcBiM3q3DN3xgfXEadhvT8TdH6YndTgQLZ2LJxtAtP28MmwshM34EtFhPDLorNocunk1E2KBvBbsGVJ5NorsvxW1yDWxsuLZF8Y" }, { "legacy": "1CmRFZjxL6auhVooc9sd3d8oKwL8mKwfFQ", "cashaddress": "bitcoincash:qzqslmsyprdfzwu3hk4sa237c7lpm44kesvkl2vtnq", + "regtestaddress": "bchreg:qzqslmsyprdfzwu3hk4sa237c7lpm44kesjcdvd0h6", "xpub": "xpub6CrzBLa9hcBiRXneS2U42GEgNSqx126TLfbZiufAeuKkb9jQwCw3D1Dhec4bNzwm9JkunejrxWcviV5NmoQTkb5eMGqJrVby2L7p6Mtee75" } ], diff --git a/test/fixtures/Mnemonic.json b/test/unit/fixtures/Mnemonic.json similarity index 75% rename from test/fixtures/Mnemonic.json rename to test/unit/fixtures/Mnemonic.json index f6fdf9fe..e1e2b6b5 100644 --- a/test/fixtures/Mnemonic.json +++ b/test/unit/fixtures/Mnemonic.json @@ -4,7 +4,7 @@ "mnemonic": "rare dinosaur army fat spend average design order ritual town brave spike", "entropy": "b207cc3029bd141f8ef4e1ba9cc86d68" }, - { + { "mnemonic": "rabbit track ahead moral either upper tiger paper echo snow multiply trial kind two cram", "entropy": "b03cd014c7d471de387cff45f9b245f417a9d74c" }, @@ -27,22 +27,27 @@ "output": [ { "privateKeyWIF": "L5NHWZusDiBVi5eMc6mBGufDMewTqnN9fzi6zyCQSVp39iKPqH7v", + "privateKeyWIFRegTest": "cVjGyUuiemsksX7czWaJeEAGytEsWETqk2ra7PeuwcU3QTKYFYX7", "address": "bitcoincash:qr3r0yazu6s4ed0ckgpv96zcwx3wt9jy6vv56ywm2w" }, { "privateKeyWIF": "L3nGc7sEDQ6CQV7LPzyLwec8uWwQFWhXKcYdPC6dmx8xZuq4mmDM", + "privateKeyWIFRegTest": "cU9G52s5eTnTZvabnQnUJy7CXkEouxoDPeh6VcZ9H4nxpeqnn4y7", "address": "bitcoincash:qqzc32v777yz4qprp0tk443j5j35q5q0xgzuvprgv0" }, { "privateKeyWIF": "KxD3i4YUdzEdDggNbNjRbYqta85KPGko9mRxcZH1Dh7MYQ5PFjcq", + "privateKeyWIFRegTest": "cNa3AyYL53vtP89dynYYxsLxCMNj3irVDoaRiyjWiomMo9AginKE", "address": "bitcoincash:qre988ur4gp5k2ph3lmxltqtg4q2zgw6eye0l6k6eg" }, { "privateKeyWIF": "L1emnG2hYd3VKGVRHpZS3qHXQHMBgvDy4he4UtFu747wVyT5sQGT", + "privateKeyWIFRegTest": "cS1mFB2YygjkUhxggENZR9nb2WebMNKf8jnXbJiQcAmwkiSwiEsC", "address": "bitcoincash:qzrjsum46ecex9qs28eyhw27ltydu37wzcq3v80ld8" }, { "privateKeyWIF": "L28uLVU1Kt8fPJtbK7HUB436atC4dSN1WQPJLde1w6dtyhNmLMyt", + "privateKeyWIFRegTest": "cSVtoQTrkwpvYkMrhX6bYNYAD7VUHtThaSXmT46XSDHuESQ7LCaQ", "address": "bitcoincash:qqqnmqmpy9vz899ctv4chtx5n857pv9l4ykuea44xz" } ] @@ -52,22 +57,27 @@ "output": [ { "privateKeyWIF": "KxGbR7jBWA7jm7GVz9SQvUghX4cYyf1WoP7oGjVXgzbeCDBFy5Qi", + "privateKeyWIFRegTest": "cNdat2j2wDozvYjmNZFYHoBm9Huxe77CsRGGP9x3C7FeSxGV9GtJ", "address": "bitcoincash:qr3r0yazu6s4ed0ckgpv96zcwx3wt9jy6vv56ywm2w" }, { "privateKeyWIF": "L2Er6iZ87yeQVDREKQWw8xr7Uj2ZTmdF4fzfG2MYP3TYHHgXBphK", + "privateKeyWIFRegTest": "cSbqZdYyZ3LfeetVhpL4WHMB6xKy8Diw8i98NSp3tA7YY2o3PGAC", "address": "bitcoincash:qqzc32v777yz4qprp0tk443j5j35q5q0xgzuvprgv0" }, { "privateKeyWIF": "KwQW5F2oFfeqaB9H8AEWX6e8SFyw7qdNcVc3i9RBY6o1oDWYLuM3", + "privateKeyWIFRegTest": "cMmVYA2egjM6jccYWa3dtR9C4VHLnHj4gXkWpZsh3DT23xZ7Zhgx", "address": "bitcoincash:qre988ur4gp5k2ph3lmxltqtg4q2zgw6eye0l6k6eg" }, { "privateKeyWIF": "L1wrABy4xHXNct68ZkBsNUfRN3MHvSW4KJPPDbusUCTjPq3zm3AB", + "privateKeyWIFRegTest": "cSJqd6xvPMDdnKZPx9zzjoAUzGehatbkPLXrL2NNyK7jea72uxB7", "address": "bitcoincash:qzrjsum46ecex9qs28eyhw27ltydu37wzcq3v80ld8" }, { "privateKeyWIF": "L5fQnDhGNYH6qFjh4pgtxYtZ6SSa6PNvqsvXL3Xxc3UTckwo35WU", + "privateKeyWIFRegTest": "cW2QF8h7obyMzhCxTEW2KsPcifjykqUcuv4zSTzU7A8TsW2nQGUh", "address": "bitcoincash:qqqnmqmpy9vz899ctv4chtx5n857pv9l4ykuea44xz" } ] @@ -77,22 +87,27 @@ "output": [ { "privateKeyWIF": "Kwv3n87vwRrMbxa4vTWKY9gaAZtthe3NR1iebRTraaVSAwY5ty8Q", + "privateKeyWIFRegTest": "cNH3F37nNVYcmQ3LJsKSuUBdnoCJN694V3s7hqvN5h9SRgYiXW9A", "address": "bitcoincash:qr3r0yazu6s4ed0ckgpv96zcwx3wt9jy6vv56ywm2w" }, { "privateKeyWIF": "KzucDPxzkExCHTzzJBXo17V7LwRtKj6movuYWmbGW2HjVsFTSBdk", + "privateKeyWIFRegTest": "cRGbgJxrBJeTSuUFgbLvNRzAyAjHzBCTsy41dC3n18wjkcGHbiRX", "address": "bitcoincash:qqzc32v777yz4qprp0tk443j5j35q5q0xgzuvprgv0" }, { "privateKeyWIF": "Kye3NjRtM2NYtS4kfQgSNK2RvtzUM9mXzy6szZTVii33ETd5jNrU", + "privateKeyWIFRegTest": "cQ12qeRjn64p3sY23pVZjdXVZ8Ht1bsE51FM6yv1Dph3VCj31tVz", "address": "bitcoincash:qre988ur4gp5k2ph3lmxltqtg4q2zgw6eye0l6k6eg" }, { "privateKeyWIF": "KzZWMxZGgu8cZF2aEaP1sYnh3E4vtCHEKVzY2fWaHG44MFosYmq1", + "privateKeyWIFRegTest": "cQvVpsZ87xpsigVqczC9EsHkfTNLYeNvPY9195y5nNi4bzvNh7Zt", "address": "bitcoincash:qzrjsum46ecex9qs28eyhw27ltydu37wzcq3v80ld8" }, { "privateKeyWIF": "L4iVLdaMkKvwtZKeD1ishayo2XHGWLm37imjpQFyV4XSkv1XTkGk", + "privateKeyWIFRegTest": "cV5UoYaDBPdD3znubRY14uUrekagAnrjBkvCvpiUzBBT1f5bgdjT", "address": "bitcoincash:qqqnmqmpy9vz899ctv4chtx5n857pv9l4ykuea44xz" } ] @@ -102,22 +117,27 @@ "output": [ { "privateKeyWIF": "KwZ38dBpAk1BY53mmo6tSkt5we3FEAw8nvPE5m3L8iGJvfgCtM1r", + "privateKeyWIFRegTest": "cMv2bYBfbohShWX3ACv1p5P9ZsLetd2prxXhCBVqdpvKBQpZYKBJ", "address": "bitcoincash:qr3r0yazu6s4ed0ckgpv96zcwx3wt9jy6vv56ywm2w" }, { "privateKeyWIF": "L1VCKD5oq7s5iaWC2ZY79KuRxDJrQ6tjRiB3VaScYsxYD8TxsSan", + "privateKeyWIFRegTest": "cRrBn85fGBZLt1yTQyMEWeQVaScG4YzRVkKWbzu83zcYTsVYovue", "address": "bitcoincash:qqzc32v777yz4qprp0tk443j5j35q5q0xgzuvprgv0" }, { "privateKeyWIF": "KxojM7WKQqxS1FNKGVWowDPtzMXaXQ7UUsdwhxJFUwE7HxSofqUK", + "privateKeyWIFRegTest": "cPAip2WAquehAgqaeuKwJXtxcapzBrDAYunQpNkkz3t7YhTkSbJy", "address": "bitcoincash:qre988ur4gp5k2ph3lmxltqtg4q2zgw6eye0l6k6eg" }, { "privateKeyWIF": "KyWdb9m9TJpxqGHkZjHLipQiLUVmhvZT8p49N761RUc2Nq23FBxd", + "privateKeyWIFRegTest": "cPsd44kztNXDzhm1x96U68umxhoBNNf9CrCcUXYWvbG2daC2pDgL", "address": "bitcoincash:qzrjsum46ecex9qs28eyhw27ltydu37wzcq3v80ld8" }, { "privateKeyWIF": "L33wzMLV6m6DLHPnzuf27ZSjLv8HGG3DCjMdxDDTieDt7P1ih1ic", + "privateKeyWIFRegTest": "cTQwTGLLXpnUVis4PKU9Uswny9Rgvi8uGmW74dfyDkstN874DDMJ", "address": "bitcoincash:qqqnmqmpy9vz899ctv4chtx5n857pv9l4ykuea44xz" } ] @@ -127,22 +147,27 @@ "output": [ { "privateKeyWIF": "KyapaU8zwrHxLoqVfwRrF9e5a35DoXhV6C7zTkVnneuLQhMHBd7G", + "privateKeyWIFRegTest": "cPwp3P8rNuzDWFJm4MEycU99CGNdTyoBAEGTaAxJHmZLfSTUM32i", "address": "bitcoincash:qr3r0yazu6s4ed0ckgpv96zcwx3wt9jy6vv56ywm2w" }, { "privateKeyWIF": "L2WCL7KEJT415BPYBhW3vUp89x1AwFrLfMyjMrbC444N1tFKBhXY", + "privateKeyWIFRegTest": "cSsBo2K5jWkGEcroa7KBHoKBnBJabhx2jQ8CUH3hZAiNGdPAbR1L", "address": "bitcoincash:qqzc32v777yz4qprp0tk443j5j35q5q0xgzuvprgv0" }, { "privateKeyWIF": "L3Dz8kbwNf6EShtjnpZ65k8RuyD2reMcbZAnFY4GvQjy7CtvtmZX", + "privateKeyWIFRegTest": "cTaybfbnoinVc9N1BENDT4dVYCWSX6TJfbKFMxWnRXPyMwwVTigN", "address": "bitcoincash:qre988ur4gp5k2ph3lmxltqtg4q2zgw6eye0l6k6eg" }, { "privateKeyWIF": "L3Dy5sJB31JBnRtFZq6QJaKEaijo3wCnvJpjRvr8hYov7LUu8E13", + "privateKeyWIFRegTest": "cTaxYnJ2U4zSwsMWxEuXftpJCx3CiPJUzLyCYMJeCfTvN5VU9AG6", "address": "bitcoincash:qzrjsum46ecex9qs28eyhw27ltydu37wzcq3v80ld8" }, { "privateKeyWIF": "L4DTuvT3XWFW7vs6gvS88v4vYBMuJK3GjzMBTjD8XkpfJwoeqewD", + "privateKeyWIFRegTest": "cUaTNqStxZwmHNLN5LFFWEZzAQfJxm8xp2Vea9fe2sUfZgtqShVL", "address": "bitcoincash:qqqnmqmpy9vz899ctv4chtx5n857pv9l4ykuea44xz" } ] diff --git a/test/fixtures/Script.json b/test/unit/fixtures/Script.json similarity index 98% rename from test/fixtures/Script.json rename to test/unit/fixtures/Script.json index 04ebfbab..ab45e230 100644 --- a/test/fixtures/Script.json +++ b/test/unit/fixtures/Script.json @@ -412,6 +412,10 @@ "script": "OP_RETURN 5454", "type": "nulldata" }, + { + "script": "OP_RETURN 877 8106baaeb4f1b3f7f2558b788be6cb62d76b5ea8eba64a05a509edd504d76fb7 f09fa496203120424348203d203536312e30322420f09f938820362e3533250a54697073203d206675656cefb88f", + "type": "nulldata" + }, { "script": "OP_RETURN 424348466f7245766572796f6e65", "type": "nulldata" @@ -650,5 +654,19 @@ "output": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", "hex": "a9141b61ebed0c2a16c699a99c3d5ef4d08de7fb1cb887" } + ], + "scriptNumber": [ + { + "decoded": 1, + "encoded": "01" + }, + { + "decoded": -1, + "encoded": "81" + }, + { + "decoded": 1000, + "encoded": "e803" + } ] } diff --git a/test/fixtures/TransactionBuilder.json b/test/unit/fixtures/TransactionBuilder.json similarity index 81% rename from test/fixtures/TransactionBuilder.json rename to test/unit/fixtures/TransactionBuilder.json index bd71fdef..f3c8da41 100644 --- a/test/fixtures/TransactionBuilder.json +++ b/test/unit/fixtures/TransactionBuilder.json @@ -524,6 +524,58 @@ "bchtest:qz9glwj836l6xtf0r3fhm6895d4ed3rhy5s907urel" ] } + ], + "regtest": [ + { + "xpriv": "tprv8jwG6YA1fGe7Ut879xQ9NMTwK9oWx4huSvQuix8bEorixxkhkSJd55B7mfQAQeALoEpWWQ5GW2qCmBjAnnyTCyMXoJYUGuQLQLPN367M98Y", + "txHash": "adcda2424f8768bdf3d5064e9a71a61d6d80b22bcc12f5eae0372822aac4c293", + "hex": "020000000193c2c4aa222837e0eaf512cc2bb2806d1da6719a4e06d5f3bd68874f42a2cdad000000006b483045022100dce87e98844fe01c7f0bffeb3ec6dbd92cada2751570653abb5db5bb1c40eeec02202eeac6d4f79f4774b40c121c6b99b8f431357a17dc8bae39003a16a8246a2bae4121037e04aa55787df424b4f1160aa64c65f64b2daa69e53d16c75b9a40708b01651dffffffff0140a0eb0b000000001976a9143cb6602d5ab7dc5c283f34c361fe9ce152f5c46888ac00000000", + "amount": 199994240, + "vout": 0, + "outputs": [ + "bchreg:qq7tvcpdt2machpg8u6vxc07nns49awydq85ujk0dc" + ] + }, + { + "xpriv": "tprv8jwG6YA1fGe7Zw1EnkCEfsm4DosKKHtczdcH2n2H6b7NgnyoHqcQLQHt9d384GG14MJyQ3Jifij1tgkkVCJn4x926i5vZbFhtjkyewCFBYD", + "txHash": "0ed1f82a7581f694fa77e9bdcb36a6e67e95ff75bb141e1df78e1f3de7109af4", + "hex": "0200000001f49a10e73d1f8ef71d1e14bb75ff957ee6a636cbbde977fa94f681752af8d10e000000006a4730440221009e36bba2b64d1aaf6fe509e27cffdeab3c5f5b4bd464c014e0abb0cfa8594880021f3f8111b1f19894f902b592ba967e55b98568dea4c5e14e1f9260bfc988ed9c412103b230a14bfbdaacb71b2005314de971fa58b14edb6a8dd7bfbd3fdd2ba41be329ffffffff010095eb0b000000001976a91481a5df1328bc195ee8affe9cf497bbdb79957bb588ac00000000", + "amount": 199991360, + "vout": 0, + "outputs": [ + "bchreg:qzq6thcn9z7pjhhg4llfeayhh0dhn9tmk5rfn084kv" + ] + }, + { + "xpriv": "tprv8jwG6YA1fGe7bymmgt3fveCX9Ja97PYm6zuVAzxkqMwD2W9RMH7QeqmJjjcYds7oqe6TnEqVvDjxSB5JJW2gTijE9HtptT8UHskamocUgrA", + "txHash": "62c0967f5fedbde7b5d485b8a98cf64c6f59c49b52667407e1e4f08f8868e80a", + "hex": "02000000010ae868888ff0e4e1077466529bc4596f4cf68ca9b885d4b5e7bded5f7f96c062000000006b483045022100810a26ea991a98f3bc38764095b00be6f86795a6b165117726f1401f2714757b02207d6ee4551f4dc7e053cc29abd63b24bbb6ef150024b656fde0289bec52053633412102193e4ead30e7008945e5c98589668762814624ed97a6fdbe89b5cb9cef90ec76ffffffff01c089eb0b000000001976a914305166fda99a88d62955a21adc6d5515c88b194f88ac00000000", + "amount": 199988480, + "vout": 0, + "outputs": [ + "bchreg:qqc9zeha4xdg343f2k3p4hrd252u3zcefurwxvh6g9" + ] + }, + { + "xpriv": "tprv8jwG6YA1fGe7cffn1viCuHyewctT4zxe6tBKvHJavt5AMgTUJTSbZyiYwXwaq1bXSzP2k6WmBTewtLdXqG7hmNWCsUgrGz9XEp9iBaZcjz2", + "txHash": "8095f9aacd64c3119ed07b1152e0aaaa2d9a2da8886e442b6e43ee0c5474cdc0", + "hex": "0200000001c0cd74540cee436e2b446e88a82d9a2daaaae052117bd09e11c364cdaaf99580000000006b4830450221008226da5999b699f941b120824e6f2f0eac1cfd1ee0265758996a1351c5e0f800022002a8125bacee157b482fff4e4412d2926a5cdb8ba154f1de14aac68858403c7a41210355cfbd19413917309ac59f1dfe4bd7ea9ea86628ed54872a9c70eb20d453e518ffffffff01807eeb0b000000001976a9145c529406c0577109811a9e4305900c283783b5ff88ac00000000", + "amount": 199985600, + "vout": 0, + "outputs": [ + "bchreg:qpw999qxcpthzzvpr20yxpvsps5r0qa4lusgdzjysj" + ] + }, + { + "xpriv": "tprv8jwG6YA1fGe7fLkrKHuZWCM8uy911tAZKrqM8RRaF6aJUku9Vw9uYCYtRdAoLG6cyfBcfyVrXBAqaXUxFZZXPRxqiszMj5U9zTGL52PZxPD", + "txHash": "10b55f91a2dd91ad28bffb32b8967f5dcfd4f1d93f6bf2fafd089f5899b341fd", + "hex": "0200000001fd41b399589f08fdfaf26b3fd9f1d4cf5d7f96b832fbbf28ad91dda2915fb510000000006b483045022100b289038c20d65b2e2403df6bcc5d3ab56ecae10d2b04e75aa98e4a1418f670f40220079d059ec3546bfd6baa1355bd7f65cb38a997439d99afb1e7ab21c7506a15ec412103ee46afc68bb38a9a5598950e51e4466a8b33573e8605126b0779040d740f88f0ffffffff014073eb0b000000001976a9148a8fba478ebfa32d2f1c537de8e5a36b96c4772588ac00000000", + "amount": 199982720, + "vout": 0, + "outputs": [ + "bchreg:qz9glwj836l6xtf0r3fhm6895d4ed3rhy52eells6e" + ] + } ] }, "toMany": { @@ -640,6 +692,59 @@ "bchtest:qrld2c0xn8zpm8knvyn9lx2zuh8rhkawsyat9mtkg4" ] } + ], + "regtest": [ + { + "xpriv": "tprv8jwG6YA1fGe7jgUsatzgsqH941oUDZs9FejN6rVRZcMaL4nPoShBwD6LNFThDNNg1zpVe1k4zHeK82KJMU4iJMCeEbinn86QuFd5eXutaUL", + "txHash": "4edb662b14424d7bbbbe4b9fd1533d49690aefb2a15af8fa0704eab1ce41210b", + "hex": "02000000010b2141ceb1ea0407faf85aa1b2ef0a69493d53d19f4bbebb7b4d42142b66db4e000000006b483045022100bf8c2e6b8d3bcbfbaa64a5e9c2cbe5ce71471f87ff1d9f6a0bcec1c58c4a8a2102201504868d60e6f75ccda4c3fe899df0094d878fe8ca5ec55893da5f61517b49a04121029cc6fa90d901a5474249facbb32b187a1de63e853c43b272752109abdef19728ffffffff0201b3f505000000001976a914b3a223ad62ca6c8669a69a508216cd374612cb5688ac01b3f505000000001976a914b4e71aaf9bf4afd806d0560b17995c873ef61e9e88ac00000000", + "amount": 199979840, + "vout": 0, + "outputs": [ + "bchreg:qze6ygadvt9xepnf56d9pqske5m5vykt2cyscdju70", + "bchreg:qz6wwx40n062lkqx6ptqk9uetjrnaas7ncppy9sc0f" + ] + }, + { + "xpriv": "tprv8jwG6YA1fGe7vmRFrLKrsa216JHN44gEbnqUDThD1YtcFfVnb4a68bN6vdr3SqTPh1PX4CBgRoHcK8Ub4HCCei1q8c8HdstHsY93fxvQaEz", + "txHash": "7bc7e2f13ee5aab5c561dadde8ccdaa9968a75af074605c8d9a07545d3c03c8b", + "hex": "02000000018b3cc0d34575a0d9c8054607af758a96a9dacce8ddda61c5b5aae53ef1e2c77b000000006b483045022100d01c1c4039bd57bd18bd6d1185f7ca68477f6f347c977f740464685d80ae8b0402202de873b559814282a8a54b032c3bfc4cd7aa3a6e556356be1e78e999a5f478e94121028495390a7537738c2b0b1709eeba8bc74cc21279a35a45d0a7ff5a31d0416be2ffffffff027797f505000000001976a91417995bdbdd04ffa5d6fcf475d147d71fb7fb9d2088ac7797f505000000001976a91438b9d2974d586b062af9fe25b5fb8a2a87e3b27888ac00000000", + "amount": 199965740, + "vout": 0, + "outputs": [ + "bchreg:qqtejk7mm5z0lfwkln68t5286u0m07uayqdy443vvd", + "bchreg:qqutn55hf4vxkp32l8lztd0m3g4g0caj0qlel2j0dj" ] + }, + { + "xpriv": "tprv8jwG6YA1fGe8AkaYjYBgP4uCdBzEc1KNJTEmjaf7bwyysea4qt275maGXt9ergfGz7JeUULZok9UNKT5uuPMoseGJzYJUJgac2pqS7FLhgP", + "txHash": "84f8380b4f4166e332a9aba700b7c616061ac77f85593245470ef0657c000f92", + "hex": "0200000001920f007c65f00e47453259857fc71a0616c6b700a7aba932e366414f0b38f884010000006b483045022100b342eaa7f357a19fc24918b772b73c13e2060db4fcde690eb5df526e6341b9a2022030b36ec3f862e03081af98f0d64dabba0ecde8605f70c4ef08a93b60af662739412102547aa38203e296e558c0ab77fff7b2f12669e7e39fe1511993ce2038eebf0fbeffffffff0261daf505000000001976a914b65a6f84ba3b239f4258192562c3b99ec576e28688ac61daf505000000001976a914fe64266e2cdee4ed1f9708a71d9e6883451e067088ac00000000", + "amount": 200000000, + "vout": 1, + "outputs": [ + "bchreg:qzm95muyhgaj886ztqvj2ckrhx0v2ahzscdcnyd8e7", + "bchreg:qrlxgfnw9n0wfmgljuy2w8v7dzp528sxwqw7rzk9zj" ] + }, + { + "xpriv": "tprv8jwG6YA1fGe8M9RrTT7WZc4NJshwsfEW8RKp8b2oCNNNLa5YJfPPJhDgXHFQJQsyrioTeQi4D1Xdh28rA5c1FYSpe5QpD39QdYeReUFErSV", + "txHash": "ab6c8f1b141f5a169afb2abe44d91d0eaa2b294e3df8326c3ffeeba62c7fcad0", + "hex": "0200000001d0ca7f2ca6ebfe3f6c32f83d4e292baa0e1dd944be2afb9a165a1f141b8f6cab000000006b483045022100f975e3114ff17c7b4ca5ad19c268b89135f1664163acd68a7f1fc516e2f554e102200bdeb773f5f1d466f22e476ae35e2ac8e810c4bdca7f8f477519c4d889224e4341210223c633d50fb10af9de12f9ef3aecc39ebc26a76e57fa510c3455e5cd1da827d9ffffffff02d7bef505000000001976a914a1612a990756144cd374bc77395b38ce3a4e4afc88acd7bef505000000001976a914d324c14c2fedd81ee2ce94cf4ef896f4b303391088ac00000000", + "amount": 199985900, + "vout": 0, + "outputs": [ + "bchreg:qzskz25eqatpgnxnwj78ww2m8r8r5nj2ls8e66qkc6", + "bchreg:qrfjfs2v9lkas8hze62v7nhcjm6txqeezqxk4g7uuf" ] + }, + { + "xpriv": "tprv8jwG6YA1fGe8aEi5iXr42XpRDHANmSKvjkGQDhUEn4E3vFKU6uyxmzmDvH4XRDkykP56gr37YshRMJ6Q4ZPqmG3UD9bMvVPkv5oyEUZKoE3", + "txHash": "83d388b50f42e4dd4bc0dd6629c912e5a1ee2e78b3d8851bdab841112efe04ca", + "hex": "0200000001ca04fe2e1141b8da1b85d8b3782eeea1e512c92966ddc04bdde4420fb588d383000000006a473044022024c944f77c00cf8cca8641cf9e0b3cad498f04c2919e0067832a1031c64caa8a02204d7cc3e0181f56dd72039219d2eb139728a77172d1a2010379f0c00e97d443574121037c5b346363b720a74c5fd732ba2002f16682744fb0d728a24826ed83c2f6f633ffffffff024da3f505000000001976a91444f3088ca3a476f9d8c1d217cfe47d5df0e83a7088ac4da3f505000000001976a914fed561e699c41d9ed361265f9942e5ce3bdbae8188ac00000000", + "amount": 199971800, + "vout": 0, + "outputs": [ + "bchreg:qpz0xzyv5wj8d7wcc8fp0nly04wlp6p6wqg540xw5p", + "bchreg:qrld2c0xn8zpm8knvyn9lx2zuh8rhkawsy8hn6g9tn" ] + } ] }, "manyToMany": { @@ -806,6 +911,88 @@ "bchtest:qzdk7py96h020e6wv63zql2ld5dfp73uzgl9hqe9lw" ] } + ], + "regtest": [ + { + "xprivs": [ + "tprv8jwG6YA1fGe7kqL9HPxnBAJtzwzRmUq5qYAgA37BWw2PCFn3Tr56qikGoMpXxdPJ8vD7JokXN4rmLuygZMQ5nRTFUSodZtsD735UTDn99ff", + "tprv8jwG6YA1fGe7phE5EFsL5bSMK2EG4UvxHZb69tuajqGqmUas2R4JCA3G9gHeHGt8w71MVDEH7G1pYnqE2GhECtRFDYWpEovnnnnqdRhvS5e" + ], + "txHash": "a0367edacec483e77e2401ed73e035d4fe65b8c456b66175280701cd486af271", + "hex": "020000000271f26a48cd0107287561b656c4b865fed435e073ed01247ee783c4ceda7e36a0000000006a47304402207ff1867ad6e9b7dc7a1d3968113e20965c0ff77ad739e12b17e5dce7fe76e57502202e656dc0f57c3e7884228fe6c0f6161de74842fe2dc4b40296d0e49e118c778a412103206d484ae9751634d0a059acfbee14de2967f9da04159ac8fdd6fa8f1cb486f7ffffffff71f26a48cd0107287561b656c4b865fed435e073ed01247ee783c4ceda7e36a0010000006b483045022100b9115cf9024e5d61a17e6002fb5f9a71c9ecc1f50604c266638bda197579511d0220035b31d1a51a72136c1813e3a90a1e785f94650dc78bd0f0e9f8bbd4422e82d541210318a9bba01a9b343b3469af1ecd27815bdb6797c0eb21b1734a0d0f47290f44faffffffff020ca8f505000000001976a91439890e01e03442581056f0e3f606083cb552f66488ac0ca8f505000000001976a91443802909a4a51575217b553bb5b2670631fdc3cb88ac00000000", + "amounts": [ + 99988225, + 99988225 + ], + "outputs": [ + "bchreg:qqucjrspuq6yykqs2mcw8asxpq7t25hkvs9tlywwcn", + "bchreg:qppcq2gf5jj32afp0d2nhddjvurrrlwrevpdgvew0d" + ] + }, + { + "xprivs": [ + "tprv8jwG6YA1fGe81FvYckTjBt9uYG7XAmBMo59BRnytSBDUcTwTuRk2xidoA75t3b8rBEBnDxc2yV9nG4FiE9eedcwdFfzEg9Jaifqva5AXeQo", + "tprv8jwG6YA1fGe822yK9p2ojos9qESLKr3VXUFHca2jwv5Q32vBqMaMsXgH9S4iXQJVMTq4pPEFT7SWKv4Tx2fP45ktk7CXJaDSQYDCyWZo57T" + ], + "txHash": "860cdbf1c532dcb8b5c1e0a663f826400c55f7ccd7377e4d3bad9fcaa144e204", + "hex": "020000000204e244a1ca9fad3b4d7e37d7ccf7550c4026f863a6e0c1b5b8dc32c5f1db0c86000000006b483045022100cb3c583edc2a4023bcd3bdc1504f8a1584730a86eb3f1e947478cdb06914f9a10220553feed668967a194008d68da28010cf6dab0b9d0bc195d28fdc71f54abd44544121031b276c55b432444553e2739eaf77a98fbd21fb6b1597fea52dfa2a4692350972ffffffff04e244a1ca9fad3b4d7e37d7ccf7550c4026f863a6e0c1b5b8dc32c5f1db0c86010000006a473044022050e8437b4bc64890a1420ad74c0b51bc1d6bf2cc7e889d0e062c9ba41d50205402204b129553250cf13aa0269a048ad3e70fbde3747cd62efbad9d899f31121a795e412103fc35b3829b5fa081121470caa84cb9f4893f3ae542432ae1b1d05443d31f48d6ffffffff02828cf505000000001976a91431bcd80a099174adbd2355f03a3a9d1f39f60cb688ac828cf505000000001976a91405dd4318185a8726ee26bd344a535d7b61af082088ac00000000", + "amounts": [ + 99981175, + 99981175 + ], + "outputs": [ + "bchreg:qqcmekq2pxghftdayd2lqw36n50nnasvkcl4mu5rll", + "bchreg:qqza6sccrpdgwfhwy67ngjjnt4akrtcgyqkrzyar5g" + ] + }, + { + "xprivs": [ + "tprv8jwG6YA1fGe8E31BpkuCMurbLYKyuiaozJkMSqF2pS5UzygRQDh1Wb6uLWA6v9oQPNPHUi3VrxeT766HcJ5ApnDgU51REx1XA5s1f2vVnsN", + "tprv8jwG6YA1fGe8Fnr2eFwWmFMqK6t2YnEbXNLAS44iHmfaubrj7VQ6o1WnqLEG8CD7Q4ghoJbce9W8U2nG7WntiDX3Enk2y3SJuKuJubukkYY" + ], + "txHash": "d0e96087e7b5e684de362792a7e7a1d88b8647568fe372e4f45160eb4b927a67", + "hex": "0200000002677a924beb6051f4e472e38f5647868bd8a1e7a7922736de84e6b5e78760e9d0000000006b483045022100f3a9e17a8b9e2062c51376a9781015da460857165b183b33cad3fc611d28705f022016418087ac42ecfac3b411fbdc39e9a2aa24061e368769b1a782500fbacab9fd412103bf3e95bf65f053d883ed590a8bb3839e4028ffcba86a26d3e8c6ae12af3ed461ffffffff677a924beb6051f4e472e38f5647868bd8a1e7a7922736de84e6b5e78760e9d0010000006b483045022100dd9a7b17336da13c89aa35b5a8c78ad2cf5d62c82d89a9ac9a55a984827864cd02202baaf9b9dbd35da72720559e97b24e31ed54b7a76d120d42f3934d4322f50a08412103ba2abd8d0a84d0ed16c07569581aeebc1619661627527c48a6a7778d529e5cf7ffffffff026ccff505000000001976a914fe64266e2cdee4ed1f9708a71d9e6883451e067088ac6ccff505000000001976a9145ff601b23938962a743651a2bc682fdbae08171088ac00000000", + "amounts": [ + 99998305, + 99998305 + ], + "outputs": [ + "bchreg:qrlxgfnw9n0wfmgljuy2w8v7dzp528sxwqw7rzk9zj", + "bchreg:qp0lvqdj8yufv2n5xeg690rg9ld6uzqhzqy6u6mp8p" + ] + }, + { + "xprivs": [ + "tprv8jwG6YA1fGe8QJVJJ4sFfteUDybajahxa8NhkPgazaUFyEZ66C3WT99KnCuSpd9tbroDRqeD6oBTrjLFm8JMzcUSexbS2NAB8CrGzXS5CCj", + "tprv8jwG6YA1fGe8SiGV9L54byiMzUwms12gLrY8c7MRA6movJxrcnUHSmMqo5G27nET3ecF3ZhGMtXDDCWabhudscgnaxy5iVm1davE9JZ99sX" + ], + "txHash": "be6545f91b961d7b317d23f0b74f433bf4cae002317ebe9721a5b2e938a1887e", + "hex": "02000000027e88a138e9b2a52197be7e3102e0caf43b434fb7f0237d317b1d961bf94565be000000006a473044022016b8d887dcf44f95242a9b6bc5b85a35c71de80c3a5238261aa7c46010a92ce302205ae014669368148d070d3492e954fec156107248e468161c1ad05289a8c0d7454121020a2b22cd2eb901dfd79f12c5e4789223e88f5fadb560dd9a695d4228104a06ecffffffff7e88a138e9b2a52197be7e3102e0caf43b434fb7f0237d317b1d961bf94565be010000006a473044022052fc4bb44921e65ea9b4c57a495e3e10f0c43e69dc355d684bba5d6f8ca903920220642067e7a047964be39f6d4cc35aacf1041c7cf56a9fe1f352cefe97043d872b41210353183b2da1e76e1722a9ec5583ac22a75f6f79a8cfe9606a02ace3072e81ebb3ffffffff02e2b3f505000000001976a9145df278d466856014987fa0f921b5ee28622ac51d88ace2b3f505000000001976a914f9cfec9585d99d929a39644e34b9fc27ddbf65bf88ac00000000", + "amounts": [ + 99991255, + 99991255 + ], + "outputs": [ + "bchreg:qpwly7x5v6zkq9yc07s0jgd4ac5xy2k9r5x0k6h9y5", + "bchreg:qruulmy4shvemy5689jyud9elsnam0m9hu9hxau5rs" + ] + }, + { + "xprivs": [ + "tprv8jwG6YA1fGe8ajHkiGHL6oh97Thw7zBQSWhc5AHyFbLgEr5PnY6akBLpj4hvWcJRUzTD39bLqy4wzT5G8vsXAJBMX21GPTxWeuycvdPnaST", + "tprv8jwG6YA1fGe8dDLRhAmXv5rYxM3G7o8B7wEdKWMrBgCk2A2u8Q2mmhBEX2Xz7YVNUfS44CDuKZkQ552C1ybshigst6G1YvroBN2TrksrFec" + ], + "txHash": "bfc8eb9070d97f34f5b923a07036b1559b5260f5daa0adacb944c235103e68c2", + "hex": "0200000002c2683e1035c244b9acada0daf560529b55b13670a023b9f5347fd97090ebc8bf000000006a473044022073daa422f4825fea6a0d14e3b3574d35eb2ae8acd24a44cacc179e7fcef3d92d0220261e5ca416e98e0bdab9727ecc1fb2af0e14ffd7e1839546fe2af31a48be5784412102611ad099d44f5c6e1c765f36557287da7e190db591ce1b5a59439edb493511b9ffffffffc2683e1035c244b9acada0daf560529b55b13670a023b9f5347fd97090ebc8bf010000006b48304502210094ce1d26331f37f4679e2b3dc7cfb098e383dd54315371522feecd7162db184c02203fb3810d8252e6e208ebb347d58fba97408611dba507058ad0ec7e71d5fa2304412102b1746ad583eb093774063036a847250ac9c424edf1498cae7e7a0bad20df9640ffffffff025898f505000000001976a91495a5bddee9ad7fc612ea237f326c5ac77e751f8888ac5898f505000000001976a9149b6f0485d5dea7e74e66a2207d5f6d1a90fa3c1288ac00000000", + "amounts": [ + 99984205, + 99984205 + ], + "outputs": [ + "bchreg:qz26t0w7axkhl3sjag3h7vnvttrhuagl3q5dznjkdq", + "bchreg:qzdk7py96h020e6wv63zql2ld5dfp73uzg9epp6kug" + ] + } ] }, "fromMany": { @@ -962,6 +1149,83 @@ "bchtest:qzz29p3dccmrrwmptgtgqamectz6vexpturce5juax" ] } + ], + "regtest": [ + { + "xprivs": [ + "tprv8jwG6YA1fGe7r2bbsoGrUt7gSo8auZgv6aSaS59FVjZjRiJkK1SYqPGY3vr9gMEXvfKNzRNjW6VjMRpt3GVwXXF6gT8SgNfdSMarW2mU5JC", + "tprv8jwG6YA1fGe7u7wh93Si5YXPWAm6mZD4MMqEmdPiYzgWUCC3BDJ6Sg8XR14Rw4QmyBFu5fSF7ksjDU3Xk94KAjSY6P3f372X5uk9T3iSugg" + ], + "txHash": "812391dbaf4dc6b39dcbbb85a613a183aea48fb994212449bdbd4dd1b74b3518", + "hex": "020000000218354bb7d14dbdbd49242194b98fa4ae83a113a685bbcb9db3c64dafdb912381000000006a473044022058c446eec373bb5cae046e12a57cbf5f0b85f7c5a022b88ca17e77f72c2f8d7b022049cfdcb56bf6291db71c5fcbe82812f1e1a98c5e083c405b855b9532eb055f85412103dbd4cae70953a0c34550d59120bc8aa6ed6c01adf833c1d9d3118247f6175084ffffffff18354bb7d14dbdbd49242194b98fa4ae83a113a685bbcb9db3c64dafdb912381010000006a473044022045df2a8ccca97dedeb22bf74fc890bc6a2d2998147621b78a208938bf43a2fc4022077b4b5b21a04d27629535e7a44d3e96bf6d10bf84a20d68c1fccdaca41eb5fc8412103b744479db3b9b26ae110236568fdaff6637bb0e7a874154bf3060468fc5de09dffffffff012c3ceb0b000000001976a91456f61499e2617482f2a63e8aceae5e8cc4c16b5a88ac00000000", + "amounts": [ + 99985420, + 99985420 + ], + "outputs": [ + "bchreg:qpt0v9yeufshfqhj5clg4n4wt6xvfstttg5n5z6sx4" + ] + }, + { + "xprivs": [ + "tprv8jwG6YA1fGe85moRDL8ZmSRmsHDxgdje16KyYvnc2N4wzTpXoQQVgygVwUYzEGWeMNTuMZCRGAiReSGNdFm2R5mEmfvTEPpdiqYWWLNmdSk", + "tprv8jwG6YA1fGe86yJEbtnWSGSLZQ9Ep7cRptNFLYChBAfDqnR9EA12hN4eum2wTDd3rgVFrVW97M4yPSHDzEQ2KE3PwnuSvVt87ZQMLoA5zyj" + ], + "txHash": "29aa7fe4cb2ab3a0ab3e8d3d98ef6acd95be66e6c0a2709d58c4991b57fb6a8d", + "hex": "02000000028d6afb571b99c4589d70a2c0e666be95cd6aef983d8d3eaba0b32acbe47faa29000000006b483045022100960f60296536abf61573aa012a91492874a52bfab4ab220ba67011616f309e7002206f48e6d34ff2a91e76b329dff9dc5766a1e9a04030a9529d334b521e459bdc054121023f30c27ee820b656ef9c4286f657b1a3353f9bea94b3fde7446181e080217777ffffffff8d6afb571b99c4589d70a2c0e666be95cd6aef983d8d3eaba0b32acbe47faa29010000006b483045022100a02e8bc1bf5df3a45d79d16aadc1e0256fcc44355896d35179471a71be0934bc0220253d2d57428e05570829bbf18f7d3fb7120a34046797673457edead77749a606412103aa369a3edc60b06b099b20fc624ff5213a44212911e7b89b561ecd2e8089cbd2ffffffff011805eb0b000000001976a914cf0abb634cfdb82c73544f625697eb464b008b0288ac00000000", + "amounts": [ + 99978370, + 99978370 + ], + "outputs": [ + "bchreg:qr8s4wmrfn7mstrn238ky45hadrykqytqg3g07krgt" + ] + }, + { + "xprivs": [ + "tprv8jwG6YA1fGe8Fnr2eFwWmFMqK6t2YnEbXNLAS44iHmfaubrj7VQ6o1WnqLEG8CD7Q4ghoJbce9W8U2nG7WntiDX3Enk2y3SJuKuJubukkYY", + "tprv8jwG6YA1fGe8HbFCHAmLcKgz7Ft8c3LBGACiohF5AdFR6PQLHGfxgyESph9FLm8p7zM4wahBjFCEkgAtSQEyjNCuy8yE8jwpZxfCe1KSwjG" + ], + "txHash": "017232691d2d6d1c6c366943d536a1d1818101a6289a9f544c49fa54dd00c2e1", + "hex": "0200000002e1c200dd54fa494c549f9a28a6018181d1a136d54369366c1c6d2d1d69327201000000006b483045022100bb85f1b6a241a1c594c7686589e62438b2a9d25de106b4a9bb241f05beaed76e02204dd2e495462a448adf73197bfea811d7f76fde1657a988dfaba588ad2b964260412103ba2abd8d0a84d0ed16c07569581aeebc1619661627527c48a6a7778d529e5cf7ffffffffe1c200dd54fa494c549f9a28a6018181d1a136d54369366c1c6d2d1d69327201010000006a47304402202e7f45406b0225cffa0d9de135a9233b98accc9ea2601f3b980bcd030d2dfdc802205c3b32c93bc5321e0040a01b2062a31037f2235ce37e9883f17e0919d1b3ad5841210300251d96a333cb1712a6ce2491670ccf156ba51d56265d23b3f1ca88dc0911d1ffffffff01ec8aeb0b000000001976a914fe7325733cb8a245f39300b3c01eb218f54f8cc188ac00000000", + "amounts": [ + 99995500, + 99995500 + ], + "outputs": [ + "bchreg:qrl8xftn8ju2y30njvqt8sq7kgv02nuvcymle9tr0k" + ] + }, + { + "xprivs": [ + "tprv8jwG6YA1fGe8TDaPJgNPpGg4Lw4ui6ypX9MBJGwgrQEfSifG7sA3L5kX4mif1ToufcMQFfRKavBew5rw9HKcHjjbZBE3zYJFbrAR6QvxZZK", + "tprv8jwG6YA1fGe8WP5MiS2b8JrrqMTcttJ11FMBv9Z8UAzkj3G2NHcxyJsbmjPQ6sX5NLtcVBgcmPFP7mjNZewNZ7A2v6HeofXS6nPvVKXHkoD" + ], + "txHash": "d39387deba6166d99e3fe35a54d715bfccae883c303575e97d555b7c57d1975c", + "hex": "02000000025c97d1577c5b557de97535303c88aeccbf15d7545ae33f9ed96661bade8793d3000000006a47304402206f49ad053ed79c0e7cbeeb0463889e9e51da503bebd6615108455e2e5e23e86e0220510041031e44eb466fbea0ffd5ccc3e749a01e7135d014b0e7050d5d74e9a620412102338993f9038fbff3c595d8a5eca8f36c5c7c1f837f60a2aec1e9bd3f06acbb2dffffffff5c97d1577c5b557de97535303c88aeccbf15d7545ae33f9ed96661bade8793d3010000006a47304402202b47efa8d290ef8bab184ed297a08aecfe772dd1fc889a91664d6127fe32f6b702204f6f83351f81df5703a9fa64c1ba2e1fb418d3944eee025408d6d30ea2907d9d412102101fd2a369bf6ef3e3ae69bd0e3a86f4c9d5670dae8588792ec0dc23a7bed47dffffffff01d853eb0b000000001976a9144156292b93d85702651e163326b0f6374031cb6888ac00000000", + "amounts": [ + 99988450, + 99988450 + ], + "outputs": [ + "bchreg:qpq4v2ftj0v9wqn9rctrxf4s7cm5qvwtdqn2nmkwk7" + ] + }, + { + "xprivs": [ + "tprv8jwG6YA1fGe8fvc31CxrmL81j3Le2iGmkm6HkpC2Mw8ZYKAQMCd5y2UZ8rMFossHwwPVfL28Cjizd2fweeQmPeWtnirBEbZLFZ3LutsE6Q5", + "tprv8jwG6YA1fGe8icVTQp2n5nWJKSLCErHXqGRy6fcby9h1QUN9Nxy6Agxg8atUL687XtwV8bJvotdjVLaZ6rMwea2k9Em2Hk418LkFK79FKgj" + ], + "txHash": "89b1b44fca675b0a8740c7493af3a67be3824985d37ffd52798fccbcc12fb0af", + "hex": "0200000002afb02fc1bccc8f7952fd7fd3854982e37ba6f33a49c740870a5b67ca4fb4b189000000006a47304402203689aab908c142791d5e7c84ab5b5e4cc3332bf921292216464326d489729bb702200f3d31fe6c77482946d7d84571c6a05b78e6ed01813a0c4ac50bd57f01f5ebf4412102747da20b143a15a33c9d7165815f79ede81881044e23066d2fc803d43a21deb2ffffffffafb02fc1bccc8f7952fd7fd3854982e37ba6f33a49c740870a5b67ca4fb4b189010000006b483045022100c574a287502e7f782a244156445b7130bbc7934e5f784a55b3535f83576c667602200f9c636dce7e7414ce0dac5a652ddc9f4ebeb48144cd01f860b2ea8d984b4e134121032bfc541ed6be30e1e02b5f3827a81c4b59426611b697fd202d40cbd65d6e53deffffffff01c41ceb0b000000001976a91484a2862dc63631bb615a16807779c2c5a664c15f88ac00000000", + "amounts": [ + 99981400, + 99981400 + ], + "outputs": [ + "bchreg:qzz29p3dccmrrwmptgtgqamectz6vexptuey04307q" + ] + } ] } }, @@ -1426,8 +1690,102 @@ "script": "OP_RETURN 426974636f696e2043617368", "hex": "0200000001fa9ebcdee96f09e1b5049fe222d16574e0100fa1e538f78b248bd91d26b88edc000000006a4730440220337ccd2d539e25c7b12388e7e416c8e90f4d416b502d0086e83d0ec809f473f2022002143e840c1ae49dc19fe5a5b291f3466c096e5105a26a26e11159916983d3034121026d0446d88c057cdf3b59f4442603609282672c4961c44e738ca48387d911f782ffffffff0208b9eb0b000000001976a914b0cc863e96ed2492f085f2141447d91ce3d51af788ac00000000000000000e6a0c426974636f696e204361736800000000" } + ], + "regtest": [ + { + "xpriv": "tprv8kNvR1z7HT4RJ72z5HGtpPVVrTMY9uVFJh9sbDw62CBU2iKbCUkqjHUSjpT3drDVEWsqrTJqW4C2EEMnb2RueNo6MWtPdPmRnGdx97XZijS", + "txHash": "126d9e84a51b64ca1d88b47f42fdada0ac7fee543e49feffef01114f9f61111e", + "data": "Satoshi Nakamoto", + "amount": 199999344, + "output": "bchreg:qzcvep37jmkjfyhsshepg9z8myww84g67uzu3pgfr3", + "script": "OP_RETURN 5361746f736869204e616b616d6f746f", + "hex": "02000000011e11619f4f1101effffe493e54ee7faca0adfd427fb4881dca641ba5849e6d12000000006a4730440220094fcec3637c1b7473818198558b5b6dcee0026034119927b12c11943d7d894d0220489ed60a6b01d7d4c6146ae36d6dc81a329391d6796c2b851b99ac934f96b4af4121026d0446d88c057cdf3b59f4442603609282672c4961c44e738ca48387d911f782ffffffff0228beeb0b000000001976a914b0cc863e96ed2492f085f2141447d91ce3d51af788ac0000000000000000126a105361746f736869204e616b616d6f746f00000000" + }, + { + "xpriv": "tprv8kNvR1z7HT4RJ72z5HGtpPVVrTMY9uVFJh9sbDw62CBU2iKbCUkqjHUSjpT3drDVEWsqrTJqW4C2EEMnb2RueNo6MWtPdPmRnGdx97XZijS", + "txHash": "0655231b5a008ef23bfaa16ec7b08ae178e81f033834babce84fd4114ea2b226", + "data": "BCHForEveryone", + "amount": 199999016, + "output": "bchreg:qzcvep37jmkjfyhsshepg9z8myww84g67uzu3pgfr3", + "script": "OP_RETURN 424348466f7245766572796f6e65", + "hex": "020000000126b2a24e11d44fe8bcba3438031fe878e18ab0c76ea1fa3bf28e005a1b235506000000006a47304402204d972c018376836ba0b40a0f93b5d93beb2ce9be24d1eff12a9c44eb33e6f2f3022062cf5abf201312f720d8e22eb48ca021da0364edd755f6991a7a6e90f24cd3804121026d0446d88c057cdf3b59f4442603609282672c4961c44e738ca48387d911f782ffffffff02e0bceb0b000000001976a914b0cc863e96ed2492f085f2141447d91ce3d51af788ac0000000000000000106a0e424348466f7245766572796f6e6500000000" + }, + { + "xpriv": "tprv8kNvR1z7HT4RJ72z5HGtpPVVrTMY9uVFJh9sbDw62CBU2iKbCUkqjHUSjpT3drDVEWsqrTJqW4C2EEMnb2RueNo6MWtPdPmRnGdx97XZijS", + "txHash": "6b95aa8764096fb531ae235acbd281935fc7f4fc055992b7060fb36ff3cce8d6", + "data": "chancellor on brink of second bailout for banks", + "amount": 199998688, + "output": "bchreg:qzcvep37jmkjfyhsshepg9z8myww84g67uzu3pgfr3", + "script": "OP_RETURN 6368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73", + "hex": "0200000001d6e8ccf36fb30f06b7925905fcf4c75f9381d2cb5a23ae31b56f096487aa956b000000006a473044022006b7dd030c3eb56ba6993e7f770e7ddb8732132aede642e61af98669f2500c62022029308c95c25a56df4aa7a3eead08d16470d8b827749d747811e2b0581273b28e4121026d0446d88c057cdf3b59f4442603609282672c4961c44e738ca48387d911f782ffffffff0298bbeb0b000000001976a914b0cc863e96ed2492f085f2141447d91ce3d51af788ac0000000000000000316a2f6368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b7300000000" + }, + { + "xpriv": "tprv8kNvR1z7HT4RJ72z5HGtpPVVrTMY9uVFJh9sbDw62CBU2iKbCUkqjHUSjpT3drDVEWsqrTJqW4C2EEMnb2RueNo6MWtPdPmRnGdx97XZijS", + "txHash": "86c1fc1dbbdcb9d42ef174f31a79520547f9da1beec4aed9184fc62ef0ecce9e", + "data": "Tokenize all the things", + "amount": 199998360, + "output": "bchreg:qzcvep37jmkjfyhsshepg9z8myww84g67uzu3pgfr3", + "script": "OP_RETURN 546f6b656e697a6520616c6c20746865207468696e6773", + "hex": "02000000019eceecf02ec64f18d9aec4ee1bdaf9470552791af374f12ed4b9dcbb1dfcc186000000006b483045022100ae630f40cb0d508115f723df49ea2b5c49f141e5623ad5030a7221109db7b86f02201aa411112dcc0a558c342ee539cfc6d9c7e49c1542957bbf52dbe5421d6de7554121026d0446d88c057cdf3b59f4442603609282672c4961c44e738ca48387d911f782ffffffff0250baeb0b000000001976a914b0cc863e96ed2492f085f2141447d91ce3d51af788ac0000000000000000196a17546f6b656e697a6520616c6c20746865207468696e677300000000" + }, + { + "xpriv": "tprv8kNvR1z7HT4RJ72z5HGtpPVVrTMY9uVFJh9sbDw62CBU2iKbCUkqjHUSjpT3drDVEWsqrTJqW4C2EEMnb2RueNo6MWtPdPmRnGdx97XZijS", + "txHash": "dc8eb8261dd98b248bf738e5a10f10e07465d122e29f04b5e1096fe9debc9efa", + "data": "Bitcoin Cash", + "amount": 199998032, + "output": "bchreg:qzcvep37jmkjfyhsshepg9z8myww84g67uzu3pgfr3", + "script": "OP_RETURN 426974636f696e2043617368", + "hex": "0200000001fa9ebcdee96f09e1b5049fe222d16574e0100fa1e538f78b248bd91d26b88edc000000006a4730440220337ccd2d539e25c7b12388e7e416c8e90f4d416b502d0086e83d0ec809f473f2022002143e840c1ae49dc19fe5a5b291f3466c096e5105a26a26e11159916983d3034121026d0446d88c057cdf3b59f4442603609282672c4961c44e738ca48387d911f782ffffffff0208b9eb0b000000001976a914b0cc863e96ed2492f085f2141447d91ce3d51af788ac00000000000000000e6a0c426974636f696e204361736800000000" + } ] }, + "bip66": [ + { + "DER": "3044022029db2d5f4e1dcc04e19266cce3cb135865784c62ab653b307f0e0bb744f5c2aa022000a97f5826912cac8b44d9f577a26f169a2f8db781f2ddb7de2bc886e93b6844", + "r": "29db2d5f4e1dcc04e19266cce3cb135865784c62ab653b307f0e0bb744f5c2aa", + "s": "00a97f5826912cac8b44d9f577a26f169a2f8db781f2ddb7de2bc886e93b6844" + }, + { + "DER": "304302201ea1fdff81b3a271659df4aad19bc4ef83def389131a36358fe64b245632e777021f29e164658be9ce810921bf81d6b86694785a79ea1e52dbfa5105148d1f0bc1", + "r": "1ea1fdff81b3a271659df4aad19bc4ef83def389131a36358fe64b245632e777", + "s": "29e164658be9ce810921bf81d6b86694785a79ea1e52dbfa5105148d1f0bc1" + }, + { + "DER": "304402201b19519b38ca1e6813cd25649ad36be8bc6a6f2ad9758089c429acd9ce0b572f02203bf32193c8a3a3de1f847cd6e6eebf43c96df1ffa4d7fe920f8f71708920c65f", + "r": "1b19519b38ca1e6813cd25649ad36be8bc6a6f2ad9758089c429acd9ce0b572f", + "s": "3bf32193c8a3a3de1f847cd6e6eebf43c96df1ffa4d7fe920f8f71708920c65f" + }, + { + "DER": "3044022000c8da1836747d05a6a3d2c395825edce827147d15909e66939a5037d5916e6f022017823c2da62f539d7f8e1e186eaea7a401ab3c077dcfc44aeaf3e13fac99bdbc", + "r": "00c8da1836747d05a6a3d2c395825edce827147d15909e66939a5037d5916e6f", + "s": "17823c2da62f539d7f8e1e186eaea7a401ab3c077dcfc44aeaf3e13fac99bdbc" + }, + { + "DER": "3042021e2ff2609c8dc0392d3731a2c6312841e09c76f10b83e2b52604dc84886dd502200090ac80e787c063618192bc04758e6666d0179c377fb2f3d6105d58000f33ac", + "r": "2ff2609c8dc0392d3731a2c6312841e09c76f10b83e2b52604dc84886dd5", + "s": "0090ac80e787c063618192bc04758e6666d0179c377fb2f3d6105d58000f33ac" + }, + { + "DER": "3041021d00feb1a12c27e5fe261acc64c0923add082573883e0800d8e4080fa9bb02202e7aeb97f4046ea3be60d2896a19c8dc269ab5eb2de968912cd52a076a0a42e9", + "r": "00feb1a12c27e5fe261acc64c0923add082573883e0800d8e4080fa9bb", + "s": "2e7aeb97f4046ea3be60d2896a19c8dc269ab5eb2de968912cd52a076a0a42e9" + }, + { + "DER": "3042021d00feb1a12c27e5fe261acc64c0923add082573883e0800d8e4080fa9bb0221008aeb97f4046ea3be60d2896a19c8dc269ab5eb2de968912cd52a076a0a42e925", + "r": "00feb1a12c27e5fe261acc64c0923add082573883e0800d8e4080fa9bb", + "s": "008aeb97f4046ea3be60d2896a19c8dc269ab5eb2de968912cd52a076a0a42e925" + }, + { + "DER": "303e021d00c1d545da2e4edfbc65e9267d3c0a6fdda41793d0fd945f15acbcf0dd021d009acffda3ca5e7c349c35ba606f0a8f1ec7815b653b51695ca9ee69a6", + "r": "00c1d545da2e4edfbc65e9267d3c0a6fdda41793d0fd945f15acbcf0dd", + "s": "009acffda3ca5e7c349c35ba606f0a8f1ec7815b653b51695ca9ee69a6" + }, + { + "DER": "3006020100020100", + "r": "00", + "s": "00" + } + ], "bip68": { "encode": [ { @@ -1459,5 +1817,25 @@ "result": "0x0100fffe" } ] + }, + "locktime": { + "mainnet": [ + { + "xpriv": "xprvA3oFxxSXJZ5bcURHc3Mk6bdF8fiqtyruYJkUAZjcAjPdhd4jogpKZNZRhqLMFYu4VyJmcetjDxaW34igaNfGYRvSNZQBdM7VkABsLnNP5Dd", + "txHash": "021eb6dcbfa33979ccb45fcf59c1c9e3805505d50418c2108c9d83fdaf6393f3", + "lockTime": 500000, + "amount": 8821, + "output": "bitcoincash:qzvpzzj8yylqy6amtk7xs9pfksdx3dc0nu3k8eqax5", + "hex": "0200000001f39363affd839d8c10c21804d5055580e3c9c159cf5fb4cc7939a3bfdcb61e02000000006a4730440220588a14faadd7f4c38ef63a87578e5484b57415acbbeafe692cae36384c3fde9c02201d6e52c3d7010faaca3d9ca89a1091a63aaf5ebbdbb9d5c822fa62f4380bd87341210351cedb293c6aef49e3e5fa4bb554a6a4833fc83702eb4e027a09e018392777000100000001b5210000000000001976a91498110a47213e026bbb5dbc681429b41a68b70f9f88ac20a10700" + }, + { + "xpriv": "xprvA3oFxxSXJZ5bcURHc3Mk6bdF8fiqtyruYJkUAZjcAjPdhd4jogpKZNZRhqLMFYu4VyJmcetjDxaW34igaNfGYRvSNZQBdM7VkABsLnNP5Dd", + "txHash": "24c196f28b5ad1c08c2b68e4dd3294fa307354267f028600c3001a0dea6e175f", + "lockTime": 600000, + "amount": 8493, + "output": "bitcoincash:qzvpzzj8yylqy6amtk7xs9pfksdx3dc0nu3k8eqax5", + "hex": "02000000015f176eea0d1a00c30086027f26547330fa9432dde4682b8cc0d15a8bf296c124000000006a473044022050e94b156df6dee0af24593a60f7be5ea29986f8d7ac19d64da6b75dd311a9af022028a07ddd56d3ddc85bf0aaec5bc7b088e1ffdf5f63048d25c5e90a41e21dd51e41210351cedb293c6aef49e3e5fa4bb554a6a4833fc83702eb4e027a09e0183927770001000000016d200000000000001976a91498110a47213e026bbb5dbc681429b41a68b70f9f88acc0270900" + } + ] } } diff --git a/test/unit/mocks/address-mock.js b/test/unit/mocks/address-mock.js new file mode 100644 index 00000000..146fe456 --- /dev/null +++ b/test/unit/mocks/address-mock.js @@ -0,0 +1,165 @@ +/* + Mock data used for unit testing. +*/ + +module.exports = { + details: { + legacyAddress: "3CnzuFFbtgVyHNiDH8BknGo3PQ3dpdThgJ", + cashAddress: "bitcoincash:ppuukp49np467kyzxl0fkla34rmgcddhvc33ce2d6l", + balance: 300.0828874, + balanceSat: 30008288740, + totalReceived: 12945.45174649, + totalReceivedSat: 1294545174649, + totalSent: 12645.36885909, + totalSentSat: 1264536885909, + unconfirmedBalance: 0, + unconfirmedBalanceSat: 0, + unconfirmedTxApperances: 0, + txApperances: 1042, + transactions: [ + "b29425a876f62e114508e67e66b5eb1ab0d320d7c9a57fb0ece086a36e2b7309" + ], + currentPage: 0, + pagesTotal: 1, + slpAddress: "simpleledger:qrdka2205f4hyukutc2g0s6lykperc8nsuc8pkcp7h" + }, + + // An example of address with multiple utxos. + utxos1: { + utxos: [ + { + txid: + "27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c", + vout: 0, + amount: 0.001, + satoshis: 100000, + height: 560430, + confirmations: 25161 + }, + { + txid: + "6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d", + vout: 0, + amount: 0.0013, + satoshis: 130000, + height: 560039, + confirmations: 25552 + } + ], + legacyAddress: "1M1FYu4zuVaxRPWLZG5CnP8qQrZaqu6c2L", + cashAddress: "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", + slpAddress: "simpleledger:qrdka2205f4hyukutc2g0s6lykperc8nsuc8pkcp7h", + scriptPubKey: "76a914db6ea94fa26b7272dc5e1487c35f258391e0f38788ac" + }, + + // An example of an address with no utxos. + utxos2: { + utxos: [], + legacyAddress: "19LXyLnux1tbTdHnMuYAgDZ81ZQDWEi12g", + cashAddress: "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v", + slpAddress: "simpleledger:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4q39c44a2j", + scriptPubKey: "" + }, + + // Example of an address with an unconfirmed UTXO + unconfirmed1: { + utxos: [ + { + txid: + "3904ffe6f8fba4ceda5e887130f60fcb18bdc7dcee10392a57f89475c5c108f1", + vout: 0, + amount: 0.03608203, + satoshis: 3608203, + confirmations: 0, + ts: 1559670801 + } + ], + legacyAddress: "1AyWs8U4HUnTLmxxFiGoJbsXauRsvBrcKW", + cashAddress: "bitcoincash:qpkkjkhe29mqhqmu3evtq3dsnruuzl3rku6usknlh5", + slpAddress: "simpleledger:qpkkjkhe29mqhqmu3evtq3dsnruuzl3rkuk8mdxlf2", + scriptPubKey: "76a9146d695af951760b837c8e58b045b098f9c17e23b788ac" + }, + + // Example of an address without any unconfirmed utxos. + unconfirmed2: { + utxos: [], + legacyAddress: "1M1FYu4zuVaxRPWLZG5CnP8qQrZaqu6c2L", + cashAddress: "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", + slpAddress: "simpleledger:qrdka2205f4hyukutc2g0s6lykperc8nsuc8pkcp7h", + scriptPubKey: "76a914db6ea94fa26b7272dc5e1487c35f258391e0f38788ac" + }, + + transactions: { + pagesTotal: 1, + txs: [ + { + txid: + "ec7bc8349386e3e1939bbdc4f8092fdbdd6a380734e68486b558cd594c451d5b", + version: 2, + locktime: 0, + vin: [ + { + txid: + "4f1fc57c33659628938db740449bf92fb75799e1d5750a4aeef80eb52d6df1e0", + vout: 0, + sequence: 4294967295, + n: 0, + scriptSig: { + hex: + "483045022100a3662a19ae384a1ceddea57765e425e61b04823e976d574da3911ac6b55d7f9b02200e571d985bce987675a2d58587a346fa40c39f4df13dc88548a92c52d5b24422412103f953f7630acc15bd3f5078c698f3af777286ae955b57e4857c158f75d87adb5f", + asm: + "3045022100a3662a19ae384a1ceddea57765e425e61b04823e976d574da3911ac6b55d7f9b02200e571d985bce987675a2d58587a346fa40c39f4df13dc88548a92c52d5b24422[ALL|FORKID] 03f953f7630acc15bd3f5078c698f3af777286ae955b57e4857c158f75d87adb5f" + }, + addr: "17HPz8RQ4XM6mjre6aspvqyj1j648CZidM", + valueSat: 1111, + value: 0.00001111, + doubleSpentTxID: null + }, + { + txid: + "126d62c299e7e14c66fe0b485d13082c23641f003690462046bc24ad2d1180c1", + vout: 0, + sequence: 4294967295, + n: 1, + scriptSig: { + hex: + "47304402203e3f923207111ff9bbd2fb5ab1a49a9145ad809ee0cad0e0ddaed64bfe38dc16022012ee288fb413bd500c63f8bb95e46b6b57d34762decd46b7188478a1c398eeda412103f953f7630acc15bd3f5078c698f3af777286ae955b57e4857c158f75d87adb5f", + asm: + "304402203e3f923207111ff9bbd2fb5ab1a49a9145ad809ee0cad0e0ddaed64bfe38dc16022012ee288fb413bd500c63f8bb95e46b6b57d34762decd46b7188478a1c398eeda[ALL|FORKID] 03f953f7630acc15bd3f5078c698f3af777286ae955b57e4857c158f75d87adb5f" + }, + addr: "17HPz8RQ4XM6mjre6aspvqyj1j648CZidM", + valueSat: 1000, + value: 0.00001, + doubleSpentTxID: null + } + ], + vout: [ + { + value: "0.00001736", + n: 0, + scriptPubKey: { + hex: "76a914d96ac75ca8df9729d278da50ccd7355c5785444e88ac", + asm: + "OP_DUP OP_HASH160 d96ac75ca8df9729d278da50ccd7355c5785444e OP_EQUALVERIFY OP_CHECKSIG", + addresses: ["1LpbYkEM5cryfhs58tH8c93p4SGzit7UrP"], + type: "pubkeyhash" + }, + spentTxId: null, + spentIndex: null, + spentHeight: null + } + ], + blockheight: -1, + confirmations: 0, + time: 1559673337, + valueOut: 0.00001736, + size: 339, + valueIn: 0.00002111, + fees: 0.00000375 + } + ], + legacyAddress: "1LpbYkEM5cryfhs58tH8c93p4SGzit7UrP", + cashAddress: "bitcoincash:qrvk436u4r0ew2wj0rd9pnxhx4w90p2yfc29ta0d2n", + currentPage: 0 + } +} diff --git a/test/unit/mocks/block-mock.js b/test/unit/mocks/block-mock.js new file mode 100644 index 00000000..844140f6 --- /dev/null +++ b/test/unit/mocks/block-mock.js @@ -0,0 +1,29 @@ +/* + Mock data used for unit testing. +*/ + +module.exports = { + details: { + hash: "000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0", + size: 216, + height: 507, + version: 1, + merkleroot: + "a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8", + tx: ["a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8"], + time: 1231973656, + nonce: 330467862, + bits: "1d00ffff", + difficulty: 1, + chainwork: + "000000000000000000000000000000000000000000000000000001fc01fc01fc", + confirmations: 585104, + previousblockhash: + "00000000a99525c043fd7e323414b60add43c254c44860094048f9c01e9a5fdd", + nextblockhash: + "000000000d550f4161f2702165fdd782ec72ff9c541f864ebb8256b662b7e51a", + reward: 50, + isMainChain: true, + poolInfo: {} + } +} diff --git a/test/unit/mocks/blockchain-mock.js b/test/unit/mocks/blockchain-mock.js new file mode 100644 index 00000000..17b7c43a --- /dev/null +++ b/test/unit/mocks/blockchain-mock.js @@ -0,0 +1,51 @@ +/* + Mock data used for unit testing. +*/ + +module.exports = { + bestBlockHash: + "0000000000000000008e1f65f875703872544aa888c7ca6587f055f8f5fbd4bf", + + blockHeader: { + hash: "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201", + confirmations: 85727, + height: 500000, + version: 536870912, + versionHex: "20000000", + merkleroot: + "4af279645e1b337e655ae3286fc2ca09f58eb01efa6ab27adedd1e9e6ec19091", + time: 1509343584, + mediantime: 1509336533, + nonce: 3604508752, + bits: "1809b91a", + difficulty: 113081236211.4533, + chainwork: + "0000000000000000000000000000000000000000007ae48aca46e3b449ad9714", + previousblockhash: + "0000000000000000043831d6ebb013716f0580287ee5e5687e27d0ed72e6e523", + nextblockhash: + "00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3" + }, + + txOutProof: + "0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01", + + verifiedProof: + "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7", + + txOutUnspent: { + bestblock: + "000000000000000000b441e02f5b1b9f5b3def961047afcc6f2f5636c952705e", + confirmations: 2, + value: 0.00006, + scriptPubKey: { + asm: + "OP_DUP OP_HASH160 d19fae66b685f5c3633c0db0600313918347225f OP_EQUALVERIFY OP_CHECKSIG", + hex: "76a914d19fae66b685f5c3633c0db0600313918347225f88ac", + reqSigs: 1, + type: "pubkeyhash", + addresses: ["bitcoincash:qrgeltnxk6zltsmr8sxmqcqrzwgcx3eztusrwgf0x3"] + }, + coinbase: false + } +} diff --git a/test/unit/mocks/cashaccounts-mock.js b/test/unit/mocks/cashaccounts-mock.js new file mode 100644 index 00000000..f1be9512 --- /dev/null +++ b/test/unit/mocks/cashaccounts-mock.js @@ -0,0 +1,77 @@ +/* + Mock data used for unit testing. +*/ + +module.exports = { + lookup: { + identifier: "cgcardona#122;", + information: { + emoji: "🍞", + name: "cgcardona", + number: 122, + collision: { + hash: "6383276713", + count: 0, + length: 0 + }, + payment: [ + { + type: "Key Hash", + address: "bitcoincash:qrhncn6hgkhljqg4fuq4px5qg74sjz9fqqj64s9la9" + } + ] + } + }, + check: { + identifier: "cgcardona#122", + block: 563742, + results: [ + { + transaction: + "0100000001A8421264294082C08C0611E162BD49999443EF577C57923BD052F7202B09408E010000006A473044022039F4DD9AD6BC2C4E799D135BB68B5E05E71F83731EFC63260C7FB16F63BB842802203DEA9E82E97D28ADC9A9567E16762CF3663C24CE6A42AEDDC1E273E50B8CA9C941210202435C144A77C6ED76C3A74EE6006A9255B449F1B2F09FA2668027FEC106CFA1FFFFFFFF020000000000000000266A0401010101096367636172646F6E611501EF3C4F5745AFF901154F01509A8047AB0908A9008CD51100000000001976A914919908484336464C2A9938D24149A4177606340F88AC00000000", + inclusionProof: + "0000C020C98F109DA027EB72472AC903F6E2BFA993D88724734B2C01000000000000000019213AEE113214AF03EEEE303F733708AD79F259A148F4A17C496302E1D093DF7D9D2E5C4CE10418F2AE48C41F000000067AA86CA831AB260AF59E0ED93305939D9A300BD66076EB18D155143E992950C33A46C140D7202C577D6C25DCD8F315D304285D8BD890C41925F00CC256C22CC69E1410317FD69D5A58F762EE26B469DC1909F2D0DE5E471B0AC09C686C41664585DF32ABA0EEAF50B6AB66010206DE24A5C576CBC331EF153507E9E20D1C18506E24DBEDB0A0B66705E10376CD19ADB4A605098058ACB805D24456CC004CCA78ABA3969F47284773B7809C81B93E2CCCC280218272164AE5D90245A629F6801802EB00" + } + ] + }, + reverseLookup: { + results: [ + { + accountEmoji: "☯", + nameText: "Jonathan", + accountNumber: 100, + accountHash: "5876958390", + accountCollisionLength: 0, + payloadType: 1, + payloadAddress: "bitcoincash:qr4aadjrpu73d2wxwkxkcrt6gqxgu6a7usxfm96fst" + }, + { + accountEmoji: "🍭", + nameText: "ConfirmationTest", + accountNumber: 113, + accountHash: "4640561912", + accountCollisionLength: 0, + payloadType: 1, + payloadAddress: "bitcoincash:qr4aadjrpu73d2wxwkxkcrt6gqxgu6a7usxfm96fst" + }, + { + accountEmoji: "🌽", + nameText: "Bob", + accountNumber: 4035, + accountHash: "7443382842", + accountCollisionLength: 0, + payloadType: 1, + payloadAddress: "bitcoincash:qr4aadjrpu73d2wxwkxkcrt6gqxgu6a7usxfm96fst" + }, + { + accountEmoji: "🎀", + nameText: "qr4aadjrpu73d2wxwkxkcrt6gqxgu6a7usxfm96fst", + accountNumber: 7084, + accountHash: "4319915751", + accountCollisionLength: 0, + payloadType: 1, + payloadAddress: "bitcoincash:qr4aadjrpu73d2wxwkxkcrt6gqxgu6a7usxfm96fst" + } + ] + } +} diff --git a/test/unit/mocks/rawtransactions-mock.js b/test/unit/mocks/rawtransactions-mock.js new file mode 100644 index 00000000..a8578715 --- /dev/null +++ b/test/unit/mocks/rawtransactions-mock.js @@ -0,0 +1,118 @@ +/* + Mock data used for unit testing. +*/ + +module.exports = { + decodedTx: { + txid: "a332237d82a2543af1b0e1ae3c8cea1610c290ebcaf084a7e9894a61de0be988", + hash: "a332237d82a2543af1b0e1ae3c8cea1610c290ebcaf084a7e9894a61de0be988", + version: 2, + size: 226, + locktime: 0, + vin: [ + { + txid: + "21cced645eab150585ed7ca7c96edebab5793cc0a3b3b286c42fd7d6d798b5b9", + vout: 1, + scriptSig: { + asm: + "3045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd41390[ALL|FORKID] 0360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413d", + hex: + "483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413d" + }, + sequence: 4294967295 + } + ], + vout: [ + { + value: 0.0001, + n: 0, + scriptPubKey: { + asm: + "OP_DUP OP_HASH160 eb4b180def88e3f5625b2d8ae2c098ff7d85f664 OP_EQUALVERIFY OP_CHECKSIG", + hex: "76a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac", + reqSigs: 1, + type: "pubkeyhash", + addresses: ["bitcoincash:qr45kxqda7yw8atztvkc4ckqnrlhmp0kvsan3xnznu"] + } + }, + { + value: 0.09989752, + n: 1, + scriptPubKey: { + asm: + "OP_DUP OP_HASH160 eb4b180def88e3f5625b2d8ae2c098ff7d85f664 OP_EQUALVERIFY OP_CHECKSIG", + hex: "76a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac", + reqSigs: 1, + type: "pubkeyhash", + addresses: ["bitcoincash:qr45kxqda7yw8atztvkc4ckqnrlhmp0kvsan3xnznu"] + } + } + ] + }, + + rawTx: + "010000000186db5c732438733e305e2e6fb6f15cab898e61202e3d8708c8cf9db90d20a862000000006a47304402202578ad648a8bab3065295155a07337d9d01c165f506e20faeaf582a9feca188602207aac7cab6e6ff9c63ff1b95543f1f2f0b866a2494d98b1bf58055094c0989e80412102b84cc40b16cf6f76ac47fff353a301f8394d9a8f0199c56269897ae3e11559eeffffffff029aa7ce06000000001976a914270f290bf8f4eba093063330b9a9e8202b66217b88acb06b3c00000000001976a9148b55a3985e74ea4137f0f1749439f161b52b861c88ac00000000", + + decodedTx: { + txid: "23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1", + hash: "23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1", + version: 1, + size: 225, + locktime: 0, + vin: [ + { + txid: + "62a8200db99dcfc808873d2e20618e89ab5cf1b66f2e5e303e733824735cdb86", + vout: 0, + scriptSig: { + asm: + "304402202578ad648a8bab3065295155a07337d9d01c165f506e20faeaf582a9feca188602207aac7cab6e6ff9c63ff1b95543f1f2f0b866a2494d98b1bf58055094c0989e80[ALL|FORKID] 02b84cc40b16cf6f76ac47fff353a301f8394d9a8f0199c56269897ae3e11559ee", + hex: + "47304402202578ad648a8bab3065295155a07337d9d01c165f506e20faeaf582a9feca188602207aac7cab6e6ff9c63ff1b95543f1f2f0b866a2494d98b1bf58055094c0989e80412102b84cc40b16cf6f76ac47fff353a301f8394d9a8f0199c56269897ae3e11559ee" + }, + sequence: 4294967295 + } + ], + vout: [ + { + value: 1.14206618, + n: 0, + scriptPubKey: { + asm: + "OP_DUP OP_HASH160 270f290bf8f4eba093063330b9a9e8202b66217b OP_EQUALVERIFY OP_CHECKSIG", + hex: "76a914270f290bf8f4eba093063330b9a9e8202b66217b88ac", + reqSigs: 1, + type: "pubkeyhash", + addresses: ["bitcoincash:qqns72gtlr6whgynqcenpwdfaqszke3p0vntl8lvhz"] + } + }, + { + value: 0.03959728, + n: 1, + scriptPubKey: { + asm: + "OP_DUP OP_HASH160 8b55a3985e74ea4137f0f1749439f161b52b861c OP_EQUALVERIFY OP_CHECKSIG", + hex: "76a9148b55a3985e74ea4137f0f1749439f161b52b861c88ac", + reqSigs: 1, + type: "pubkeyhash", + addresses: ["bitcoincash:qz94tgucte6w5sfh7rchf9pe79sm22uxrsn6dh8smf"] + } + } + ], + hex: + "010000000186db5c732438733e305e2e6fb6f15cab898e61202e3d8708c8cf9db90d20a862000000006a47304402202578ad648a8bab3065295155a07337d9d01c165f506e20faeaf582a9feca188602207aac7cab6e6ff9c63ff1b95543f1f2f0b866a2494d98b1bf58055094c0989e80412102b84cc40b16cf6f76ac47fff353a301f8394d9a8f0199c56269897ae3e11559eeffffffff029aa7ce06000000001976a914270f290bf8f4eba093063330b9a9e8202b66217b88acb06b3c00000000001976a9148b55a3985e74ea4137f0f1749439f161b52b861c88ac00000000", + blockhash: + "000000000000000003a09a7d68a0d62fd0ab51c368372e46bac84277e2df47e2", + confirmations: 20168, + time: 1547752564, + blocktime: 1547752564 + }, + + decodedScript: { + asm: + "30450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed59201 02e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16", + type: "nonstandard", + p2sh: "bitcoincash:pqwndulzwft8dlmqrteqyc9hf823xr3lcc7ypt74ts" + } +} diff --git a/test/unit/mocks/transactions-mock.js b/test/unit/mocks/transactions-mock.js new file mode 100644 index 00000000..46695e5f --- /dev/null +++ b/test/unit/mocks/transactions-mock.js @@ -0,0 +1,45 @@ +/* + Mock data used for unit testing. +*/ + +module.exports = { + details: { + txid: "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33", + version: 1, + locktime: 0, + vin: [ + { + coinbase: "04ffff001d02fd04", + sequence: 4294967295, + n: 0 + } + ], + vout: [ + { + value: "50.00000000", + n: 0, + scriptPubKey: { + hex: + "4104f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446aac", + asm: + "04f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446a OP_CHECKSIG", + addresses: ["1BW18n7MfpU35q4MTBSk8pse3XzQF8XvzT"], + type: "pubkeyhash", + cashAddrs: ["bitcoincash:qpej6mkrwca4tvy2snq4crhrf88v4ljspysx0ueetk"] + }, + spentTxId: null, + spentIndex: null, + spentHeight: null + } + ], + blockhash: + "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", + blockheight: 1000, + confirmations: 585610, + time: 1232346882, + blocktime: 1232346882, + isCoinBase: true, + valueOut: 50, + size: 135 + } +} diff --git a/test/unit/mocks/util-mock.js b/test/unit/mocks/util-mock.js new file mode 100644 index 00000000..30029d65 --- /dev/null +++ b/test/unit/mocks/util-mock.js @@ -0,0 +1,18 @@ +/* + Mock data used for unit testing. +*/ + +module.exports = { + invalid: { + isvalid: false + }, + + valid: { + isvalid: true, + address: "bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z", + scriptPubKey: "76a9146b63a64b4727768fc4045f7ed439e3b811766a6688ac", + ismine: false, + iswatchonly: false, + isscript: false + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..8e7a6d25 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "module": "commonjs", + "strict": true, + "target": "es5", + "downlevelIteration": true, + "moduleResolution": "node", + "lib": ["es2017"], + "sourceMap": true, + "esModuleInterop": true + }, + "include": ["./lib", "./test", "./test/unit/**/*.ts"], + "files": ["index.ts"] +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..7e247055 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,7124 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" + integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== + dependencies: + "@babel/highlight" "^7.0.0" + +"@babel/generator@^7.4.0", "@babel/generator@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.5.tgz#873a7f936a3c89491b43536d12245b626664e3cf" + integrity sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ== + dependencies: + "@babel/types" "^7.5.5" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-function-name@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== + dependencies: + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-get-function-arity@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-split-export-declaration@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" + integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== + dependencies: + "@babel/types" "^7.4.4" + +"@babel/highlight@^7.0.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" + integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.4.3", "@babel/parser@^7.4.4", "@babel/parser@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.5.tgz#02f077ac8817d3df4a832ef59de67565e71cca4b" + integrity sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g== + +"@babel/runtime@^7.6.3": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.2.tgz#111a78002a5c25fc8e3361bedc9529c696b85a6a" + integrity sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw== + dependencies: + regenerator-runtime "^0.13.2" + +"@babel/template@^7.1.0", "@babel/template@^7.4.0": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" + integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.4.4" + "@babel/types" "^7.4.4" + +"@babel/traverse@^7.4.3": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.5.tgz#f664f8f368ed32988cd648da9f72d5ca70f165bb" + integrity sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ== + dependencies: + "@babel/code-frame" "^7.5.5" + "@babel/generator" "^7.5.5" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/parser" "^7.5.5" + "@babel/types" "^7.5.5" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/types@^7.0.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.5.tgz#97b9f728e182785909aa4ab56264f090a028d18a" + integrity sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@bitcoin-dot-com/bitcoincashjs2-lib@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@bitcoin-dot-com/bitcoincashjs2-lib/-/bitcoincashjs2-lib-4.1.0.tgz#c01025d99f6472bb298fd801f9e7e7b1519f66d4" + integrity sha512-p36L4ZTVsLnFQuAdVVsDoIVYGglkyb1VWn8EEYo/kixUVdT7Mvf3gsJ0MG1wIP57SZLTj46hyhklTfT8fNbG0A== + dependencies: + bech32 "^1.1.2" + bigi "^1.4.0" + bip66 "^1.1.0" + bitcoincash-ops "github:Bitcoin-com/bitcoincash-ops#2.0.0" + bs58check "^2.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.3" + ecurve "^1.0.0" + merkle-lib "^2.0.10" + pushdata-bitcoin "github:Bitcoin-com/pushdata-bitcoin#1.2.1" + randombytes "^2.0.1" + safe-buffer "^5.0.1" + typeforce "^1.11.3" + varuint-bitcoin "^1.0.4" + wif "^2.0.1" + +"@istanbuljs/nyc-config-typescript@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/nyc-config-typescript/-/nyc-config-typescript-0.1.3.tgz#944d15b3ebdb71f963a628daffaa25ade981bb86" + integrity sha512-EzRFg92bRSD1W/zeuNkeGwph0nkWf+pP2l/lYW4/5hav7RjKKBN5kV1Ix7Tvi0CMu3pC4Wi/U7rNisiJMR3ORg== + +"@nodelib/fs.scandir@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.1.tgz#7fa8fed654939e1a39753d286b48b4836d00e0eb" + integrity sha512-NT/skIZjgotDSiXs0WqYhgcuBKhUMgfekCmCGtkUAiLqZdOnrdjmZr9wRl3ll64J9NF79uZ4fk16Dx0yMc/Xbg== + dependencies: + "@nodelib/fs.stat" "2.0.1" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.1", "@nodelib/fs.stat@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.1.tgz#814f71b1167390cfcb6a6b3d9cdeb0951a192c14" + integrity sha512-+RqhBlLn6YRBGOIoVYthsG0J9dfpO79eJyN7BYBkZJtfqrBwf2KK+rD/M/yjZR6WBmIhAgOV7S60eCgaSWtbFw== + +"@nodelib/fs.walk@^1.2.1": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.2.tgz#6a6450c5e17012abd81450eb74949a4d970d2807" + integrity sha512-J/DR3+W12uCzAJkw7niXDcqcKBg6+5G5Q/ZpThpGNzAUz70eOR6RV4XnnSN01qHZiVl0eavoxJsBypQoKsV2QQ== + dependencies: + "@nodelib/fs.scandir" "2.1.1" + fastq "^1.6.0" + +"@octokit/endpoint@^5.1.0": + version "5.3.2" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-5.3.2.tgz#2deda2d869cac9ba7f370287d55667be2a808d4b" + integrity sha512-gRjteEM9I6f4D8vtwU2iGUTn9RX/AJ0SVXiqBUEuYEWVGGAVjSXdT0oNmghH5lvQNWs8mwt6ZaultuG6yXivNw== + dependencies: + deepmerge "4.0.0" + is-plain-object "^3.0.0" + universal-user-agent "^3.0.0" + url-template "^2.0.8" + +"@octokit/request-error@^1.0.1", "@octokit/request-error@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.0.4.tgz#15e1dc22123ba4a9a4391914d80ec1e5303a23be" + integrity sha512-L4JaJDXn8SGT+5G0uX79rZLv0MNJmfGa4vb4vy1NnpjSnWDLJRy6m90udGwvMmavwsStgbv2QNkPzzTCMmL+ig== + dependencies: + deprecation "^2.0.0" + once "^1.4.0" + +"@octokit/request@^5.0.0": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.0.2.tgz#59a920451f24811c016ddc507adcc41aafb2dca5" + integrity sha512-z1BQr43g4kOL4ZrIVBMHwi68Yg9VbkRUyuAgqCp1rU3vbYa69+2gIld/+gHclw15bJWQnhqqyEb7h5a5EqgZ0A== + dependencies: + "@octokit/endpoint" "^5.1.0" + "@octokit/request-error" "^1.0.1" + deprecation "^2.0.0" + is-plain-object "^3.0.0" + node-fetch "^2.3.0" + once "^1.4.0" + universal-user-agent "^3.0.0" + +"@octokit/rest@^16.27.0": + version "16.28.7" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.28.7.tgz#a2c2db5b318da84144beba82d19c1a9dbdb1a1fa" + integrity sha512-cznFSLEhh22XD3XeqJw51OLSfyL2fcFKUO+v2Ep9MTAFfFLS1cK1Zwd1yEgQJmJoDnj4/vv3+fGGZweG+xsbIA== + dependencies: + "@octokit/request" "^5.0.0" + "@octokit/request-error" "^1.0.2" + atob-lite "^2.0.0" + before-after-hook "^2.0.0" + btoa-lite "^1.0.0" + deprecation "^2.0.0" + lodash.get "^4.4.2" + lodash.set "^4.3.2" + lodash.uniq "^4.5.0" + octokit-pagination-methods "^1.1.0" + once "^1.4.0" + universal-user-agent "^3.0.0" + url-template "^2.0.8" + +"@semantic-release/commit-analyzer@^6.1.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@semantic-release/commit-analyzer/-/commit-analyzer-6.3.0.tgz#e0fb2f6af7be2321ad9401d8ae25be0cc1005d83" + integrity sha512-sh51MVlV8VyrvGIemcvzueDADX/8qGbAgce1F0CtQv8hNKYyhdaJeHzfiM1rNXwCynDmcQj+Yq9rrWt71tBd/Q== + dependencies: + conventional-changelog-angular "^5.0.0" + conventional-commits-filter "^2.0.0" + conventional-commits-parser "^3.0.0" + debug "^4.0.0" + import-from "^3.0.0" + lodash "^4.17.4" + +"@semantic-release/error@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@semantic-release/error/-/error-2.2.0.tgz#ee9d5a09c9969eade1ec864776aeda5c5cddbbf0" + integrity sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg== + +"@semantic-release/github@^5.1.0": + version "5.4.2" + resolved "https://registry.yarnpkg.com/@semantic-release/github/-/github-5.4.2.tgz#1dbde876228c03ff9a000893a18aff5c6ab2cd61" + integrity sha512-8gkOa5tED/+sjAPwZRYsLaGr6VuAGLZinSvLsuF9/l4qLeYV8gvj7fhjFJepGu6y31t7PR2J9SWzmsqsBAyyKQ== + dependencies: + "@octokit/rest" "^16.27.0" + "@semantic-release/error" "^2.2.0" + aggregate-error "^3.0.0" + bottleneck "^2.18.1" + debug "^4.0.0" + dir-glob "^3.0.0" + fs-extra "^8.0.0" + globby "^10.0.0" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.1" + issue-parser "^4.0.0" + lodash "^4.17.4" + mime "^2.4.3" + p-filter "^2.0.0" + p-retry "^4.0.0" + parse-github-url "^1.0.1" + url-join "^4.0.0" + +"@semantic-release/npm@^5.0.5": + version "5.1.13" + resolved "https://registry.yarnpkg.com/@semantic-release/npm/-/npm-5.1.13.tgz#7b06d62b4d9c8336ae5a5c85eede26fb89f19e3b" + integrity sha512-pONvpoEtGH1nd6Wj3SryACNJ/YXXsvSSekE9Pdk6mnaRv7lGhXdaeJJr6Lr4L8WK98oZv4aJOr68vTac2Oc+dA== + dependencies: + "@semantic-release/error" "^2.2.0" + aggregate-error "^3.0.0" + execa "^1.0.0" + fs-extra "^8.0.0" + lodash "^4.17.4" + nerf-dart "^1.0.0" + normalize-url "^4.0.0" + npm "^6.8.0" + rc "^1.2.8" + read-pkg "^5.0.0" + registry-auth-token "^4.0.0" + +"@semantic-release/release-notes-generator@^7.1.2": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@semantic-release/release-notes-generator/-/release-notes-generator-7.3.0.tgz#b94f3d84d7071eb8e921b53a9729ca48722e7c0f" + integrity sha512-6ozBLHM9XZR6Z8PFSKssLtwBYc5l1WOnxj034F8051QOo3TMKDDPKwdj2Niyc+e7ru7tGa3Ftq7nfN0YnD6//A== + dependencies: + conventional-changelog-angular "^5.0.0" + conventional-changelog-writer "^4.0.0" + conventional-commits-filter "^2.0.0" + conventional-commits-parser "^3.0.0" + debug "^4.0.0" + get-stream "^5.0.0" + import-from "^3.0.0" + into-stream "^5.0.0" + lodash "^4.17.4" + read-pkg-up "^6.0.0" + +"@sinonjs/commons@^1", "@sinonjs/commons@^1.3.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.6.0.tgz#ec7670432ae9c8eb710400d112c201a362d83393" + integrity sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg== + dependencies: + type-detect "4.0.8" + +"@sinonjs/formatio@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-2.0.0.tgz#84db7e9eb5531df18a8c5e0bfb6e449e55e654b2" + integrity sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg== + dependencies: + samsam "1.3.0" + +"@sinonjs/formatio@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-3.2.1.tgz#52310f2f9bcbc67bdac18c94ad4901b95fde267e" + integrity sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ== + dependencies: + "@sinonjs/commons" "^1" + "@sinonjs/samsam" "^3.1.0" + +"@sinonjs/samsam@^3.1.0": + version "3.3.3" + resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-3.3.3.tgz#46682efd9967b259b81136b9f120fd54585feb4a" + integrity sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ== + dependencies: + "@sinonjs/commons" "^1.3.0" + array-from "^2.1.1" + lodash "^4.17.15" + +"@sinonjs/text-encoding@^0.7.1": + version "0.7.1" + resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" + integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== + +"@types/bigi@^1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@types/bigi/-/bigi-1.4.2.tgz#8dda60612e689e5769047568d0ce8b8fa83db953" + integrity sha512-St8Vm0x1ApYlU9yNaFx3jBis5JVU6oR/5Xtgvn8+N8Ts8f3ze6kOvAAg0aNkbGMGhhG6PrP0nMOgDI9NMFETkA== + +"@types/bip39@^2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@types/bip39/-/bip39-2.4.2.tgz#f5d6617212be496bb998d3969f657f77a10c5287" + integrity sha512-Vo9lqOIRq8uoIzEVrV87ZvcIM0PN9t0K3oYZ/CS61fIYKCBdOIM7mlWzXuRvSXrDtVa1uUO2w1cdfufxTC0bzg== + dependencies: + "@types/node" "*" + +"@types/chai@^4.1.7": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.0.tgz#2478260021408dec32c123a7cad3414beb811a07" + integrity sha512-zw8UvoBEImn392tLjxoavuonblX/4Yb9ha4KBU10FirCfwgzhKO0dvyJSF9ByxV1xK1r2AgnAi/tvQaLgxQqxA== + +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + +"@types/events@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== + +"@types/glob@^7.1.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" + integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== + dependencies: + "@types/events" "*" + "@types/minimatch" "*" + "@types/node" "*" + +"@types/minimatch@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== + +"@types/mocha@^5.2.6": + version "5.2.7" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" + integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== + +"@types/node@*": + version "12.7.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.2.tgz#c4e63af5e8823ce9cc3f0b34f7b998c2171f0c44" + integrity sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg== + +"@types/node@^10.11.7": + version "10.14.16" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.16.tgz#4d690c96cbb7b2728afea0e260d680501b3da5cf" + integrity sha512-/opXIbfn0P+VLt+N8DE4l8Mn8rbhiJgabU96ZJ0p9mxOkIks5gh6RUnpHak7Yh0SFkyjO/ODbxsQQPV2bpMmyA== + +"@types/normalize-package-data@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" + integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/randombytes@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/randombytes/-/randombytes-2.0.0.tgz#0087ff5e60ae68023b9bc4398b406fea7ad18304" + integrity sha512-bz8PhAVlwN72vqefzxa14DKNT8jK/mV66CSjwdVQM/k3Th3EPKfUtdMniwZgMedQTFuywAsfjnZsg+pEnltaMA== + dependencies: + "@types/node" "*" + +"@types/retry@^0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== + +"@types/sinon@^7.0.11": + version "7.0.13" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-7.0.13.tgz#ca039c23a9e27ebea53e0901ef928ea2a1a6d313" + integrity sha512-d7c/C/+H/knZ3L8/cxhicHUiTDxdgap0b/aNJfsmLwFu/iOP17mdgbQsbHA3SJmrzsjD0l3UEE5SN4xxuz5ung== + +"@types/socket.io-client@^1.4.32": + version "1.4.32" + resolved "https://registry.yarnpkg.com/@types/socket.io-client/-/socket.io-client-1.4.32.tgz#988a65a0386c274b1c22a55377fab6a30789ac14" + integrity sha512-Vs55Kq8F+OWvy1RLA31rT+cAyemzgm0EWNeax6BWF8H7QiiOYMJIdcwSDdm5LVgfEkoepsWkS+40+WNb7BUMbg== + +"@types/socket.io@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@types/socket.io/-/socket.io-2.1.2.tgz#7165c2587cc3b86b44aa78e2a0060140551de211" + integrity sha512-Ind+4qMNfQ62llyB4IMs1D8znMEBsMKohZBPqfBUIXqLQ9bdtWIbNTBWwtdcBWJKnokMZGcmWOOKslatni5vtA== + dependencies: + "@types/node" "*" + +"@types/wif@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/wif/-/wif-2.0.1.tgz#bcab48b201403cb759cd7659aff4610cfd4888f4" + integrity sha512-FQKvE4EncC8C4qxW9y0psAOs2XVkxSAGIofB8tqNDPSeOsR4OueEf9TED3PHf8xlOquI+m++AXTWjJIS07FNHw== + dependencies: + "@types/node" "*" + +JSONStream@^1.0.4, JSONStream@^1.3.4, JSONStream@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abbrev@1, abbrev@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@^1.3.7, accepts@~1.3.4: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + integrity sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s= + dependencies: + acorn "^3.0.4" + +acorn-jsx@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.2.tgz#84b68ea44b373c4f8686023a551f61a21b7c4a4f" + integrity sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw== + +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + integrity sha1-ReN/s56No/JbruP/U2niu18iAXo= + +acorn@^5.5.0: + version "5.7.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" + integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== + +acorn@^6.0.7: + version "6.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e" + integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA== + +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= + +agent-base@4, agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + +agent-base@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== + dependencies: + es6-promisify "^5.0.0" + +agentkeepalive@^3.4.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz#a113924dd3fa24a0bc3b78108c450c2abee00f67" + integrity sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ== + dependencies: + humanize-ms "^1.2.1" + +aggregate-error@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.0.tgz#5b5a3c95e9095f311c9ab16c19fb4f3527cd3f79" + integrity sha512-yKD9kEoJIR+2IFqhMwayIBgheLYbB3PS2OBhWae1L/ODTd/JF/30cW0bc9TqzRL3k4U41Dieu3BF4I29p8xesA== + dependencies: + clean-stack "^2.0.0" + indent-string "^3.2.0" + +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" + integrity sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I= + +ajv@^5.2.3, ajv@^5.3.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +ajv@^6.10.2, ajv@^6.5.5, ajv@^6.9.1: + version "6.10.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" + integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-align@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" + integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38= + dependencies: + string-width "^2.0.0" + +ansi-escapes@^3.0.0, ansi-escapes@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-escapes@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.2.1.tgz#4dccdb846c3eee10f6d64dea66273eab90c37228" + integrity sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q== + dependencies: + type-fest "^0.5.2" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.0.tgz#5681f0dcf7ae5880a7841d8831c4724ed9cc0172" + integrity sha512-7kFQgnEaMdRtwf6uSfUnVr9gSGC7faurn+J/Mv90/W+iTtN0405/nLdopfMWwchyxhbGYl6TC4Sccn9TUkGAgg== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + +ansicolors@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk= + +ansistyles@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" + integrity sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk= + +append-transform@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" + integrity sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw== + dependencies: + default-require-extensions "^2.0.0" + +aproba@^1.0.3, aproba@^1.1.1, aproba@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +"aproba@^1.1.2 || 2", aproba@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +archy@^1.0.0, archy@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +arg@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.1.tgz#485f8e7c390ce4c5f78257dbea80d4be11feda4c" + integrity sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argv-formatter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/argv-formatter/-/argv-formatter-1.0.0.tgz#a0ca0cbc29a5b73e836eebe1cbf6c5e0e4eb82f9" + integrity sha1-oMoMvCmltz6Dbuvhy/bF4OTrgvk= + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= + +array-from@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/array-from/-/array-from-2.1.1.tgz#cfe9d8c26628b9dc5aecc62a9f5d8f1f352c1195" + integrity sha1-z+nYwmYoudxa7MYqn12PHzUsEZU= + +array-ify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" + integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= + +array-includes@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" + integrity sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.7.0" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array-uniq@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-2.1.0.tgz#46603d5e28e79bfd02b046fcc1d77c6820bd8e98" + integrity sha512-bdHxtev7FN6+MXI1YFW0Q8mQ8dTJc2S8AMfju+ZR77pbg2yAdVyDlwkaUI7Har0LyOMRFPHrJ9lYdyjZZswdlQ== + +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== + +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + +asap@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert@^1.4.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== + dependencies: + object-assign "^4.1.1" + util "0.10.3" + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob-lite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/atob-lite/-/atob-lite-2.0.0.tgz#0fef5ad46f1bd7a8502c65727f0367d5ee43d696" + integrity sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY= + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + +axios@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8" + integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ== + dependencies: + follow-redirects "1.5.10" + is-buffer "^2.0.2" + +babel-code-frame@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base-x@^3.0.2: + version "3.0.6" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.6.tgz#de047ec95f5f7b99ae63d830a2a894c96538b2cd" + integrity sha512-4PaF8u2+AlViJxRVjurkLTxpp7CaFRD/jo5rPT9ONnKxyhQ8f59yzamEvq7EkriG56yn5On4ONyaG75HLqr46w== + dependencies: + safe-buffer "^5.0.1" + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= + +base64id@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY= + +bc-bip68@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/bc-bip68/-/bc-bip68-1.0.5.tgz#4d3774067d8c9e922e225f5f2c4178ee9ae8dc94" + integrity sha512-GzaMlN7pNthrY5BhReVhnfr4Ixx+GUSfyNRHYh0QiMUF0d0+0YaD8MpEdv6AjFBksg/zlqL1fVCBBm6PpTt2Rg== + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +bech32@^1.1.2, bech32@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.3.tgz#bd47a8986bbb3eec34a56a097a84b8d3e9a2dfcd" + integrity sha512-yuVFUvrNcoJi0sv5phmqc6P+Fl1HjRDRNOOkHY2X/3LBy2bIGNSFx4fZ95HMaXHupuS7cZR15AsvtmCIF4UEyg== + +before-after-hook@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" + integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A== + +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= + dependencies: + callsite "1.0.0" + +big-integer@^1.6.34: + version "1.6.44" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.44.tgz#4ee9ae5f5839fc11ade338fea216b4513454a539" + integrity sha512-7MzElZPTyJ2fNvBkPxtFQ2fWIkVmuzw41+BZHSzpEq3ymB2MfeKp1+yXl/tS75xCx+WnyV+yb0kp+K1C3UNwmQ== + +big.js@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" + integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== + +bigi@^1.1.0, bigi@^1.2.0, bigi@^1.4.0, bigi@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/bigi/-/bigi-1.4.2.tgz#9c665a95f88b8b08fc05cfd731f561859d725825" + integrity sha1-nGZalfiLiwj8Bc/XMfVhhZ1yWCU= + +bin-links@^1.1.2, bin-links@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-1.1.3.tgz#702fd59552703727313bc624bdbc4c0d3431c2ca" + integrity sha512-TEwmH4PHU/D009stP+fkkazMJgkBNCv60z01lQ/Mn8E6+ThHoD03svMnBVuCowwXo2nP2qKyKZxKxp58OHRzxw== + dependencies: + bluebird "^3.5.3" + cmd-shim "^3.0.0" + gentle-fs "^2.0.1" + graceful-fs "^4.1.15" + write-file-atomic "^2.3.0" + +bindings@^1.2.1, bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bip-schnorr@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/bip-schnorr/-/bip-schnorr-0.3.0.tgz#e6490379603704e9dd123d874b41755aea4f352c" + integrity sha512-Sc1Hn2+1n+okPEW8G+JLjeaM12dsUOwr+oFlMDSKR9wYwNGMw0alskeBIHTmXxBxMZSWKhCW7PwKQVDyGmnaVg== + dependencies: + ecurve "^1.0.6" + js-sha256 "^0.9.0" + random-bytes "^1.0.0" + safe-buffer "^5.0.1" + +bip21@Bitcoin-com/bip21: + version "2.0.1" + resolved "https://codeload.github.com/Bitcoin-com/bip21/tar.gz/28f8d03a3a16ed11eb5b963248ed1be8c46c6d6f" + dependencies: + qs "^6.3.0" + +bip32-utils@Bitcoin-com/bip32-utils#0.13.1: + version "0.13.1" + resolved "https://codeload.github.com/Bitcoin-com/bip32-utils/tar.gz/b8a33ebd0a0ac39de7cd987e5c3f77a8c5d84e58" + dependencies: + keccak "^1.3.0" + nyc "*" + standard "^11.0.1" + tape "*" + +bip38@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/bip38/-/bip38-2.0.3.tgz#12e48749d6c28dd14e8bcb37a9f2dae67a797da0" + integrity sha512-HiABhYNhhRNAAeGmkt3LS2El6oonIftNkHq6uFxHCjaCIEbHr7I6RIBhKMQWw5AhGzIPpO5Mt7I8bFOfKqqh9w== + dependencies: + bigi "^1.2.0" + browserify-aes "^1.0.1" + bs58check "<3.0.0" + buffer-xor "^1.0.2" + create-hash "^1.1.1" + ecurve "^1.0.0" + scryptsy "^2.0.0" + +bip39@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/bip39/-/bip39-2.6.0.tgz#9e3a720b42ec8b3fbe4038f1e445317b6a99321c" + integrity sha512-RrnQRG2EgEoqO24ea+Q/fftuPUZLmrEM3qNhhGsA3PbaXaCW791LTzPuVyx/VprXQcTbPJ3K3UeTna8ZnVl2sg== + dependencies: + create-hash "^1.1.0" + pbkdf2 "^3.0.9" + randombytes "^2.0.1" + safe-buffer "^5.0.1" + unorm "^1.3.3" + +bip66@^1.1.0, bip66@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/bip66/-/bip66-1.1.5.tgz#01fa8748785ca70955d5011217d1b3139969ca22" + integrity sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI= + dependencies: + safe-buffer "^5.0.1" + +bitcoincash-ops@Bitcoin-com/bitcoincash-ops#2.0.0, "bitcoincash-ops@github:Bitcoin-com/bitcoincash-ops#2.0.0": + version "2.0.0" + resolved "https://codeload.github.com/Bitcoin-com/bitcoincash-ops/tar.gz/6ab82cc7326c67236f3b2d9d0457258ac2ef48e3" + +bitcoinjs-message@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/bitcoinjs-message/-/bitcoinjs-message-2.1.0.tgz#5fe36a7d92473bdc929d9183416970bbef1690ad" + integrity sha512-xVL2YvyAJUI8ZwfNpi6Ju5zda3+QYGHTLUvISDb0VHWbsWn9Zyvd1o8XHRC/0r+DNwDIwenpXDSPl1XLCMGnMA== + dependencies: + bech32 "^1.1.3" + bs58check "^2.1.2" + buffer-equals "^1.0.3" + create-hash "^1.1.2" + secp256k1 "^3.0.1" + varuint-bitcoin "^1.0.1" + +blob@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== + +bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5: + version "3.5.5" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" + integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== + +bn.js@^4.11.8, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + +bottleneck@^2.18.1: + version "2.19.5" + resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91" + integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw== + +boxen@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" + integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw== + dependencies: + ansi-align "^2.0.0" + camelcase "^4.0.0" + chalk "^2.0.1" + cli-boxes "^1.0.0" + string-width "^2.0.0" + term-size "^1.2.0" + widest-line "^2.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserify-aes@^1.0.1, browserify-aes@^1.0.6: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +bs58@^4.0.0, bs58@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha1-vhYedsNU9veIrkBx9j806MTwpCo= + dependencies: + base-x "^3.0.2" + +bs58check@<3.0.0, bs58check@^2.0.0, bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + +btoa-lite@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" + integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc= + +buffer-equals@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/buffer-equals/-/buffer-equals-1.0.4.tgz#0353b54fd07fd9564170671ae6f66b9cf10d27f5" + integrity sha1-A1O1T9B/2VZBcGca5vZrnPENJ/U= + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-xor@^1.0.2, buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +builtin-modules@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= + +builtins@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= + +byline@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" + integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE= + +byte-size@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-5.0.1.tgz#4b651039a5ecd96767e71a3d7ed380e48bed4191" + integrity sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw== + +cacache@^12.0.0, cacache@^12.0.2, cacache@^12.0.3: + version "12.0.3" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" + integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== + dependencies: + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + infer-owner "^1.0.3" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +caching-transform@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-3.0.2.tgz#601d46b91eca87687a281e71cef99791b0efca70" + integrity sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w== + dependencies: + hasha "^3.0.0" + make-dir "^2.0.0" + package-hash "^3.0.0" + write-file-atomic "^2.4.2" + +call-limit@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/call-limit/-/call-limit-1.1.1.tgz#ef15f2670db3f1992557e2d965abc459e6e358d4" + integrity sha512-5twvci5b9eRBw2wCfPtN0GmlR2/gadZqyFpPhOK6CvMFoFgA+USnZ6Jpu1lhG9h85pQ3Ouil3PfXWRD4EUaRiQ== + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8= + dependencies: + callsites "^0.2.0" + +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase-keys@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77" + integrity sha1-oqpfsa9oh1glnDLBQUJteJI7m3c= + dependencies: + camelcase "^4.1.0" + map-obj "^2.0.0" + quick-lru "^1.0.0" + +camelcase@^4.0.0, camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +capture-stack-trace@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d" + integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw== + +cardinal@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-2.1.1.tgz#7cc1055d822d212954d07b085dea251cc7bc5505" + integrity sha1-fMEFXYItISlU0HsIXeolHMe8VQU= + dependencies: + ansicolors "~0.3.2" + redeyed "~2.1.0" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +cashaddrjs@^0.2.9: + version "0.2.9" + resolved "https://registry.yarnpkg.com/cashaddrjs/-/cashaddrjs-0.2.9.tgz#e38e323e11e0ab761767006b3938a36278dadec9" + integrity sha512-DhJF4iAH0/RM3UjHDHKRxzs09YGL9px+oTyizzydanhC7jTyM2aJ+aLKA96vZGTTWayvvr2iDF2l13lpqXiRFg== + dependencies: + big-integer "^1.6.34" + +chai@^4.1.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" + integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.2" + deep-eql "^3.0.1" + get-func-name "^2.0.0" + pathval "^1.1.0" + type-detect "^4.0.5" + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chardet@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +check-error@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= + +chownr@^1.1.1, chownr@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6" + integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A== + +ci-info@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" + integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cidr-regex@^2.0.10: + version "2.0.10" + resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-2.0.10.tgz#af13878bd4ad704de77d6dc800799358b3afa70d" + integrity sha512-sB3ogMQXWvreNPbJUZMRApxuRYd+KoIo4RGQ81VatjmMW6WJPo+IJZ2846FGItr9VzKo5w7DXzijPLGtSd0N3Q== + dependencies: + ip-regex "^2.1.0" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +circular-json@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-boxes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" + integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= + +cli-columns@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cli-columns/-/cli-columns-3.1.2.tgz#6732d972979efc2ae444a1f08e08fa139c96a18e" + integrity sha1-ZzLZcpee/CrkRKHwjgj6E5yWoY4= + dependencies: + string-width "^2.0.0" + strip-ansi "^3.0.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + dependencies: + restore-cursor "^2.0.0" + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-table3@^0.5.0, cli-table3@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" + integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== + dependencies: + object-assign "^4.1.0" + string-width "^2.1.1" + optionalDependencies: + colors "^1.1.2" + +cli-table@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM= + dependencies: + colors "1.0.3" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +cmd-shim@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-3.0.1.tgz#7b34dfbd503898b9953928a9eed1ef251fe19f88" + integrity sha512-C5t8o5glT2rDJkfRXZXweu5+obqcCjA5OSKSFQeYBDGZo+crirMh35Uhm9Lmb1wRSinKBXOFsCN7XNyLGTve8A== + dependencies: + graceful-fs "^4.1.2" + mkdirp "~0.5.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +coininfo@Bitcoin-com/coininfo: + version "4.0.0" + resolved "https://codeload.github.com/Bitcoin-com/coininfo/tar.gz/eece2c6141d08c3e7783929f2a1e1e681aa1a82c" + dependencies: + safe-buffer "^5.1.1" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= + +colors@^1.1.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" + integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== + +columnify@~1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" + integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs= + dependencies: + strip-ansi "^3.0.0" + wcwidth "^1.0.0" + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@2.15.1: + version "2.15.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" + integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== + +commander@~2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +compare-func@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-1.3.2.tgz#99dd0ba457e1f9bc722b12c08ec33eeab31fa648" + integrity sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg= + dependencies: + array-ify "^1.0.0" + dot-prop "^3.0.0" + +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= + +component-emitter@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.0, concat-stream@^1.6.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +config-chain@^1.1.12: + version "1.1.12" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" + integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +configstore@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" + integrity sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw== + dependencies: + dot-prop "^4.1.0" + graceful-fs "^4.1.2" + make-dir "^1.0.0" + unique-string "^1.0.0" + write-file-atomic "^2.0.0" + xdg-basedir "^3.0.0" + +console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= + +conventional-changelog-angular@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.3.tgz#299fdd43df5a1f095283ac16aeedfb0a682ecab0" + integrity sha512-YD1xzH7r9yXQte/HF9JBuEDfvjxxwDGGwZU1+ndanbY0oFgA+Po1T9JDSpPLdP0pZT6MhCAsdvFKC4TJ4MTJTA== + dependencies: + compare-func "^1.3.1" + q "^1.5.1" + +conventional-changelog-writer@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.0.7.tgz#e4b7d9cbea902394ad671f67108a71fa90c7095f" + integrity sha512-p/wzs9eYaxhFbrmX/mCJNwJuvvHR+j4Fd0SQa2xyAhYed6KBiZ780LvoqUUvsayP4R1DtC27czalGUhKV2oabw== + dependencies: + compare-func "^1.3.1" + conventional-commits-filter "^2.0.2" + dateformat "^3.0.0" + handlebars "^4.1.2" + json-stringify-safe "^5.0.1" + lodash "^4.2.1" + meow "^4.0.0" + semver "^6.0.0" + split "^1.0.0" + through2 "^3.0.0" + +conventional-commits-filter@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.1.tgz#55a135de1802f6510b6758e0a6aa9e0b28618db3" + integrity sha512-92OU8pz/977udhBjgPEbg3sbYzIxMDFTlQT97w7KdhR9igNqdJvy8smmedAAgn4tPiqseFloKkrVfbXCVd+E7A== + dependencies: + is-subset "^0.1.1" + modify-values "^1.0.0" + +conventional-commits-filter@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.2.tgz#f122f89fbcd5bb81e2af2fcac0254d062d1039c1" + integrity sha512-WpGKsMeXfs21m1zIw4s9H5sys2+9JccTzpN6toXtxhpw2VNF2JUXwIakthKBy+LN4DvJm+TzWhxOMWOs1OFCFQ== + dependencies: + lodash.ismatch "^4.4.0" + modify-values "^1.0.0" + +conventional-commits-parser@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.0.1.tgz#fe1c49753df3f98edb2285a5e485e11ffa7f2e4c" + integrity sha512-P6U5UOvDeidUJ8ebHVDIoXzI7gMlQ1OF/id6oUvp8cnZvOXMt1n8nYl74Ey9YMn0uVQtxmCtjPQawpsssBWtGg== + dependencies: + JSONStream "^1.0.4" + is-text-path "^1.0.0" + lodash "^4.2.1" + meow "^4.0.0" + split2 "^2.0.0" + through2 "^2.0.0" + trim-off-newlines "^1.0.0" + +convert-source-map@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" + integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== + dependencies: + safe-buffer "~5.1.1" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + +coveralls@^3.0.2: + version "3.0.6" + resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.0.6.tgz#5c63b2759b6781118e7439bd870ba5e9ee428b25" + integrity sha512-Pgh4v3gCI4T/9VijVrm8Ym5v0OgjvGLKj3zTUwkvsCiwqae/p6VLzpsFNjQS2i6ewV7ef+DjFJ5TSKxYt/mCrA== + dependencies: + growl "~> 1.10.0" + js-yaml "^3.13.1" + lcov-parse "^0.0.10" + log-driver "^1.2.7" + minimist "^1.2.0" + request "^2.86.0" + +cp-file@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-6.2.0.tgz#40d5ea4a1def2a9acdd07ba5c0b0246ef73dc10d" + integrity sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA== + dependencies: + graceful-fs "^4.1.2" + make-dir "^2.0.0" + nested-error-stacks "^2.0.0" + pify "^4.0.1" + safe-buffer "^5.0.1" + +create-error-class@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y= + dependencies: + capture-stack-trace "^1.0.0" + +create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.3, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^4: + version "4.0.2" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41" + integrity sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE= + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cross-spawn@^5.0.1, cross-spawn@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" + integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= + dependencies: + array-find-index "^1.0.1" + +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +dateformat@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" + integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== + +debug-log@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" + integrity sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8= + +debug@3.1.0, debug@=3.1.0, debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +debuglog@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= + +decamelize-keys@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" + integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= + dependencies: + decamelize "^1.1.0" + map-obj "^1.0.0" + +decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-eql@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== + dependencies: + type-detect "^4.0.0" + +deep-equal@^1.0.0, deep-equal@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +deepmerge@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.0.0.tgz#3e3110ca29205f120d7cb064960a39c3d2087c09" + integrity sha512-YZ1rOP5+kHor4hMAH+HRQnBQHg+wvS1un1hAOuIcxcBy0hzcUf6Jg2a1w65kpoOUnurOfZbERwjI1TfZxNjcww== + +default-require-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" + integrity sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc= + dependencies: + strip-bom "^3.0.0" + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + +define-properties@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +defined@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= + +deglob@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/deglob/-/deglob-2.1.1.tgz#d268e168727799862e8eac07042e165957c1f3be" + integrity sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw== + dependencies: + find-root "^1.0.0" + glob "^7.0.5" + ignore "^3.0.9" + pkg-config "^1.1.0" + run-parallel "^1.1.2" + uniq "^1.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +deprecation@^2.0.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" + integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== + +detect-indent@~5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" + integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= + +detect-newline@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= + +dezalgo@^1.0.0, dezalgo@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= + dependencies: + asap "^2.0.0" + wrappy "1" + +diff@3.5.0, diff@^3.1.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + +diff@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff" + integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q== + +dir-glob@^3.0.0, dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^2.0.2, doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dot-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" + integrity sha1-G3CK8JSknJoOfbyteQq6U52sEXc= + dependencies: + is-obj "^1.0.0" + +dot-prop@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== + dependencies: + is-obj "^1.0.0" + +dotenv@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" + integrity sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow== + +drbg.js@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/drbg.js/-/drbg.js-1.0.1.tgz#3e36b6c42b37043823cdbc332d58f31e2445480b" + integrity sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs= + dependencies: + browserify-aes "^1.0.6" + create-hash "^1.1.2" + create-hmac "^1.1.4" + +duplexer2@~0.1.0: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME= + dependencies: + readable-stream "^2.0.2" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ecurve@^1.0.0, ecurve@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/ecurve/-/ecurve-1.0.6.tgz#dfdabbb7149f8d8b78816be5a7d5b83fcf6de797" + integrity sha512-/BzEjNfiSuB7jIWKcS/z8FK9jNjmEWvUV2YZ4RLSmcDtP7Lq0m6FvDuSnJpBlDpGRpfRQeTLGLBI8H+kEv0r+w== + dependencies: + bigi "^1.1.0" + safe-buffer "^5.0.1" + +editor@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" + integrity sha1-YMf4e9YrzGqJT6jM1q+3gjok90I= + +elliptic@^6.4.1: + version "6.5.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.0.tgz#2b8ed4c891b7de3200e14412a5b8248c7af505ca" + integrity sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg== + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= + dependencies: + iconv-lite "~0.4.13" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== + dependencies: + once "^1.4.0" + +engine.io-client@~3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.3.2.tgz#04e068798d75beda14375a264bb3d742d7bc33aa" + integrity sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ== + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.1.1" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~6.1.0" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" + integrity sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA== + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.5" + has-binary2 "~1.0.2" + +engine.io@~3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.3.2.tgz#18cbc8b6f36e9461c5c0f81df2b830de16058a59" + integrity sha512-AsaA9KG7cWPXWHp5FvHdDWY3AMWeZ8x+2pUVLcn71qE5AtAzgGbxuclOytygskw8XGmiQafTmnI9Bix3uihu2w== + dependencies: + accepts "~1.3.4" + base64id "1.0.0" + cookie "0.3.1" + debug "~3.1.0" + engine.io-parser "~2.1.0" + ws "~6.1.0" + +env-ci@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/env-ci/-/env-ci-4.1.1.tgz#b8438fc7258a0dc7a4f4c4816de730767946a718" + integrity sha512-eTgpkALDeYRGNhYM2fO9LKsWDifoUgKL7hxpPZqFMP2IU7f+r89DtKqCmk3yQB/jxS8CmZTfKnWO5TiIDFs9Hw== + dependencies: + execa "^1.0.0" + java-properties "^1.0.0" + +env-paths@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-1.0.0.tgz#4168133b42bb05c38a35b1ae4397c8298ab369e0" + integrity sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA= + +err-code@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" + integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= + +errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.5.0, es-abstract@^1.5.1, es-abstract@^1.7.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" + integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== + dependencies: + es-to-primitive "^1.2.0" + function-bind "^1.1.1" + has "^1.0.3" + is-callable "^1.1.4" + is-regex "^1.0.4" + object-keys "^1.0.12" + +es-to-primitive@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" + integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es6-error@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" + integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== + +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +eslint-config-prettier@^3.0.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-3.6.0.tgz#8ca3ffac4bd6eeef623a0651f9d754900e3ec217" + integrity sha512-ixJ4U3uTLXwJts4rmSVW/lMXjlGwCijhBJHk8iVqKKSifeI0qgFEfWl8L63isfc8Od7EiBALF6BX3jKLluf/jQ== + dependencies: + get-stdin "^6.0.0" + +eslint-config-standard-jsx@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-5.0.0.tgz#4abfac554f38668e0078c664569e7b2384e5d2aa" + integrity sha512-rLToPAEqLMPBfWnYTu6xRhm2OWziS2n40QFqJ8jAM8NSVzeVKTa3nclhsU4DpPJQRY60F34Oo1wi/71PN/eITg== + +eslint-config-standard@11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-11.0.0.tgz#87ee0d3c9d95382dc761958cbb23da9eea31e0ba" + integrity sha512-oDdENzpViEe5fwuRCWla7AXQd++/oyIp8zP+iP9jiUPG6NBj3SHgdgtl/kTn00AjeN+1HNvavTKmYbMo+xMOlw== + +eslint-import-resolver-node@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" + integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q== + dependencies: + debug "^2.6.9" + resolve "^1.5.0" + +eslint-module-utils@^2.1.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz#7b4675875bf96b0dbf1b21977456e5bb1f5e018c" + integrity sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw== + dependencies: + debug "^2.6.8" + pkg-dir "^2.0.0" + +eslint-plugin-es@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-1.4.0.tgz#475f65bb20c993fc10e8c8fe77d1d60068072da6" + integrity sha512-XfFmgFdIUDgvaRAlaXUkxrRg5JSADoRC8IkKLc/cISeR3yHVMefFHQZpcyXXEUUPHfy5DwviBcrfqlyqEwlQVw== + dependencies: + eslint-utils "^1.3.0" + regexpp "^2.0.1" + +eslint-plugin-import@~2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.9.0.tgz#26002efbfca5989b7288ac047508bd24f217b169" + integrity sha1-JgAu+/ylmJtyiKwEdQi9JPIXsWk= + dependencies: + builtin-modules "^1.1.1" + contains-path "^0.1.0" + debug "^2.6.8" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.1" + eslint-module-utils "^2.1.1" + has "^1.0.1" + lodash "^4.17.4" + minimatch "^3.0.3" + read-pkg-up "^2.0.0" + +eslint-plugin-node@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-7.0.1.tgz#a6e054e50199b2edd85518b89b4e7b323c9f36db" + integrity sha512-lfVw3TEqThwq0j2Ba/Ckn2ABdwmL5dkOgAux1rvOk6CO7A6yGyPI2+zIxN6FyNkp1X1X/BSvKOceD6mBWSj4Yw== + dependencies: + eslint-plugin-es "^1.3.1" + eslint-utils "^1.3.1" + ignore "^4.0.2" + minimatch "^3.0.4" + resolve "^1.8.1" + semver "^5.5.0" + +eslint-plugin-node@~6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz#bf19642298064379315d7a4b2a75937376fa05e4" + integrity sha512-Q/Cc2sW1OAISDS+Ji6lZS2KV4b7ueA/WydVWd1BECTQwVvfQy5JAi3glhINoKzoMnfnuRgNP+ZWKrGAbp3QDxw== + dependencies: + ignore "^3.3.6" + minimatch "^3.0.4" + resolve "^1.3.3" + semver "^5.4.1" + +eslint-plugin-prettier@^2.6.2: + version "2.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.7.0.tgz#b4312dcf2c1d965379d7f9d5b5f8aaadc6a45904" + integrity sha512-CStQYJgALoQBw3FsBzH0VOVDRnJ/ZimUlpLm226U8qgqYJfPOY/CPK6wyRInMxh73HSKg5wyRwdS4BVYYHwokA== + dependencies: + fast-diff "^1.1.1" + jest-docblock "^21.0.0" + +eslint-plugin-promise@~3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz#f4bde5c2c77cdd69557a8f69a24d1ad3cfc9e67e" + integrity sha512-2WO+ZFh7vxUKRfR0cOIMrWgYKdR6S1AlOezw6pC52B6oYpd5WFghN+QHxvrRdZMtbo8h3dfUZ2o1rWb0UPbKtg== + +eslint-plugin-react@~7.7.0: + version "7.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz#f606c719dbd8a1a2b3d25c16299813878cca0160" + integrity sha512-KC7Snr4YsWZD5flu6A5c0AcIZidzW3Exbqp7OT67OaD2AppJtlBr/GuPrW/vaQM/yfZotEvKAdrxrO+v8vwYJA== + dependencies: + doctrine "^2.0.2" + has "^1.0.1" + jsx-ast-utils "^2.0.1" + prop-types "^15.6.0" + +eslint-plugin-standard@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz#34d0c915b45edc6f010393c7eef3823b08565cf2" + integrity sha1-NNDJFbRe3G8BA5PH7vOCOwhWXPI= + +eslint-scope@^3.7.1: + version "3.7.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" + integrity sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.3.0, eslint-utils@^1.3.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" + integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q== + dependencies: + eslint-visitor-keys "^1.0.0" + +eslint-visitor-keys@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== + +eslint@^5.16.0: + version "5.16.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" + integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.9.1" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^4.0.3" + eslint-utils "^1.3.1" + eslint-visitor-keys "^1.0.0" + espree "^5.0.1" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.7.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^6.2.2" + js-yaml "^3.13.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.11" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^5.5.1" + strip-ansi "^4.0.0" + strip-json-comments "^2.0.1" + table "^5.2.3" + text-table "^0.2.0" + +eslint@~4.18.0: + version "4.18.2" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.18.2.tgz#0f81267ad1012e7d2051e186a9004cc2267b8d45" + integrity sha512-qy4i3wODqKMYfz9LUI8N2qYDkHkoieTbiHpMrYUI/WbjhXJQr7lI4VngixTgaG+yHX+NBCv7nW4hA0ShbvaNKw== + dependencies: + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.2" + esquery "^1.0.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" + imurmurhash "^0.1.4" + inquirer "^3.0.6" + is-resolvable "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" + strip-json-comments "~2.0.1" + table "4.0.2" + text-table "~0.2.0" + +espree@^3.5.2: + version "3.5.4" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" + integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A== + dependencies: + acorn "^5.5.0" + acorn-jsx "^3.0.0" + +espree@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" + integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== + dependencies: + acorn "^6.0.7" + acorn-jsx "^5.0.0" + eslint-visitor-keys "^1.0.0" + +esprima@^4.0.0, esprima@~4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.0.0, esquery@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== + dependencies: + estraverse "^4.1.0" + +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eventsource@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" + integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== + dependencies: + original "^1.0.0" + +evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-3.3.0.tgz#7e348eef129a1937f21ecbbd53390942653522c1" + integrity sha512-j5Vit5WZR/cbHlqU97+qcnw9WHRCIL4V1SVe75VcHcD1JRBdt8fv0zw89b7CQHQdUHTt2VjuhcF5ibAgVOxqpg== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + p-finally "^2.0.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +external-editor@^2.0.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + +fast-diff@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-glob@^3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.0.4.tgz#d484a41005cb6faeb399b951fd1bd70ddaebb602" + integrity sha512-wkIbV6qg37xTJwqSsdnIphL1e+LaGz4AIQqr00mIubMaEhv1/HEmJ0uuCGZRNRUkZZmOB5mJKO0ZUTVq+SxMQg== + dependencies: + "@nodelib/fs.stat" "^2.0.1" + "@nodelib/fs.walk" "^1.2.1" + glob-parent "^5.0.0" + is-glob "^4.0.1" + merge2 "^1.2.3" + micromatch "^4.0.2" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fastq@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.6.0.tgz#4ec8a38f4ac25f21492673adb7eae9cfef47d1c2" + integrity sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA== + dependencies: + reusify "^1.0.0" + +figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +figures@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.0.0.tgz#756275c964646163cc6f9197c7a0295dbfd04de9" + integrity sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E= + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-cache-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-npm-prefix@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf" + integrity sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA== + +find-root@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-versions@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-3.1.0.tgz#10161f29cf3eb4350dec10a29bdde75bff0df32d" + integrity sha512-NCTfNiVzeE/xL+roNDffGuRbrWI6atI18lTJ22vKp7rs2OhYzMK3W1dIdO2TUndH/QMcacM4d1uWwgcZcHK69Q== + dependencies: + array-uniq "^2.1.0" + semver-regex "^2.0.0" + +flat-cache@^1.2.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.4.tgz#2c2ef77525cc2929007dfffa1dd314aa9c9dee6f" + integrity sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg== + dependencies: + circular-json "^0.3.1" + graceful-fs "^4.1.2" + rimraf "~2.6.2" + write "^0.2.1" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" + integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== + +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + +for-each@~0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +foreground-child@^1.5.6: + version "1.5.6" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-1.5.6.tgz#4fd71ad2dfde96789b980a5c0a295937cb2f5ce9" + integrity sha1-T9ca0t/elnibmApcCilZN8svXOk= + dependencies: + cross-spawn "^4" + signal-exit "^3.0.0" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +fresh@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-1.3.0.tgz#88413baaa5f9a597cfde9221d86986cd3c061dfd" + integrity sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0= + dependencies: + inherits "~2.0.1" + readable-stream "~1.1.10" + +from2@^2.1.0, from2@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-extra@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-minipass@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" + integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== + dependencies: + minipass "^2.2.1" + +fs-vacuum@^1.2.10, fs-vacuum@~1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" + integrity sha1-t2Kb7AekAxolSP35n17PHMizHjY= + dependencies: + graceful-fs "^4.1.2" + path-is-inside "^1.0.1" + rimraf "^2.5.2" + +fs-write-stream-atomic@^1.0.8, fs-write-stream-atomic@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +genfun@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" + integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA== + +gentle-fs@^2.0.1, gentle-fs@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/gentle-fs/-/gentle-fs-2.2.1.tgz#1f38df4b4ead685566257201fd526de401ebb215" + integrity sha512-e7dRgUM5fsS+7wm2oggZpgcRx6sEvJHXujPH5RzgQ1ziQY4+HuVBYsnUzJwJ+C7mjOJN27DjiFy1TaL+TNltow== + dependencies: + aproba "^1.1.2" + chownr "^1.1.2" + fs-vacuum "^1.2.10" + graceful-fs "^4.1.11" + iferr "^0.1.5" + infer-owner "^1.0.4" + mkdirp "^0.5.1" + path-is-inside "^1.0.2" + read-cmd-shim "^1.0.1" + slide "^1.1.6" + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-func-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= + +get-stdin@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" + integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^4.0.0, get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" + integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== + dependencies: + pump "^3.0.0" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +git-log-parser@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/git-log-parser/-/git-log-parser-1.2.0.tgz#2e6a4c1b13fc00028207ba795a7ac31667b9fd4a" + integrity sha1-LmpMGxP8AAKCB7p5WnrDFme5/Uo= + dependencies: + argv-formatter "~1.0.0" + spawn-error-forwarder "~1.0.0" + split2 "~1.0.0" + stream-combiner2 "~1.1.1" + through2 "~2.0.0" + traverse "~0.6.6" + +glob-parent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954" + integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg== + dependencies: + is-glob "^4.0.1" + +glob@7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" + integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= + dependencies: + ini "^1.3.4" + +globals@^11.0.1, globals@^11.1.0, globals@^11.7.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globby@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.1.tgz#4782c34cb75dd683351335c5829cc3420e606b22" + integrity sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A== + dependencies: + "@types/glob" "^7.1.1" + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.0.3" + glob "^7.1.3" + ignore "^5.1.1" + merge2 "^1.2.3" + slash "^3.0.0" + +got@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA= + dependencies: + create-error-class "^3.0.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-redirect "^1.0.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + unzip-response "^2.0.1" + url-parse-lax "^1.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02" + integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q== + +growl@1.10.5, "growl@~> 1.10.0": + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +handlebars@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67" + integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw== + dependencies: + neo-async "^2.6.0" + optimist "^0.6.1" + source-map "^0.6.1" + optionalDependencies: + uglify-js "^3.1.4" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-binary2@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== + dependencies: + isarray "2.0.1" + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= + +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= + +has-unicode@^2.0.0, has-unicode@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has@^1.0.1, has@^1.0.3, has@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hasha@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/hasha/-/hasha-3.0.0.tgz#52a32fab8569d41ca69a61ff1a214f8eb7c8bd39" + integrity sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk= + dependencies: + is-stream "^1.0.1" + +he@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hook-std@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hook-std/-/hook-std-2.0.0.tgz#ff9aafdebb6a989a354f729bb6445cf4a3a7077c" + integrity sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g== + +hosted-git-info@^2.1.4, hosted-git-info@^2.6.0, hosted-git-info@^2.8.2: + version "2.8.4" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.4.tgz#44119abaf4bc64692a16ace34700fed9c03e2546" + integrity sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ== + +hosted-git-info@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.0.tgz#dd8af49cd01e73cc8e61ba13e217a772fd4ecd2d" + integrity sha512-zYSx1cP4MLsvKtTg8DF/PI6e6FHZ3wcawcTGsrLU2TM+UfD4jmSrn2wdQT16TFbH3lO4PIdjLG0E+cuYDgFD9g== + dependencies: + lru-cache "^5.1.1" + +http-cache-semantics@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== + dependencies: + agent-base "4" + debug "3.1.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-proxy-agent@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz#271ea8e90f836ac9f119daccd39c19ff7dfb0793" + integrity sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg== + dependencies: + agent-base "^4.3.0" + debug "^3.1.0" + +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= + dependencies: + ms "^2.0.0" + +iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@~0.4.13: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +iferr@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-1.0.2.tgz#e9fde49a9da06dc4a4194c6c9ed6d08305037a6d" + integrity sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg== + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== + dependencies: + minimatch "^3.0.4" + +ignore@^3.0.9, ignore@^3.3.3, ignore@^3.3.6: + version "3.3.10" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== + +ignore@^4.0.2, ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.1: + version "5.1.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" + integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A== + +import-fresh@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118" + integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-fresh@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-3.0.0.tgz#055cfec38cd5a27d8057ca51376d7d3bf0891966" + integrity sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ== + dependencies: + resolve-from "^5.0.0" + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indent-string@^3.0.0, indent-string@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" + integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= + +infer-owner@^1.0.3, infer-owner@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + +inflight@^1.0.4, inflight@~1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +init-package-json@^1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.10.3.tgz#45ffe2f610a8ca134f2bd1db5637b235070f6cbe" + integrity sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw== + dependencies: + glob "^7.1.1" + npm-package-arg "^4.0.0 || ^5.0.0 || ^6.0.0" + promzard "^0.3.0" + read "~1.0.1" + read-package-json "1 || 2" + semver "2.x || 3.x || 4 || 5" + validate-npm-package-license "^3.0.1" + validate-npm-package-name "^3.0.0" + +inquirer@^3.0.6: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + +inquirer@^6.2.2: + version "6.5.1" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.1.tgz#8bfb7a5ac02dac6ff641ac4c5ff17da112fcdb42" + integrity sha512-uxNHBeQhRXIoHWTSNYUFhQVrHYFThIt6IVo2fFmSe8aBwdR3/w6b58hJpiL/fMukFkvGzjg+hSxFtwvVmKZmXw== + dependencies: + ansi-escapes "^4.2.1" + chalk "^2.4.2" + cli-cursor "^3.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.15" + mute-stream "0.0.8" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^4.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + +into-stream@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-5.1.0.tgz#b05f37d8fed05c06a0b43b556d74e53e5af23878" + integrity sha512-cbDhb8qlxKMxPBk/QxTtYg1DQ4CwXmadu7quG3B7nrJsgSncEreF2kwWKZFdnjc/lSNNIkFPsjI7SM0Cx/QXPw== + dependencies: + from2 "^2.3.0" + p-is-promise "^2.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-buffer@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" + integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== + +is-callable@^1.1.3, is-callable@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== + +is-ci@^1.0.10: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" + integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== + dependencies: + ci-info "^1.5.0" + +is-cidr@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-3.0.0.tgz#1acf35c9e881063cd5f696d48959b30fed3eed56" + integrity sha512-8Xnnbjsb0x462VoYiGlhEi+drY8SFwrHiSYuzc/CEwco55vkehTaxAyIjEdpi3EMvLPPJAJi9FlzP+h+03gp0Q== + dependencies: + cidr-regex "^2.0.10" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-installed-globally@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" + integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA= + dependencies: + global-dirs "^0.1.0" + is-path-inside "^1.0.0" + +is-npm@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" + integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ= + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= + dependencies: + path-is-inside "^1.0.1" + +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-object@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.0.tgz#47bfc5da1b5d50d64110806c199359482e75a928" + integrity sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg== + dependencies: + isobject "^4.0.0" + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= + +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= + dependencies: + has "^1.0.1" + +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== + +is-retry-allowed@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ= + +is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" + integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== + +is-subset@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" + integrity sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY= + +is-symbol@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" + integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== + dependencies: + has-symbols "^1.0.0" + +is-text-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" + integrity sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4= + dependencies: + text-extensions "^1.0.0" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= + +isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" + integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +issue-parser@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/issue-parser/-/issue-parser-4.0.0.tgz#397817323abbb70c7c29cea2ff62448cf83b686c" + integrity sha512-1RmmAXHl5+cqTZ9dRr861xWy0Gkc9TWTEklgjKv+nhlB1dY1NmGBV8b20jTWRL5cPGpOIXkz84kEcDBM8Nc0cw== + dependencies: + lodash.capitalize "^4.2.1" + lodash.escaperegexp "^4.1.2" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.uniqby "^4.7.0" + +istanbul-lib-coverage@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" + integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== + +istanbul-lib-hook@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz#c95695f383d4f8f60df1f04252a9550e15b5b133" + integrity sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA== + dependencies: + append-transform "^1.0.0" + +istanbul-lib-instrument@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" + integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== + dependencies: + "@babel/generator" "^7.4.0" + "@babel/parser" "^7.4.3" + "@babel/template" "^7.4.0" + "@babel/traverse" "^7.4.3" + "@babel/types" "^7.4.0" + istanbul-lib-coverage "^2.0.5" + semver "^6.0.0" + +istanbul-lib-report@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" + integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ== + dependencies: + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + supports-color "^6.1.0" + +istanbul-lib-source-maps@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" + integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + rimraf "^2.6.3" + source-map "^0.6.1" + +istanbul-reports@^2.2.4: + version "2.2.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.6.tgz#7b4f2660d82b29303a8fe6091f8ca4bf058da1af" + integrity sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA== + dependencies: + handlebars "^4.1.2" + +java-properties@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/java-properties/-/java-properties-1.0.2.tgz#ccd1fa73907438a5b5c38982269d0e771fe78211" + integrity sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ== + +jest-docblock@^21.0.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" + integrity sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw== + +js-sha256@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" + integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= + +js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.9.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +jsx-ast-utils@^2.0.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.2.1.tgz#4d4973ebf8b9d2837ee91a8208cc66f3a2776cfb" + integrity sha512-v3FxCcAf20DayI+uxnCuw795+oOIkVu6EnJ1+kSzhqqTZHNkTZ7B66ZgLp4oLJ/gbA64cI0B7WRoHZMSRdyVRQ== + dependencies: + array-includes "^3.0.3" + object.assign "^4.1.0" + +just-extend@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.0.2.tgz#f3f47f7dfca0f989c55410a7ebc8854b07108afc" + integrity sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw== + +keccak@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-1.4.0.tgz#572f8a6dbee8e7b3aa421550f9e6408ca2186f80" + integrity sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw== + dependencies: + bindings "^1.2.1" + inherits "^2.0.3" + nan "^2.2.1" + safe-buffer "^5.1.0" + +latest-version@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" + integrity sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU= + dependencies: + package-json "^4.0.0" + +lazy-property@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lazy-property/-/lazy-property-1.0.0.tgz#84ddc4b370679ba8bd4cdcfa4c06b43d57111147" + integrity sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc= + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + dependencies: + invert-kv "^1.0.0" + +lcov-parse@^0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3" + integrity sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM= + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +libcipm@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/libcipm/-/libcipm-4.0.3.tgz#6a6db4a6e040e56f4af18bb1d664e05e8eb23a39" + integrity sha512-nuIxNtqA+kIkwUiNM/nZ0yPyR7NkSUov6g6mCfFPkYylO1dEovZBL+NZ3axdouS2UOTa8GdnJ7/meSc1/0AIGw== + dependencies: + bin-links "^1.1.2" + bluebird "^3.5.1" + figgy-pudding "^3.5.1" + find-npm-prefix "^1.0.2" + graceful-fs "^4.1.11" + ini "^1.3.5" + lock-verify "^2.0.2" + mkdirp "^0.5.1" + npm-lifecycle "^3.0.0" + npm-logical-tree "^1.2.1" + npm-package-arg "^6.1.0" + pacote "^9.1.0" + read-package-json "^2.0.13" + rimraf "^2.6.2" + worker-farm "^1.6.0" + +libnpm@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/libnpm/-/libnpm-3.0.1.tgz#0be11b4c9dd4d1ffd7d95c786e92e55d65be77a2" + integrity sha512-d7jU5ZcMiTfBqTUJVZ3xid44fE5ERBm9vBnmhp2ECD2Ls+FNXWxHSkO7gtvrnbLO78gwPdNPz1HpsF3W4rjkBQ== + dependencies: + bin-links "^1.1.2" + bluebird "^3.5.3" + find-npm-prefix "^1.0.2" + libnpmaccess "^3.0.2" + libnpmconfig "^1.2.1" + libnpmhook "^5.0.3" + libnpmorg "^1.0.1" + libnpmpublish "^1.1.2" + libnpmsearch "^2.0.2" + libnpmteam "^1.0.2" + lock-verify "^2.0.2" + npm-lifecycle "^3.0.0" + npm-logical-tree "^1.2.1" + npm-package-arg "^6.1.0" + npm-profile "^4.0.2" + npm-registry-fetch "^4.0.0" + npmlog "^4.1.2" + pacote "^9.5.3" + read-package-json "^2.0.13" + stringify-package "^1.0.0" + +libnpmaccess@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-3.0.2.tgz#8b2d72345ba3bef90d3b4f694edd5c0417f58923" + integrity sha512-01512AK7MqByrI2mfC7h5j8N9V4I7MHJuk9buo8Gv+5QgThpOgpjB7sQBDDkeZqRteFb1QM/6YNdHfG7cDvfAQ== + dependencies: + aproba "^2.0.0" + get-stream "^4.0.0" + npm-package-arg "^6.1.0" + npm-registry-fetch "^4.0.0" + +libnpmconfig@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/libnpmconfig/-/libnpmconfig-1.2.1.tgz#c0c2f793a74e67d4825e5039e7a02a0044dfcbc0" + integrity sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA== + dependencies: + figgy-pudding "^3.5.1" + find-up "^3.0.0" + ini "^1.3.5" + +libnpmhook@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/libnpmhook/-/libnpmhook-5.0.3.tgz#4020c0f5edbf08ebe395325caa5ea01885b928f7" + integrity sha512-UdNLMuefVZra/wbnBXECZPefHMGsVDTq5zaM/LgKNE9Keyl5YXQTnGAzEo+nFOpdRqTWI9LYi4ApqF9uVCCtuA== + dependencies: + aproba "^2.0.0" + figgy-pudding "^3.4.1" + get-stream "^4.0.0" + npm-registry-fetch "^4.0.0" + +libnpmorg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/libnpmorg/-/libnpmorg-1.0.1.tgz#5d2503f6ceb57f33dbdcc718e6698fea6d5ad087" + integrity sha512-0sRUXLh+PLBgZmARvthhYXQAWn0fOsa6T5l3JSe2n9vKG/lCVK4nuG7pDsa7uMq+uTt2epdPK+a2g6btcY11Ww== + dependencies: + aproba "^2.0.0" + figgy-pudding "^3.4.1" + get-stream "^4.0.0" + npm-registry-fetch "^4.0.0" + +libnpmpublish@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-1.1.2.tgz#4201cfc4a69c44e6f454ec548fa1cd90f10df0a0" + integrity sha512-2yIwaXrhTTcF7bkJKIKmaCV9wZOALf/gsTDxVSu/Gu/6wiG3fA8ce8YKstiWKTxSFNC0R7isPUb6tXTVFZHt2g== + dependencies: + aproba "^2.0.0" + figgy-pudding "^3.5.1" + get-stream "^4.0.0" + lodash.clonedeep "^4.5.0" + normalize-package-data "^2.4.0" + npm-package-arg "^6.1.0" + npm-registry-fetch "^4.0.0" + semver "^5.5.1" + ssri "^6.0.1" + +libnpmsearch@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/libnpmsearch/-/libnpmsearch-2.0.2.tgz#9a4f059102d38e3dd44085bdbfe5095f2a5044cf" + integrity sha512-VTBbV55Q6fRzTdzziYCr64+f8AopQ1YZ+BdPOv16UegIEaE8C0Kch01wo4s3kRTFV64P121WZJwgmBwrq68zYg== + dependencies: + figgy-pudding "^3.5.1" + get-stream "^4.0.0" + npm-registry-fetch "^4.0.0" + +libnpmteam@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/libnpmteam/-/libnpmteam-1.0.2.tgz#8b48bcbb6ce70dd8150c950fcbdbf3feb6eec820" + integrity sha512-p420vM28Us04NAcg1rzgGW63LMM6rwe+6rtZpfDxCcXxM0zUTLl7nPFEnRF3JfFBF5skF/yuZDUthTsHgde8QA== + dependencies: + aproba "^2.0.0" + figgy-pudding "^3.4.1" + get-stream "^4.0.0" + npm-registry-fetch "^4.0.0" + +libnpx@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/libnpx/-/libnpx-10.2.0.tgz#1bf4a1c9f36081f64935eb014041da10855e3102" + integrity sha512-X28coei8/XRCt15cYStbLBph+KGhFra4VQhRBPuH/HHMkC5dxM8v24RVgUsvODKCrUZ0eTgiTqJp6zbl0sskQQ== + dependencies: + dotenv "^5.0.1" + npm-package-arg "^6.0.0" + rimraf "^2.6.2" + safe-buffer "^5.1.0" + update-notifier "^2.3.0" + which "^1.3.0" + y18n "^4.0.0" + yargs "^11.0.0" + +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lock-verify@^2.0.2, lock-verify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lock-verify/-/lock-verify-2.1.0.tgz#fff4c918b8db9497af0c5fa7f6d71555de3ceb47" + integrity sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg== + dependencies: + npm-package-arg "^6.1.0" + semver "^5.4.1" + +lockfile@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" + integrity sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA== + dependencies: + signal-exit "^3.0.2" + +lodash._baseuniq@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" + integrity sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg= + dependencies: + lodash._createset "~4.0.0" + lodash._root "~3.0.0" + +lodash._createset@~4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" + integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY= + +lodash._root@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= + +lodash.capitalize@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9" + integrity sha1-+CbJtOKoUR2E46yinbBeGk87cqk= + +lodash.clonedeep@^4.5.0, lodash.clonedeep@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + +lodash.escaperegexp@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" + integrity sha1-ZHYsSGGAglGKw99Mz11YhtriA0c= + +lodash.flattendeep@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" + integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= + +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + +lodash.ismatch@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" + integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= + +lodash.set@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" + integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= + +lodash.toarray@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" + integrity sha1-JMS/zWsvuji/0FlNsRedjptlZWE= + +lodash.union@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= + +lodash.uniq@^4.5.0, lodash.uniq@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash.uniqby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" + integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= + +lodash.without@~4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" + integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw= + +lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +log-driver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" + integrity sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg== + +lolex@^2.2.0: + version "2.7.5" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-2.7.5.tgz#113001d56bfc7e02d56e36291cc5c413d1aa0733" + integrity sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q== + +lolex@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.2.0.tgz#ddbd7f6213ca1ea5826901ab1222b65d714b3cd7" + integrity sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg== + +loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +macos-release@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f" + integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA== + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== + dependencies: + pify "^3.0.0" + +make-dir@^2.0.0, make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-error@^1.1.1: + version "1.3.5" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" + integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== + +make-fetch-happen@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-5.0.0.tgz#a8e3fe41d3415dd656fe7b8e8172e1fb4458b38d" + integrity sha512-nFr/vpL1Jc60etMVKeaLOqfGjMMb3tAHFVJWxHOFCFS04Zmd7kGlMxo0l1tzfhoQje0/UPnd0X8OeGUiXXnfPA== + dependencies: + agentkeepalive "^3.4.1" + cacache "^12.0.0" + http-cache-semantics "^3.8.1" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.1" + lru-cache "^5.1.1" + mississippi "^3.0.0" + node-fetch-npm "^2.0.2" + promise-retry "^1.1.1" + socks-proxy-agent "^4.0.0" + ssri "^6.0.0" + +map-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + +map-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" + integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk= + +marked-terminal@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-3.3.0.tgz#25ce0c0299285998c7636beaefc87055341ba1bd" + integrity sha512-+IUQJ5VlZoAFsM5MHNT7g3RHSkA3eETqhRCdXv4niUMAKHQ7lb1yvAcuGPmm4soxhmtX13u4Li6ZToXtvSEH+A== + dependencies: + ansi-escapes "^3.1.0" + cardinal "^2.1.1" + chalk "^2.4.1" + cli-table "^0.3.1" + node-emoji "^1.4.1" + supports-hyperlinks "^1.0.1" + +marked@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/marked/-/marked-0.7.0.tgz#b64201f051d271b1edc10a04d1ae9b74bb8e5c0e" + integrity sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +meant@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.1.tgz#66044fea2f23230ec806fb515efea29c44d2115d" + integrity sha512-UakVLFjKkbbUwNWJ2frVLnnAtbb7D7DsloxRd3s/gDpI8rdv8W5Hp3NaDb+POBI1fQdeussER6NB8vpcRURvlg== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= + dependencies: + mimic-fn "^1.0.0" + +meow@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/meow/-/meow-4.0.1.tgz#d48598f6f4b1472f35bf6317a95945ace347f975" + integrity sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A== + dependencies: + camelcase-keys "^4.0.0" + decamelize-keys "^1.0.0" + loud-rejection "^1.0.0" + minimist "^1.1.3" + minimist-options "^3.0.1" + normalize-package-data "^2.3.4" + read-pkg-up "^3.0.0" + redent "^2.0.0" + trim-newlines "^2.0.0" + +merge-descriptors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +merge-source-map@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" + integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw== + dependencies: + source-map "^0.6.1" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.2.3: + version "1.2.4" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.4.tgz#c9269589e6885a60cf80605d9522d4b67ca646e3" + integrity sha512-FYE8xI+6pjFOhokZu0We3S5NKCirLbCzSh2Usf3qEyr4X8U+0jNg9P8RZ4qz+V2UoECLVwSyzU3LxXBaLGtD3A== + +merkle-lib@^2.0.10: + version "2.0.10" + resolved "https://registry.yarnpkg.com/merkle-lib/-/merkle-lib-2.0.10.tgz#82b8dbae75e27a7785388b73f9d7725d0f6f3326" + integrity sha1-grjbrnXieneFOItz+ddyXQ9vMyY= + +methods@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + +mime-db@1.40.0: + version "1.40.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" + integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== + +mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.24" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" + integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== + dependencies: + mime-db "1.40.0" + +mime@^1.3.4: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.4.3: + version "2.4.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" + integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist-options@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954" + integrity sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ== + dependencies: + arrify "^1.0.1" + is-plain-obj "^1.1.0" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= + +minipass@^2.2.1, minipass@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +mocha@^5.0.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" + integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== + dependencies: + browser-stdout "1.3.1" + commander "2.15.1" + debug "3.1.0" + diff "3.5.0" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.5" + he "1.1.1" + minimatch "3.0.4" + mkdirp "0.5.1" + supports-color "5.4.0" + +modify-values@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" + integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@^2.0.0, ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= + +mute-stream@0.0.8, mute-stream@~0.0.4: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +nan@^2.14.0, nan@^2.2.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +neo-async@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" + integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== + +nerf-dart@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/nerf-dart/-/nerf-dart-1.0.0.tgz#e6dab7febf5ad816ea81cf5c629c5a0ebde72c1a" + integrity sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo= + +nested-error-stacks@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" + integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +nise@^1.2.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/nise/-/nise-1.5.1.tgz#de61d99a1d3b46b5233be4531569b9a8e27372b2" + integrity sha512-edFWm0fsFG2n318rfEnKlTZTkjlbVOFF9XIA+fj+Ed+Qz1laYW2lobwavWoMzGrYDHH1EpiNJgDfvGnkZztR/g== + dependencies: + "@sinonjs/formatio" "^3.2.1" + "@sinonjs/text-encoding" "^0.7.1" + just-extend "^4.0.2" + lolex "^4.1.0" + path-to-regexp "^1.7.0" + +nock@^10.0.6: + version "10.0.6" + resolved "https://registry.yarnpkg.com/nock/-/nock-10.0.6.tgz#e6d90ee7a68b8cfc2ab7f6127e7d99aa7d13d111" + integrity sha512-b47OWj1qf/LqSQYnmokNWM8D88KvUl2y7jT0567NB3ZBAZFz2bWp2PC81Xn7u8F2/vJxzkzNZybnemeFa7AZ2w== + dependencies: + chai "^4.1.2" + debug "^4.1.0" + deep-equal "^1.0.0" + json-stringify-safe "^5.0.1" + lodash "^4.17.5" + mkdirp "^0.5.0" + propagate "^1.0.0" + qs "^6.5.1" + semver "^5.5.0" + +node-emoji@^1.4.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da" + integrity sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw== + dependencies: + lodash.toarray "^4.4.0" + +node-fetch-npm@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7" + integrity sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw== + dependencies: + encoding "^0.1.11" + json-parse-better-errors "^1.0.0" + safe-buffer "^5.1.1" + +node-fetch@^2.3.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" + integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== + +node-gyp@^5.0.2, node-gyp@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-5.0.3.tgz#80d64c23790244991b6d44532f0a351bedd3dd45" + integrity sha512-z/JdtkFGUm0QaQUusvloyYuGDub3nUbOo5de1Fz57cM++osBTvQatBUSTlF1k/w8vFHPxxXW6zxGvkxXSpaBkQ== + dependencies: + env-paths "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + request "^2.87.0" + rimraf "2" + semver "~5.3.0" + tar "^4.4.8" + which "1" + +node-mocks-http@^1.7.0: + version "1.7.6" + resolved "https://registry.yarnpkg.com/node-mocks-http/-/node-mocks-http-1.7.6.tgz#b5c978d73165179a218bc9d4e3bbe73fa8bedd89" + integrity sha512-ZWbZ5HEEAoVZbAYM8KHezx0v66Te3klg/yhAmdJJ0ULWQAkSqPStEzqSjONj4zRZOrTWqsHnI6nHeJxw46gj6Q== + dependencies: + accepts "^1.3.7" + depd "^1.1.0" + fresh "^0.5.2" + merge-descriptors "^1.0.1" + methods "^1.1.2" + mime "^1.3.4" + parseurl "^1.3.3" + range-parser "^1.2.0" + type-is "^1.6.18" + +"nopt@2 || 3": + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + dependencies: + abbrev "1" + +nopt@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.4.0, normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-url@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.3.0.tgz#9c49e10fc1876aeb76dba88bf1b2b5d9fa57b2ee" + integrity sha512-0NLtR71o4k6GLP+mr6Ty34c5GA6CMoEsncKJxvQd8NzPxaHRJNnb5gZE8R1XF4CPIS7QPHLJ74IFszwtNVAHVQ== + +npm-audit-report@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/npm-audit-report/-/npm-audit-report-1.3.2.tgz#303bc78cd9e4c226415076a4f7e528c89fc77018" + integrity sha512-abeqS5ONyXNaZJPGAf6TOUMNdSe1Y6cpc9MLBRn+CuUoYbfdca6AxOyXVlfIv9OgKX+cacblbG5w7A6ccwoTPw== + dependencies: + cli-table3 "^0.5.0" + console-control-strings "^1.1.0" + +npm-bundled@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" + integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + +npm-cache-filename@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" + integrity sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE= + +npm-install-checks@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-3.0.0.tgz#d4aecdfd51a53e3723b7b2f93b2ee28e307bc0d7" + integrity sha1-1K7N/VGlPjcjt7L5Oy7ijjB7wNc= + dependencies: + semver "^2.3.0 || 3.x || 4 || 5" + +npm-lifecycle@^3.0.0, npm-lifecycle@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-3.1.3.tgz#09e9b0b6686e85fd53bab82364386222d97a3730" + integrity sha512-M0QmmqbEHBXxDrmc6X3+eKjW9+F7Edg1ENau92WkYw1sox6wojHzEZJIRm1ItljEiaigZlKL8mXni/4ylAy1Dg== + dependencies: + byline "^5.0.0" + graceful-fs "^4.1.15" + node-gyp "^5.0.2" + resolve-from "^4.0.0" + slide "^1.1.6" + uid-number "0.0.6" + umask "^1.1.0" + which "^1.3.1" + +npm-logical-tree@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz#44610141ca24664cad35d1e607176193fd8f5b88" + integrity sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg== + +"npm-package-arg@^4.0.0 || ^5.0.0 || ^6.0.0", npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" + integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA== + dependencies: + hosted-git-info "^2.6.0" + osenv "^0.1.5" + semver "^5.5.0" + validate-npm-package-name "^3.0.0" + +npm-packlist@^1.1.12, npm-packlist@^1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44" + integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-pick-manifest@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-3.0.0.tgz#c94cab52d201a85875e45198fffe1a8a348e7af7" + integrity sha512-H+OnFudiq38Qj8P8xcesD/1Xa0Kvr2QRn1DTlephIwNfJg3P30Szc1wtpGEgdPXfAyKZKT2ajIM2X8YtCrbXrA== + dependencies: + figgy-pudding "^3.5.1" + npm-package-arg "^6.0.0" + semver "^5.4.1" + +npm-profile@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-4.0.2.tgz#8272a71c19634d0dce9c35a5daf8ee589cbb0f52" + integrity sha512-VRsC04pvRH+9cF+PoVh2nTmJjiG21yu59IHpsBpkxk+jaGAV8lxx96G4SDc0jOHAkfWLXbc6kIph3dGAuRnotQ== + dependencies: + aproba "^1.1.2 || 2" + figgy-pudding "^3.4.1" + npm-registry-fetch "^4.0.0" + +npm-registry-fetch@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-4.0.0.tgz#5ef75845b605855c7964472542c25da172af8677" + integrity sha512-Jllq35Jag8dtv0M17ue74XtdQTyqKzuAYGiX9mAjOhkmNjib3bBUgK6mUY61+AHnXeSRobQkpY3/xIOS/omptw== + dependencies: + JSONStream "^1.3.4" + bluebird "^3.5.1" + figgy-pudding "^3.4.1" + lru-cache "^5.1.1" + make-fetch-happen "^5.0.0" + npm-package-arg "^6.1.0" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +npm-run-path@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.0.tgz#d644ec1bd0569187d2a52909971023a0a58e8438" + integrity sha512-8eyAOAH+bYXFPSnNnKr3J+yoybe8O87Is5rtAQ8qRczJz1ajcsjg8l2oZqP+Ppx15Ii3S1vUTjQN2h4YO2tWWQ== + dependencies: + path-key "^3.0.0" + +npm-user-validate@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-1.0.0.tgz#8ceca0f5cea04d4e93519ef72d0557a75122e951" + integrity sha1-jOyg9c6gTU6TUZ73LQVXp1Ei6VE= + +npm@^6.8.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/npm/-/npm-6.11.0.tgz#98ba76e015e9ee0910e440231a7398b15a175a9f" + integrity sha512-xiA97uU+ry33XniwnMtfU89UUrJMerLYCNAOMa0qcqCF9fp79FPGnAcZ2P1YXVYvNdzU9JJt094cFbP/T5ph2A== + dependencies: + JSONStream "^1.3.5" + abbrev "~1.1.1" + ansicolors "~0.3.2" + ansistyles "~0.1.3" + aproba "^2.0.0" + archy "~1.0.0" + bin-links "^1.1.3" + bluebird "^3.5.5" + byte-size "^5.0.1" + cacache "^12.0.3" + call-limit "^1.1.1" + chownr "^1.1.2" + ci-info "^2.0.0" + cli-columns "^3.1.2" + cli-table3 "^0.5.1" + cmd-shim "^3.0.0" + columnify "~1.5.4" + config-chain "^1.1.12" + detect-indent "~5.0.0" + detect-newline "^2.1.0" + dezalgo "~1.0.3" + editor "~1.0.0" + figgy-pudding "^3.5.1" + find-npm-prefix "^1.0.2" + fs-vacuum "~1.2.10" + fs-write-stream-atomic "~1.0.10" + gentle-fs "^2.2.1" + glob "^7.1.4" + graceful-fs "^4.2.2" + has-unicode "~2.0.1" + hosted-git-info "^2.8.2" + iferr "^1.0.2" + infer-owner "^1.0.4" + inflight "~1.0.6" + inherits "^2.0.4" + ini "^1.3.5" + init-package-json "^1.10.3" + is-cidr "^3.0.0" + json-parse-better-errors "^1.0.2" + lazy-property "~1.0.0" + libcipm "^4.0.3" + libnpm "^3.0.1" + libnpmaccess "^3.0.2" + libnpmhook "^5.0.3" + libnpmorg "^1.0.1" + libnpmsearch "^2.0.2" + libnpmteam "^1.0.2" + libnpx "^10.2.0" + lock-verify "^2.1.0" + lockfile "^1.0.4" + lodash._baseuniq "~4.6.0" + lodash.clonedeep "~4.5.0" + lodash.union "~4.6.0" + lodash.uniq "~4.5.0" + lodash.without "~4.4.0" + lru-cache "^5.1.1" + meant "~1.0.1" + mississippi "^3.0.0" + mkdirp "~0.5.1" + move-concurrently "^1.0.1" + node-gyp "^5.0.3" + nopt "~4.0.1" + normalize-package-data "^2.5.0" + npm-audit-report "^1.3.2" + npm-cache-filename "~1.0.2" + npm-install-checks "~3.0.0" + npm-lifecycle "^3.1.3" + npm-package-arg "^6.1.0" + npm-packlist "^1.4.4" + npm-pick-manifest "^3.0.0" + npm-profile "^4.0.2" + npm-registry-fetch "^4.0.0" + npm-user-validate "~1.0.0" + npmlog "~4.1.2" + once "~1.4.0" + opener "^1.5.1" + osenv "^0.1.5" + pacote "^9.5.8" + path-is-inside "~1.0.2" + promise-inflight "~1.0.1" + qrcode-terminal "^0.12.0" + query-string "^6.8.2" + qw "~1.0.1" + read "~1.0.7" + read-cmd-shim "^1.0.3" + read-installed "~4.0.3" + read-package-json "^2.1.0" + read-package-tree "^5.3.1" + readable-stream "^3.4.0" + readdir-scoped-modules "^1.1.0" + request "^2.88.0" + retry "^0.12.0" + rimraf "^2.6.3" + safe-buffer "^5.1.2" + semver "^5.7.1" + sha "^3.0.0" + slide "~1.1.6" + sorted-object "~2.0.1" + sorted-union-stream "~2.1.3" + ssri "^6.0.1" + stringify-package "^1.0.0" + tar "^4.4.10" + text-table "~0.2.0" + tiny-relative-date "^1.3.0" + uid-number "0.0.6" + umask "~1.1.0" + unique-filename "^1.1.1" + unpipe "~1.0.0" + update-notifier "^2.5.0" + uuid "^3.3.2" + validate-npm-package-license "^3.0.4" + validate-npm-package-name "~3.0.0" + which "^1.3.1" + worker-farm "^1.7.0" + write-file-atomic "^2.4.3" + +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.1.2, npmlog@~4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +nyc@*, nyc@^14.1.1: + version "14.1.1" + resolved "https://registry.yarnpkg.com/nyc/-/nyc-14.1.1.tgz#151d64a6a9f9f5908a1b73233931e4a0a3075eeb" + integrity sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw== + dependencies: + archy "^1.0.0" + caching-transform "^3.0.2" + convert-source-map "^1.6.0" + cp-file "^6.2.0" + find-cache-dir "^2.1.0" + find-up "^3.0.0" + foreground-child "^1.5.6" + glob "^7.1.3" + istanbul-lib-coverage "^2.0.5" + istanbul-lib-hook "^2.0.7" + istanbul-lib-instrument "^3.3.0" + istanbul-lib-report "^2.0.8" + istanbul-lib-source-maps "^3.0.6" + istanbul-reports "^2.2.4" + js-yaml "^3.13.1" + make-dir "^2.1.0" + merge-source-map "^1.1.0" + resolve-from "^4.0.0" + rimraf "^2.6.3" + signal-exit "^3.0.2" + spawn-wrap "^1.4.2" + test-exclude "^5.2.3" + uuid "^3.3.2" + yargs "^13.2.2" + yargs-parser "^13.0.0" + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= + +object-inspect@~1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" + integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== + +object-keys@^1.0.11, object-keys@^1.0.12: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + +octokit-pagination-methods@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4" + integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ== + +once@^1.3.0, once@^1.3.1, once@^1.4.0, once@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + dependencies: + mimic-fn "^1.0.0" + +onetime@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" + integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== + dependencies: + mimic-fn "^2.1.0" + +opener@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed" + integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA== + +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== + dependencies: + url-parse "^1.4.3" + +os-homedir@^1.0.0, os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-name@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801" + integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg== + dependencies: + macos-release "^2.2.0" + windows-release "^3.1.0" + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@^0.1.4, osenv@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-filter@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-filter/-/p-filter-2.1.0.tgz#1b1472562ae7a0f742f0f3d3d3718ea66ff9c09c" + integrity sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw== + dependencies: + p-map "^2.0.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-finally@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" + integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== + +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== + dependencies: + p-try "^2.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.0.0, p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-reduce@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" + integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== + +p-retry@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.1.0.tgz#9ce7cef2069e84bf590df3b8ec18d740109338d6" + integrity sha512-oepllyG9gX1qH4Sm20YAKxg1GA7L7puhvGnTfimi31P07zSIj7SDV6YtuAx9nbJF51DES+2CIIRkXs8GKqWJxA== + dependencies: + "@types/retry" "^0.12.0" + retry "^0.12.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-3.0.0.tgz#50183f2d36c9e3e528ea0a8605dff57ce976f88e" + integrity sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA== + dependencies: + graceful-fs "^4.1.15" + hasha "^3.0.0" + lodash.flattendeep "^4.4.0" + release-zalgo "^1.0.0" + +package-json@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" + integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0= + dependencies: + got "^6.7.1" + registry-auth-token "^3.0.1" + registry-url "^3.0.3" + semver "^5.1.0" + +pacote@^9.1.0, pacote@^9.5.3, pacote@^9.5.8: + version "9.5.8" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.5.8.tgz#23480efdc4fa74515855c9ecf39cf64078f99786" + integrity sha512-0Tl8Oi/K0Lo4MZmH0/6IsT3gpGf9eEAznLXEQPKgPq7FscnbUOyopnVpwXlnQdIbCUaojWy1Wd7VMyqfVsRrIw== + dependencies: + bluebird "^3.5.3" + cacache "^12.0.2" + chownr "^1.1.2" + figgy-pudding "^3.5.1" + get-stream "^4.1.0" + glob "^7.1.3" + infer-owner "^1.0.4" + lru-cache "^5.1.1" + make-fetch-happen "^5.0.0" + minimatch "^3.0.4" + minipass "^2.3.5" + mississippi "^3.0.0" + mkdirp "^0.5.1" + normalize-package-data "^2.4.0" + npm-package-arg "^6.1.0" + npm-packlist "^1.1.12" + npm-pick-manifest "^3.0.0" + npm-registry-fetch "^4.0.0" + osenv "^0.1.5" + promise-inflight "^1.0.1" + promise-retry "^1.1.1" + protoduck "^5.0.1" + rimraf "^2.6.2" + safe-buffer "^5.1.2" + semver "^5.6.0" + ssri "^6.0.1" + tar "^4.4.10" + unique-filename "^1.1.1" + which "^1.3.1" + +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY= + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-github-url@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/parse-github-url/-/parse-github-url-1.0.2.tgz#242d3b65cbcdda14bb50439e3242acf6971db395" + integrity sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw== + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse-json@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" + integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + lines-and-columns "^1.1.6" + +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= + dependencies: + better-assert "~1.0.0" + +parseurl@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.0.tgz#99a10d870a803bdd5ee6f0470e58dfcd2f9a54d3" + integrity sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg== + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-to-regexp@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30= + dependencies: + isarray "0.0.1" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= + dependencies: + pify "^2.0.0" + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pathval@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" + integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= + +pbkdf2@^3.0.9: + version "3.0.17" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +picomatch@^2.0.5: + version "2.0.7" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6" + integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA== + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pkg-conf@^2.0.0, pkg-conf@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058" + integrity sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg= + dependencies: + find-up "^2.0.0" + load-json-file "^4.0.0" + +pkg-config@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pkg-config/-/pkg-config-1.1.1.tgz#557ef22d73da3c8837107766c52eadabde298fe4" + integrity sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q= + dependencies: + debug-log "^1.0.0" + find-root "^1.0.0" + xtend "^4.0.1" + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pluralize@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= + +prettier@^1.14.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" + integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +promise-inflight@^1.0.1, promise-inflight@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +promise-retry@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" + integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0= + dependencies: + err-code "^1.0.0" + retry "^0.10.0" + +promzard@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" + integrity sha1-JqXW7ox97kyxIggwWs+5O6OCqe4= + dependencies: + read "1" + +prop-types@^15.6.0: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + +propagate@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/propagate/-/propagate-1.0.0.tgz#00c2daeedda20e87e3782b344adba1cddd6ad709" + integrity sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk= + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= + +protoduck@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.1.tgz#03c3659ca18007b69a50fd82a7ebcc516261151f" + integrity sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg== + dependencies: + genfun "^5.0.0" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.24: + version "1.3.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.3.0.tgz#e1ebf6a3b5564fa8376f3da2275da76d875ca1bd" + integrity sha512-avHdspHO+9rQTLbv1RO+MPYeP/SzsCoxofjVnHanETfQhTJrmB0HlDoW+EiN/R+C0BZ+gERab9NY0lPN2TxNag== + +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +"pushdata-bitcoin@github:Bitcoin-com/pushdata-bitcoin#1.2.1": + version "1.2.1" + resolved "https://codeload.github.com/Bitcoin-com/pushdata-bitcoin/tar.gz/9b75eebe597853c6eeaec3e6c44b6d9c9cd7ee86" + dependencies: + bitcoincash-ops Bitcoin-com/bitcoincash-ops#2.0.0 + +q@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qrcode-terminal@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819" + integrity sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ== + +qs@^6.3.0, qs@^6.5.1: + version "6.8.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.8.0.tgz#87b763f0d37ca54200334cd57bb2ef8f68a1d081" + integrity sha512-tPSkj8y92PfZVbinY1n84i1Qdx75lZjMQYx9WZhnkofyxzw2r7Ho39G3/aEvSUdebxpnnM4LZJCtvE/Aq3+s9w== + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +query-string@^6.8.2: + version "6.8.2" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.8.2.tgz#36cb7e452ae11a4b5e9efee83375e0954407b2f6" + integrity sha512-J3Qi8XZJXh93t2FiKyd/7Ec6GNifsjKXUsVFkSBj/kjLsDylWhnCz4NT1bkPcKotttPW+QbKGqqPH8OoI2pdqw== + dependencies: + decode-uri-component "^0.2.0" + split-on-first "^1.0.0" + strict-uri-encode "^2.0.0" + +querystringify@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" + integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== + +quick-lru@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" + integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= + +qw@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/qw/-/qw-1.0.1.tgz#efbfdc740f9ad054304426acb183412cc8b996d4" + integrity sha1-77/cdA+a0FQwRCassYNBLMi5ltQ= + +random-bytes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" + integrity sha1-T2ih3Arli9P7lYSMMDJNt11kNgs= + +randombytes@^2.0.1, randombytes@^2.0.6: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +rc@^1.0.1, rc@^1.1.6, rc@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-is@^16.8.1: + version "16.9.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.9.0.tgz#21ca9561399aad0ff1a7701c01683e8ca981edcb" + integrity sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw== + +read-cmd-shim@^1.0.1, read-cmd-shim@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.4.tgz#b4a53d43376211b45243f0072b6e603a8e37640d" + integrity sha512-Pqpl3qJ/QdOIjRYA0q5DND/gLvGOfpIz/fYVDGYpOXfW/lFrIttmLsBnd6IkyK10+JHU9zhsaudfvrQTBB9YFQ== + dependencies: + graceful-fs "^4.1.2" + +read-installed@~4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" + integrity sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc= + dependencies: + debuglog "^1.0.1" + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + semver "2 || 3 || 4 || 5" + slide "~1.1.3" + util-extend "^1.0.1" + optionalDependencies: + graceful-fs "^4.1.2" + +"read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@^2.0.13, read-package-json@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.1.0.tgz#e3d42e6c35ea5ae820d9a03ab0c7291217fc51d5" + integrity sha512-KLhu8M1ZZNkMcrq1+0UJbR8Dii8KZUqB0Sha4mOx/bknfKI/fyrQVrG/YIt2UOtG667sD8+ee4EXMM91W9dC+A== + dependencies: + glob "^7.1.1" + json-parse-better-errors "^1.0.1" + normalize-package-data "^2.0.0" + slash "^1.0.0" + optionalDependencies: + graceful-fs "^4.1.2" + +read-package-tree@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.3.1.tgz#a32cb64c7f31eb8a6f31ef06f9cedf74068fe636" + integrity sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw== + dependencies: + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + util-promisify "^2.1.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" + integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= + dependencies: + find-up "^2.0.0" + read-pkg "^3.0.0" + +read-pkg-up@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978" + integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA== + dependencies: + find-up "^3.0.0" + read-pkg "^3.0.0" + +read-pkg-up@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-6.0.0.tgz#da75ce72762f2fa1f20c5a40d4dd80c77db969e3" + integrity sha512-odtTvLl+EXo1eTsMnoUHRmg/XmXdTkwXVxy4VFE9Kp6cCq7b3l7QMdBndND3eAFzrbSAXC/WCUOQQ9rLjifKZw== + dependencies: + find-up "^4.0.0" + read-pkg "^5.1.1" + type-fest "^0.5.0" + +read-pkg-up@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.0.tgz#3f3e53858ec5ae5e6fe14bc479da0a7c98f85ff3" + integrity sha512-t2ODkS/vTTcRlKwZiZsaLGb5iwfx9Urp924aGzVyboU6+7Z2i6eGr/G1Z4mjvwLLQV3uFOBKobNRGM3ux2PD/w== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + +read-pkg@^5.0.0, read-pkg@^5.1.1, read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +read@1, read@~1.0.1, read@~1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" + integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= + dependencies: + mute-stream "~0.0.4" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +"readable-stream@2 || 3", readable-stream@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" + integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@~1.1.10: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readdir-scoped-modules@^1.0.0, readdir-scoped-modules@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" + integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== + dependencies: + debuglog "^1.0.1" + dezalgo "^1.0.0" + graceful-fs "^4.1.2" + once "^1.3.0" + +redent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa" + integrity sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo= + dependencies: + indent-string "^3.0.0" + strip-indent "^2.0.0" + +redeyed@~2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-2.1.1.tgz#8984b5815d99cb220469c99eeeffe38913e6cc0b" + integrity sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs= + dependencies: + esprima "~4.0.0" + +regenerator-runtime@^0.13.2: + version "0.13.3" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" + integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +registry-auth-token@^3.0.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e" + integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A== + dependencies: + rc "^1.1.6" + safe-buffer "^5.0.1" + +registry-auth-token@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.0.0.tgz#30e55961eec77379da551ea5c4cf43cbf03522be" + integrity sha512-lpQkHxd9UL6tb3k/aHAVfnVtn+Bcs9ob5InuFLLEDqSqeq+AljB8GZW9xY0x7F+xYwEcjKe07nyoxzEYz6yvkw== + dependencies: + rc "^1.2.8" + safe-buffer "^5.0.1" + +registry-url@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI= + dependencies: + rc "^1.0.1" + +release-zalgo@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730" + integrity sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA= + dependencies: + es6-error "^4.0.1" + +request@^2.86.0, request@^2.87.0, request@^2.88.0: + version "2.88.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.0" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.4.3" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +require-uncached@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM= + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY= + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.10.0, resolve@^1.3.3, resolve@^1.5.0, resolve@^1.8.1: + version "1.12.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" + integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== + dependencies: + path-parse "^1.0.6" + +resolve@~1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" + integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== + dependencies: + path-parse "^1.0.6" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +resumer@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" + integrity sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k= + dependencies: + through "~2.3.4" + +retry@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + +reusify@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@2, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@2.6.3, rimraf@~2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= + dependencies: + is-promise "^2.1.0" + +run-parallel@^1.1.2, run-parallel@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" + integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= + +rxjs@^6.4.0: + version "6.5.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7" + integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg== + dependencies: + tslib "^1.9.0" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +samsam@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50" + integrity sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg== + +satoshi-bitcoin@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/satoshi-bitcoin/-/satoshi-bitcoin-1.0.4.tgz#d002b677075d5cbbf2c211a8df3254bcdf50b1e4" + integrity sha1-0AK2dwddXLvywhGo3zJUvN9QseQ= + dependencies: + big.js "^3.1.3" + +scryptsy@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790" + integrity sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w== + +secp256k1@^3.0.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.7.1.tgz#12e473e0e9a7c2f2d4d4818e722ad0e14cc1e2f1" + integrity sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g== + dependencies: + bindings "^1.5.0" + bip66 "^1.1.5" + bn.js "^4.11.8" + create-hash "^1.2.0" + drbg.js "^1.0.1" + elliptic "^6.4.1" + nan "^2.14.0" + safe-buffer "^5.1.2" + +semantic-release@^15.13.31: + version "15.13.31" + resolved "https://registry.yarnpkg.com/semantic-release/-/semantic-release-15.13.31.tgz#75560e61562b5b7aa3e66256fd3454683c6508a6" + integrity sha512-mrtYkH4p0FvXIRFCsr2r5il/A+Uj7oeeq+dgyojAbr4Tzywv9AlCYHeE3A8U3eE4bMJPiBV4YnQRsk1QS8yDDw== + dependencies: + "@semantic-release/commit-analyzer" "^6.1.0" + "@semantic-release/error" "^2.2.0" + "@semantic-release/github" "^5.1.0" + "@semantic-release/npm" "^5.0.5" + "@semantic-release/release-notes-generator" "^7.1.2" + aggregate-error "^3.0.0" + cosmiconfig "^6.0.0" + debug "^4.0.0" + env-ci "^4.0.0" + execa "^3.2.0" + figures "^3.0.0" + find-versions "^3.0.0" + get-stream "^5.0.0" + git-log-parser "^1.2.0" + hook-std "^2.0.0" + hosted-git-info "^3.0.0" + lodash "^4.17.15" + marked "^0.7.0" + marked-terminal "^3.2.0" + p-locate "^4.0.0" + p-reduce "^2.0.0" + read-pkg-up "^7.0.0" + resolve-from "^5.0.0" + semver "^6.0.0" + signale "^1.2.1" + yargs "^15.0.1" + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY= + dependencies: + semver "^5.0.3" + +semver-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338" + integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== + +"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +sha@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/sha/-/sha-3.0.0.tgz#b2f2f90af690c16a3a839a6a6c680ea51fedd1ae" + integrity sha512-DOYnM37cNsLNSGIG/zZWch5CKIRNoLdYUQTQlcgkRkoYIUwDYjqDyye16YcDZg/OPdcbUgTKMjc4SY6TB7ZAPw== + dependencies: + graceful-fs "^4.1.2" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +signale@^1.2.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/signale/-/signale-1.4.0.tgz#c4be58302fb0262ac00fc3d886a7c113759042f1" + integrity sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w== + dependencies: + chalk "^2.3.2" + figures "^2.0.0" + pkg-conf "^2.1.0" + +sinon@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.5.0.tgz#427ae312a337d3c516804ce2754e8c0d5028cb04" + integrity sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w== + dependencies: + "@sinonjs/formatio" "^2.0.0" + diff "^3.1.0" + lodash.get "^4.4.2" + lolex "^2.2.0" + nise "^1.2.0" + supports-color "^5.1.0" + type-detect "^4.0.5" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== + dependencies: + is-fullwidth-code-point "^2.0.0" + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +slide@^1.1.6, slide@~1.1.3, slide@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= + +smart-buffer@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.2.tgz#5207858c3815cc69110703c6b94e46c15634395d" + integrity sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw== + +socket.io-adapter@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" + integrity sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs= + +socket.io-client@2.2.0, socket.io-client@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.2.0.tgz#84e73ee3c43d5020ccc1a258faeeb9aec2723af7" + integrity sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA== + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~3.1.0" + engine.io-client "~3.3.1" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.3.0" + to-array "0.1.4" + +socket.io-parser@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f" + integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng== + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + +socket.io@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.2.0.tgz#f0f633161ef6712c972b307598ecd08c9b1b4d5b" + integrity sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w== + dependencies: + debug "~4.1.0" + engine.io "~3.3.1" + has-binary2 "~1.0.2" + socket.io-adapter "~1.1.0" + socket.io-client "2.2.0" + socket.io-parser "~3.3.0" + +socks-proxy-agent@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz#3c8991f3145b2799e70e11bd5fbc8b1963116386" + integrity sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg== + dependencies: + agent-base "~4.2.1" + socks "~2.3.2" + +socks@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.3.2.tgz#ade388e9e6d87fdb11649c15746c578922a5883e" + integrity sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ== + dependencies: + ip "^1.1.5" + smart-buffer "4.0.2" + +sorted-object@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc" + integrity sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw= + +sorted-union-stream@~2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz#c7794c7e077880052ff71a8d4a2dbb4a9a638ac7" + integrity sha1-x3lMfgd4gAUv9xqNSi27Sppjisc= + dependencies: + from2 "^1.3.0" + stream-iterate "^1.1.0" + +source-map-support@^0.5.12, source-map-support@^0.5.6: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spawn-error-forwarder@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz#1afd94738e999b0346d7b9fc373be55e07577029" + integrity sha1-Gv2Uc46ZmwNG17n8NzvlXgdXcCk= + +spawn-wrap@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.4.2.tgz#cff58e73a8224617b6561abdc32586ea0c82248c" + integrity sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg== + dependencies: + foreground-child "^1.5.6" + mkdirp "^0.5.0" + os-homedir "^1.0.1" + rimraf "^2.6.2" + signal-exit "^3.0.2" + which "^1.3.0" + +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + +split-on-first@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" + integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== + +split2@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-2.2.0.tgz#186b2575bcf83e85b7d18465756238ee4ee42493" + integrity sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw== + dependencies: + through2 "^2.0.2" + +split2@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-1.0.0.tgz#52e2e221d88c75f9a73f90556e263ff96772b314" + integrity sha1-UuLiIdiMdfmnP5BVbiY/+WdysxQ= + dependencies: + through2 "~2.0.0" + +split@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== + dependencies: + through "2" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssri@^6.0.0, ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== + dependencies: + figgy-pudding "^3.5.1" + +standard-engine@~8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/standard-engine/-/standard-engine-8.0.1.tgz#0b77be8d7ab963675717dbeac1ef1d6675fb62f0" + integrity sha512-LA531C3+nljom/XRvdW/hGPXwmilRkaRkENhO3FAGF1Vtq/WtCXzgmnc5S6vUHHsgv534MRy02C1ikMwZXC+tw== + dependencies: + deglob "^2.1.0" + get-stdin "^6.0.0" + minimist "^1.1.0" + pkg-conf "^2.0.0" + +standard@^11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/standard/-/standard-11.0.1.tgz#49be40c76f1d564964b22bbf7309929ad0335e29" + integrity sha512-nu0jAcHiSc8H+gJCXeiziMVZNDYi8MuqrYJKxTgjP4xKXZMKm311boqQIzDrYI/ktosltxt2CbDjYQs9ANC8IA== + dependencies: + eslint "~4.18.0" + eslint-config-standard "11.0.0" + eslint-config-standard-jsx "5.0.0" + eslint-plugin-import "~2.9.0" + eslint-plugin-node "~6.0.0" + eslint-plugin-promise "~3.7.0" + eslint-plugin-react "~7.7.0" + eslint-plugin-standard "~3.0.1" + standard-engine "~8.0.0" + +stream-combiner2@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" + integrity sha1-+02KFCDqNidk4hrUeAOXvry0HL4= + dependencies: + duplexer2 "~0.1.0" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-iterate@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/stream-iterate/-/stream-iterate-1.2.0.tgz#2bd7c77296c1702a46488b8ad41f79865eecd4e1" + integrity sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE= + dependencies: + readable-stream "^2.1.5" + stream-shift "^1.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= + +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.1.0.tgz#ba846d1daa97c3c596155308063e075ed1c99aff" + integrity sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^5.2.0" + +string-width@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.trim@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea" + integrity sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.0" + function-bind "^1.0.2" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +stringify-package@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.0.tgz#e02828089333d7d45cd8c287c30aa9a13375081b" + integrity sha512-JIQqiWmLiEozOC0b0BtxZ/AOUtdUZHCBPgqIZ2kSJJqGwgb9neo44XdTHUC4HZSGqi03hOeB7W/E8rAlKnGe9g== + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-indent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" + integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= + +strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +supports-color@5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== + dependencies: + has-flag "^3.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^5.0.0, supports-color@^5.1.0, supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-hyperlinks@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz#71daedf36cc1060ac5100c351bb3da48c29c0ef7" + integrity sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw== + dependencies: + has-flag "^2.0.0" + supports-color "^5.0.0" + +table@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" + integrity sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA== + dependencies: + ajv "^5.2.3" + ajv-keywords "^2.1.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +tape@*: + version "4.11.0" + resolved "https://registry.yarnpkg.com/tape/-/tape-4.11.0.tgz#63d41accd95e45a23a874473051c57fdbc58edc1" + integrity sha512-yixvDMX7q7JIs/omJSzSZrqulOV51EC9dK8dM0TzImTIkHWfe2/kFyL5v+d9C+SrCMaICk59ujsqFAVidDqDaA== + dependencies: + deep-equal "~1.0.1" + defined "~1.0.0" + for-each "~0.3.3" + function-bind "~1.1.1" + glob "~7.1.4" + has "~1.0.3" + inherits "~2.0.4" + minimist "~1.2.0" + object-inspect "~1.6.0" + resolve "~1.11.1" + resumer "~0.0.0" + string.prototype.trim "~1.1.2" + through "~2.3.8" + +tar@^4.4.10, tar@^4.4.8: + version "4.4.10" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" + integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.5" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + +term-size@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" + integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk= + dependencies: + execa "^0.7.0" + +test-exclude@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0" + integrity sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g== + dependencies: + glob "^7.1.3" + minimatch "^3.0.4" + read-pkg-up "^4.0.0" + require-main-filename "^2.0.0" + +text-extensions@^1.0.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" + integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== + +text-table@^0.2.0, text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through2@^2.0.0, through2@^2.0.2, through2@~2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through2@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a" + integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww== + dependencies: + readable-stream "2 || 3" + +through@2, "through@>=2.2.7 <3", through@^2.3.6, through@~2.3.4, through@~2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +timed-out@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= + +tiny-relative-date@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07" + integrity sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A== + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tough-cookie@~2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== + dependencies: + psl "^1.1.24" + punycode "^1.4.1" + +traverse@~0.6.6: + version "0.6.6" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" + integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc= + +trim-newlines@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" + integrity sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA= + +trim-off-newlines@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" + integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM= + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= + +ts-node@^8.1.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.3.0.tgz#e4059618411371924a1fb5f3b125915f324efb57" + integrity sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ== + dependencies: + arg "^4.1.0" + diff "^4.0.1" + make-error "^1.1.1" + source-map-support "^0.5.6" + yn "^3.0.0" + +tslib@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.5.0, type-fest@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.5.2.tgz#d6ef42a0356c6cd45f49485c3b6281fc148e48a2" + integrity sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw== + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +type-is@^1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +typeforce@^1.11.3: + version "1.18.0" + resolved "https://registry.yarnpkg.com/typeforce/-/typeforce-1.18.0.tgz#d7416a2c5845e085034d70fcc5b6cc4a90edbfdc" + integrity sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g== + +typescript@^3.4.5: + version "3.5.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" + integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== + +uglify-js@^3.1.4: + version "3.6.0" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5" + integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg== + dependencies: + commander "~2.20.0" + source-map "~0.6.1" + +uid-number@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= + +umask@^1.1.0, umask@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" + integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo= + dependencies: + crypto-random-string "^1.0.0" + +universal-user-agent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-3.0.0.tgz#4cc88d68097bffd7ac42e3b7c903e7481424b4b9" + integrity sha512-T3siHThqoj5X0benA5H0qcDnrKGXzU8TKoX15x/tQHw1hQBvIEBHjxQ2klizYsqBOO/Q+WuxoQUihadeeqDnoA== + dependencies: + os-name "^3.0.0" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unorm@^1.3.3: + version "1.6.0" + resolved "https://registry.yarnpkg.com/unorm/-/unorm-1.6.0.tgz#029b289661fba714f1a9af439eb51d9b16c205af" + integrity sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA== + +unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unzip-response@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" + integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c= + +update-notifier@^2.3.0, update-notifier@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" + integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw== + dependencies: + boxen "^1.2.1" + chalk "^2.0.1" + configstore "^3.0.0" + import-lazy "^2.1.0" + is-ci "^1.0.10" + is-installed-globally "^0.1.0" + is-npm "^1.0.0" + latest-version "^3.0.0" + semver-diff "^2.0.0" + xdg-basedir "^3.0.0" + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +url-join@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" + integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= + dependencies: + prepend-http "^1.0.1" + +url-parse@^1.4.3: + version "1.4.7" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" + integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +url-template@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21" + integrity sha1-/FZaPMy/93MMd19WQflVV5FDnyE= + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util-extend@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" + integrity sha1-p8IW0mdUUWljeztu3GypEZ4v+T8= + +util-promisify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/util-promisify/-/util-promisify-2.1.0.tgz#3c2236476c4d32c5ff3c47002add7c13b9a82a53" + integrity sha1-PCI2R2xNMsX/PEcAKt18E7moKlM= + dependencies: + object.getownpropertydescriptors "^2.0.3" + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +uuid@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" + integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== + +validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +validate-npm-package-name@^3.0.0, validate-npm-package-name@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= + dependencies: + builtins "^1.0.3" + +varuint-bitcoin@^1.0.1, varuint-bitcoin@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/varuint-bitcoin/-/varuint-bitcoin-1.1.0.tgz#7a343f50537607af6a3059312b9782a170894540" + integrity sha512-jCEPG+COU/1Rp84neKTyDJQr478/hAfVp5xxYn09QEH0yBjbmPeMfuuQIrp+BUD83hybtYZKhr5elV3bvdV1bA== + dependencies: + safe-buffer "^5.1.1" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +wcwidth@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@1, which@^1.2.9, which@^1.3.0, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +widest-line@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" + integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA== + dependencies: + string-width "^2.1.1" + +wif@^2.0.1, wif@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/wif/-/wif-2.0.6.tgz#08d3f52056c66679299726fade0d432ae74b4704" + integrity sha1-CNP1IFbGZnkplyb63g1DKudLRwQ= + dependencies: + bs58check "<3.0.0" + +windows-release@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.2.0.tgz#8122dad5afc303d833422380680a79cdfa91785f" + integrity sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA== + dependencies: + execa "^1.0.0" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + +worker-farm@^1.6.0, worker-farm@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" + integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== + dependencies: + errno "~0.1.7" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^2.0.0, write-file-atomic@^2.3.0, write-file-atomic@^2.4.2, write-file-atomic@^2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" + integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c= + dependencies: + mkdirp "^0.5.1" + +ws@~6.1.0: + version "6.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" + integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA== + dependencies: + async-limiter "~1.0.0" + +xdg-basedir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= + +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= + +xtend@^4.0.1, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + +yaml@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.7.2.tgz#f26aabf738590ab61efaca502358e48dc9f348b2" + integrity sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw== + dependencies: + "@babel/runtime" "^7.6.3" + +yargs-parser@^13.0.0, yargs-parser@^13.1.1: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^16.1.0: + version "16.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-16.1.0.tgz#73747d53ae187e7b8dbe333f95714c76ea00ecf1" + integrity sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + integrity sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc= + dependencies: + camelcase "^4.1.0" + +yargs@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" + integrity sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A== + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + +yargs@^13.2.2: + version "13.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" + integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== + dependencies: + 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.1" + +yargs@^15.0.1: + version "15.0.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.0.2.tgz#4248bf218ef050385c4f7e14ebdf425653d13bd3" + integrity sha512-GH/X/hYt+x5hOat4LMnCqMd8r5Cv78heOMIJn1hr7QPPBqfeC6p89Y78+WB9yGDvfpCvgasfmWLzNzEioOUD9Q== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^16.1.0" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= + +yn@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==